UNPKG

infusion

Version:

Infusion is an application framework for developing flexible stuff with JavaScript

299 lines (246 loc) 10.6 kB
/* Copyright 2008-2009 University of Cambridge Copyright 2008-2010 University of Toronto Copyright 2010-2011 OCAD University Copyright 2010-2011 Lucendo Development Ltd. Copyright 2012-2013 Raising the Floor - US Copyright 2014-2016 Raising the Floor - International Licensed under the Educational Community License (ECL), Version 2.0 or the New BSD license. You may not use this file except in compliance with one these Licenses. You may obtain a copy of the ECL 2.0 License and BSD License at https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt */ /* global fluid_2_0_0, QUnit */ var jqUnit = jqUnit || {}; (function ($, fluid) { "use strict"; var QUnitPassthroughs = ["module", "test", "asyncTest", "throws", "raises", "start", "stop", "expect"]; QUnit.config.reorder = false; // defeat this QUnit feature which frequently just causes confusion for (var i = 0; i < QUnitPassthroughs.length; ++i) { var method = QUnitPassthroughs[i]; jqUnit[method] = QUnit[method]; window[method] = undefined; // work around IE8 bug http://stackoverflow.com/questions/1073414/deleting-a-window-property-in-ie } jqUnit.failureHandler = function (args/*, activity*/) { if (QUnit.config.current) { QUnit.ok(false, "Assertion failure (see console.log for expanded message): ".concat(args)); } }; fluid.failureEvent.addListener(jqUnit.failureHandler, "jqUnit", "before:fail"); // Helpful utility for creating multiple test target components compactly fluid.makeComponents = function (components) { fluid.each(components, function (value, key) { var options = { gradeNames: fluid.makeArray(value) }; fluid.defaults(key, options); }); }; /** * Keeps track of the order of function invocations. The transcript contains information about * each invocation, including its name and the arguments that were supplied to it. */ jqUnit.invocationTracker = function (options) { var that = {}; that.runTestsOnFunctionNamed = options ? options.runTestsOnFunctionNamed : undefined; that.testBody = options ? options.testBody : undefined; /** * An array containing an ordered list of details about each function invocation. */ that.transcript = []; /** * Called to listen for a function's invocation and record its details in the transcript. * * @param {Object} fnName the function name to listen for * @param {Object} onObject the object on which to invoke the method */ that.intercept = function (fnName, onObject) { onObject = onObject || window; var wrappedFn = onObject[fnName]; onObject[fnName] = function () { that.transcript.push({ name: fnName, args: arguments }); wrappedFn.apply(onObject, arguments); if (fnName === that.runTestsOnFunctionNamed) { that.testBody(that.transcript); } }; }; /** * Intercepts all the functions on the specified object. * * @param {Object} obj */ that.interceptAll = function (obj) { for (var fnName in obj) { that.intercept(fnName, obj); } }; that.clearTranscript = function () { that.transcript = []; }; return that; }; var messageSuffix = ""; var processMessage = function (message) { return message + messageSuffix; }; var pok = function (condition, message) { QUnit.ok(condition, processMessage(message)); }; // unsupported, NON-API function jqUnit.okWithPrefix = pok; // unsupported, NON-API function jqUnit.setMessageSuffix = function (suffix) { messageSuffix = suffix; }; /*********************** * xUnit Compatibility * ***********************/ var jsUnitCompat = { fail: function (msg) { pok(false, msg); }, assert: function (msg) { pok(true, msg); }, assertEquals: function (msg, expected, actual) { QUnit.strictEqual(actual, expected, processMessage(msg)); }, assertNotEquals: function (msg, unexpected, actual) { QUnit.notStrictEqual(actual, unexpected, msg); }, assertTrue: function (msg, value) { pok(value, msg); }, assertFalse: function (msg, value) { pok(!value, msg); }, assertUndefined: function (msg, value) { pok(value === undefined, msg); }, assertNotUndefined: function (msg, value) { pok(value !== undefined, msg); }, assertValue: function (msg, value) { pok(value !== null && value !== undefined, msg); }, assertNoValue: function (msg, value) { pok(value === null || value === undefined, msg); }, assertNull: function (msg, value) { QUnit.equal(value, null, processMessage(msg)); }, assertNotNull: function (msg, value) { pok(value !== null, msg); }, assertDeepEq: function (msg, expected, actual) { if (fluid.isPrimitive(expected) || fluid.isPrimitive(actual)) { jqUnit.assertEquals(msg, expected, actual); } else { QUnit.propEqual(actual, expected, processMessage(msg)); } }, assertDeepNeq: function (msg, unexpected, actual) { if (fluid.isPrimitive(unexpected) || fluid.isPrimitive(actual)) { jqUnit.assertNotEquals(msg, unexpected, actual); } else { QUnit.notPropEqual(actual, unexpected, processMessage(msg)); } }, // This version of "expect" offers the cumulative semantic we desire expect: function (number) { var oldExpect = QUnit.expect(); QUnit.expect(number + oldExpect); } }; // Mix these compatibility functions into the jqUnit namespace. $.extend(jqUnit, jsUnitCompat); /** Sort a component tree into canonical order, to facilitate comparison with * deepEq */ jqUnit.sortTree = function (tree) { function comparator(ela, elb) { var ida = ela.ID || ""; var idb = elb.ID || ""; var cola = ida.indexOf(":") === -1; var colb = idb.indexOf(":") === -1; if (cola && colb) { // if neither has a colon, compare by IDs if they have IDs return ida.localeCompare(idb); } else { return cola - colb; } } if (fluid.isArrayable(tree)) { tree.sort(comparator); } fluid.each(tree, function (value) { if (!fluid.isPrimitive(value)) { jqUnit.sortTree(value); } }); }; jqUnit.canonicaliseFunctions = function (tree) { return fluid.transform(tree, function (value) { if (fluid.isPrimitive(value)) { if (typeof(value) === "function") { return fluid.identity; } else { return value; } } else { return jqUnit.canonicaliseFunctions(value); } }); }; /** Assert that two trees are equal after applying a "canonicalisation function". This can be used in * cases where the criterion for equivalence is looser than exact object equivalence - for example, * when using renderer trees, "jqUnit.sortTree" can be used for canonFunc", or in the case * of a resourceSpec, "jqUnit.canonicaliseFunctions". **/ jqUnit.assertCanoniseEqual = function (message, expected, actual, canonFunc) { var expected2 = canonFunc(expected); var actual2 = canonFunc(actual); jqUnit.assertDeepEq(message, expected2, actual2); }; /** Assert that the actual value object is a superset (considered in terms of shallow key coincidence) of the * expected value object (this method is the one that will be most often used in practice). "Left hand" (expected) is a subset of actual. **/ jqUnit.assertLeftHand = function (message, expected, actual) { jqUnit.assertDeepEq(message, expected, fluid.filterKeys(actual, fluid.keys(expected))); }; /** Assert that the actual value object is a subset of the expected value object **/ jqUnit.assertRightHand = function (message, expected, actual) { jqUnit.assertDeepEq(message, fluid.filterKeys(expected, fluid.keys(actual)), actual); }; /** Assert that the supplied callback will produce a framework diagnostic, containing the supplied text * somewhere in its error message - that is, the framework will invoke fluid.fail with a message containing * <code>errorText</code>. * @param message {String} The message prefix to be supplied for all the assertions this function issues * @param toInvoke {Function} A no-arg function holding the code to be tested for emission of the diagnostic * @param errorTexts {String} or {Array of String} Either a single string or array of strings which the <code>message</code> field * of the thrown exception will be tested against - each string must appear as a substring in the text */ jqUnit.expectFrameworkDiagnostic = function (message, toInvoke, errorTexts) { errorTexts = fluid.makeArray(errorTexts); var gotFailure; try { fluid.failureEvent.addListener(fluid.identity, "jqUnit"); jqUnit.expect(errorTexts.length); toInvoke(); } catch (e) { gotFailure = true; if (!(e instanceof fluid.FluidError)) { jqUnit.fail(message + " - received non-framework exception"); throw e; } fluid.each(errorTexts, function (errorText) { jqUnit.assertTrue(message + " - message text must contain " + errorText, e.message.indexOf(errorText) >= 0); }); } finally { if (!gotFailure) { jqUnit.fail("No failure received for test " + message); } fluid.failureEvent.removeListener("jqUnit"); } }; })(jQuery, fluid_2_0_0);