UNPKG

create-hyper-mendix-widget

Version:
1,855 lines (1,491 loc) 154 kB
/*! * QUnit 2.5.0 * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * https://jquery.org/license * * Date: 2018-01-10T02:56Z */ (function (global$1) { 'use strict'; global$1 = global$1 && global$1.hasOwnProperty('default') ? global$1['default'] : global$1; var window = global$1.window; var self$1 = global$1.self; var console = global$1.console; var setTimeout = global$1.setTimeout; var clearTimeout = global$1.clearTimeout; var document = window && window.document; var navigator = window && window.navigator; var localSessionStorage = function () { var x = "qunit-test-string"; try { global$1.sessionStorage.setItem(x, x); global$1.sessionStorage.removeItem(x); return global$1.sessionStorage; } catch (e) { return undefined; } }(); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var toString = Object.prototype.toString; var hasOwn = Object.prototype.hasOwnProperty; var now = Date.now || function () { return new Date().getTime(); }; var defined = { document: window && window.document !== undefined, setTimeout: setTimeout !== undefined }; // Returns a new Array with the elements that are in a but not in b function diff(a, b) { var i, j, result = a.slice(); for (i = 0; i < result.length; i++) { for (j = 0; j < b.length; j++) { if (result[i] === b[j]) { result.splice(i, 1); i--; break; } } } return result; } /** * Determines whether an element exists in a given array or not. * * @method inArray * @param {Any} elem * @param {Array} array * @return {Boolean} */ function inArray(elem, array) { return array.indexOf(elem) !== -1; } /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ function objectValues(obj) { var key, val, vals = is("array", obj) ? [] : {}; for (key in obj) { if (hasOwn.call(obj, key)) { val = obj[key]; vals[key] = val === Object(val) ? objectValues(val) : val; } } return vals; } function extend(a, b, undefOnly) { for (var prop in b) { if (hasOwn.call(b, prop)) { if (b[prop] === undefined) { delete a[prop]; } else if (!(undefOnly && typeof a[prop] !== "undefined")) { a[prop] = b[prop]; } } } return a; } function objectType(obj) { if (typeof obj === "undefined") { return "undefined"; } // Consider: typeof null === object if (obj === null) { return "null"; } var match = toString.call(obj).match(/^\[object\s(.*)\]$/), type = match && match[1]; switch (type) { case "Number": if (isNaN(obj)) { return "nan"; } return "number"; case "String": case "Boolean": case "Array": case "Set": case "Map": case "Date": case "RegExp": case "Function": case "Symbol": return type.toLowerCase(); default: return typeof obj === "undefined" ? "undefined" : _typeof(obj); } } // Safe object type checking function is(type, obj) { return objectType(obj) === type; } // Based on Java's String.hashCode, a simple but not // rigorously collision resistant hashing function function generateHash(module, testName) { var str = module + "\x1C" + testName; var hash = 0; for (var i = 0; i < str.length; i++) { hash = (hash << 5) - hash + str.charCodeAt(i); hash |= 0; } // Convert the possibly negative integer hash code into an 8 character hex string, which isn't // strictly necessary but increases user understanding that the id is a SHA-like hash var hex = (0x100000000 + hash).toString(16); if (hex.length < 8) { hex = "0000000" + hex; } return hex.slice(-8); } // Test for equality any JavaScript type. // Authors: Philippe Rathé <prathe@gmail.com>, David Chan <david@troi.org> var equiv = (function () { // Value pairs queued for comparison. Used for breadth-first processing order, recursion // detection and avoiding repeated comparison (see below for details). // Elements are { a: val, b: val }. var pairs = []; var getProto = Object.getPrototypeOf || function (obj) { return obj.__proto__; }; function useStrictEquality(a, b) { // This only gets called if a and b are not strict equal, and is used to compare on // the primitive values inside object wrappers. For example: // `var i = 1;` // `var j = new Number(1);` // Neither a nor b can be null, as a !== b and they have the same type. if ((typeof a === "undefined" ? "undefined" : _typeof(a)) === "object") { a = a.valueOf(); } if ((typeof b === "undefined" ? "undefined" : _typeof(b)) === "object") { b = b.valueOf(); } return a === b; } function compareConstructors(a, b) { var protoA = getProto(a); var protoB = getProto(b); // Comparing constructors is more strict than using `instanceof` if (a.constructor === b.constructor) { return true; } // Ref #851 // If the obj prototype descends from a null constructor, treat it // as a null prototype. if (protoA && protoA.constructor === null) { protoA = null; } if (protoB && protoB.constructor === null) { protoB = null; } // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if (protoA === null && protoB === Object.prototype || protoB === null && protoA === Object.prototype) { return true; } return false; } function getRegExpFlags(regexp) { return "flags" in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0]; } function isContainer(val) { return ["object", "array", "map", "set"].indexOf(objectType(val)) !== -1; } function breadthFirstCompareChild(a, b) { // If a is a container not reference-equal to b, postpone the comparison to the // end of the pairs queue -- unless (a, b) has been seen before, in which case skip // over the pair. if (a === b) { return true; } if (!isContainer(a)) { return typeEquiv(a, b); } if (pairs.every(function (pair) { return pair.a !== a || pair.b !== b; })) { // Not yet started comparing this pair pairs.push({ a: a, b: b }); } return true; } var callbacks = { "string": useStrictEquality, "boolean": useStrictEquality, "number": useStrictEquality, "null": useStrictEquality, "undefined": useStrictEquality, "symbol": useStrictEquality, "date": useStrictEquality, "nan": function nan() { return true; }, "regexp": function regexp(a, b) { return a.source === b.source && // Include flags in the comparison getRegExpFlags(a) === getRegExpFlags(b); }, // abort (identical references / instance methods were skipped earlier) "function": function _function() { return false; }, "array": function array(a, b) { var i, len; len = a.length; if (len !== b.length) { // Safe and faster return false; } for (i = 0; i < len; i++) { // Compare non-containers; queue non-reference-equal containers if (!breadthFirstCompareChild(a[i], b[i])) { return false; } } return true; }, // Define sets a and b to be equivalent if for each element aVal in a, there // is some element bVal in b such that aVal and bVal are equivalent. Element // repetitions are not counted, so these are equivalent: // a = new Set( [ {}, [], [] ] ); // b = new Set( [ {}, {}, [] ] ); "set": function set$$1(a, b) { var innerEq, outerEq = true; if (a.size !== b.size) { // This optimization has certain quirks because of the lack of // repetition counting. For instance, adding the same // (reference-identical) element to two equivalent sets can // make them non-equivalent. return false; } a.forEach(function (aVal) { // Short-circuit if the result is already known. (Using for...of // with a break clause would be cleaner here, but it would cause // a syntax error on older Javascript implementations even if // Set is unused) if (!outerEq) { return; } innerEq = false; b.forEach(function (bVal) { var parentPairs; // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global pairs list, as the nested call to // innerEquiv will clobber its contents parentPairs = pairs; if (innerEquiv(bVal, aVal)) { innerEq = true; } // Replace the global pairs list pairs = parentPairs; }); if (!innerEq) { outerEq = false; } }); return outerEq; }, // Define maps a and b to be equivalent if for each key-value pair (aKey, aVal) // in a, there is some key-value pair (bKey, bVal) in b such that // [ aKey, aVal ] and [ bKey, bVal ] are equivalent. Key repetitions are not // counted, so these are equivalent: // a = new Map( [ [ {}, 1 ], [ {}, 1 ], [ [], 1 ] ] ); // b = new Map( [ [ {}, 1 ], [ [], 1 ], [ [], 1 ] ] ); "map": function map(a, b) { var innerEq, outerEq = true; if (a.size !== b.size) { // This optimization has certain quirks because of the lack of // repetition counting. For instance, adding the same // (reference-identical) key-value pair to two equivalent maps // can make them non-equivalent. return false; } a.forEach(function (aVal, aKey) { // Short-circuit if the result is already known. (Using for...of // with a break clause would be cleaner here, but it would cause // a syntax error on older Javascript implementations even if // Map is unused) if (!outerEq) { return; } innerEq = false; b.forEach(function (bVal, bKey) { var parentPairs; // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global pairs list, as the nested call to // innerEquiv will clobber its contents parentPairs = pairs; if (innerEquiv([bVal, bKey], [aVal, aKey])) { innerEq = true; } // Replace the global pairs list pairs = parentPairs; }); if (!innerEq) { outerEq = false; } }); return outerEq; }, "object": function object(a, b) { var i, aProperties = [], bProperties = []; if (compareConstructors(a, b) === false) { return false; } // Be strict: don't ensure hasOwnProperty and go deep for (i in a) { // Collect a's properties aProperties.push(i); // Skip OOP methods that look the same if (a.constructor !== Object && typeof a.constructor !== "undefined" && typeof a[i] === "function" && typeof b[i] === "function" && a[i].toString() === b[i].toString()) { continue; } // Compare non-containers; queue non-reference-equal containers if (!breadthFirstCompareChild(a[i], b[i])) { return false; } } for (i in b) { // Collect b's properties bProperties.push(i); } // Ensures identical properties name return typeEquiv(aProperties.sort(), bProperties.sort()); } }; function typeEquiv(a, b) { var type = objectType(a); // Callbacks for containers will append to the pairs queue to achieve breadth-first // search order. The pairs queue is also used to avoid reprocessing any pair of // containers that are reference-equal to a previously visited pair (a special case // this being recursion detection). // // Because of this approach, once typeEquiv returns a false value, it should not be // called again without clearing the pair queue else it may wrongly report a visited // pair as being equivalent. return objectType(b) === type && callbacks[type](a, b); } function innerEquiv(a, b) { var i, pair; // We're done when there's nothing more to compare if (arguments.length < 2) { return true; } // Clear the global pair queue and add the top-level values being compared pairs = [{ a: a, b: b }]; for (i = 0; i < pairs.length; i++) { pair = pairs[i]; // Perform type-specific comparison on any pairs that are not strictly // equal. For container types, that comparison will postpone comparison // of any sub-container pair to the end of the pair queue. This gives // breadth-first search order. It also avoids the reprocessing of // reference-equal siblings, cousins etc, which can have a significant speed // impact when comparing a container of small objects each of which has a // reference to the same (singleton) large object. if (pair.a !== pair.b && !typeEquiv(pair.a, pair.b)) { return false; } } // ...across all consecutive argument pairs return arguments.length === 2 || innerEquiv.apply(this, [].slice.call(arguments, 1)); } return function () { var result = innerEquiv.apply(undefined, arguments); // Release any retained objects pairs.length = 0; return result; }; })(); /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ var config = { // The queue of tests to run queue: [], // Block until document ready blocking: true, // By default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // By default, modify document.title when suite is done altertitle: true, // HTML Reporter: collapse every test except the first failing test // If false, all failing tests will be expanded collapse: true, // By default, scroll to top of the page when suite is done scrolltop: true, // Depth up-to which object will be dumped maxDepth: 5, // When enabled, all tests must call expect() requireExpects: false, // Placeholder for user-configurable form-exposed URL parameters urlConfig: [], // Set of all modules. modules: [], // The first unnamed module currentModule: { name: "", tests: [], childModules: [], testsRun: 0, unskippedTestsRun: 0, hooks: { before: [], beforeEach: [], afterEach: [], after: [] } }, callbacks: {}, // The storage module to use for reordering tests storage: localSessionStorage }; // take a predefined QUnit.config and extend the defaults var globalConfig = window && window.QUnit && window.QUnit.config; // only extend the global config if there is no QUnit overload if (window && window.QUnit && !window.QUnit.version) { extend(config, globalConfig); } // Push a loose unnamed module to the modules collection config.modules.push(config.currentModule); // Based on jsDump by Ariel Flesler // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html var dump = (function () { function quote(str) { return "\"" + str.toString().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\""; } function literal(o) { return o + ""; } function join(pre, arr, post) { var s = dump.separator(), base = dump.indent(), inner = dump.indent(1); if (arr.join) { arr = arr.join("," + s + inner); } if (!arr) { return pre + post; } return [pre, inner + arr, base + post].join(s); } function array(arr, stack) { var i = arr.length, ret = new Array(i); if (dump.maxDepth && dump.depth > dump.maxDepth) { return "[object Array]"; } this.up(); while (i--) { ret[i] = this.parse(arr[i], undefined, stack); } this.down(); return join("[", ret, "]"); } function isArray(obj) { return ( //Native Arrays toString.call(obj) === "[object Array]" || // NodeList objects typeof obj.length === "number" && obj.item !== undefined && (obj.length ? obj.item(0) === obj[0] : obj.item(0) === null && obj[0] === undefined) ); } var reName = /^function (\w+)/, dump = { // The objType is used mostly internally, you can fix a (custom) type in advance parse: function parse(obj, objType, stack) { stack = stack || []; var res, parser, parserType, objIndex = stack.indexOf(obj); if (objIndex !== -1) { return "recursion(" + (objIndex - stack.length) + ")"; } objType = objType || this.typeOf(obj); parser = this.parsers[objType]; parserType = typeof parser === "undefined" ? "undefined" : _typeof(parser); if (parserType === "function") { stack.push(obj); res = parser.call(this, obj, stack); stack.pop(); return res; } return parserType === "string" ? parser : this.parsers.error; }, typeOf: function typeOf(obj) { var type; if (obj === null) { type = "null"; } else if (typeof obj === "undefined") { type = "undefined"; } else if (is("regexp", obj)) { type = "regexp"; } else if (is("date", obj)) { type = "date"; } else if (is("function", obj)) { type = "function"; } else if (obj.setInterval !== undefined && obj.document !== undefined && obj.nodeType === undefined) { type = "window"; } else if (obj.nodeType === 9) { type = "document"; } else if (obj.nodeType) { type = "node"; } else if (isArray(obj)) { type = "array"; } else if (obj.constructor === Error.prototype.constructor) { type = "error"; } else { type = typeof obj === "undefined" ? "undefined" : _typeof(obj); } return type; }, separator: function separator() { if (this.multiline) { return this.HTML ? "<br />" : "\n"; } else { return this.HTML ? "&#160;" : " "; } }, // Extra can be a number, shortcut for increasing-calling-decreasing indent: function indent(extra) { if (!this.multiline) { return ""; } var chr = this.indentChar; if (this.HTML) { chr = chr.replace(/\t/g, " ").replace(/ /g, "&#160;"); } return new Array(this.depth + (extra || 0)).join(chr); }, up: function up(a) { this.depth += a || 1; }, down: function down(a) { this.depth -= a || 1; }, setParser: function setParser(name, parser) { this.parsers[name] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, depth: 1, maxDepth: config.maxDepth, // This is the list of parsers, to modify them, use dump.setParser parsers: { window: "[Window]", document: "[Document]", error: function error(_error) { return "Error(\"" + _error.message + "\")"; }, unknown: "[Unknown]", "null": "null", "undefined": "undefined", "function": function _function(fn) { var ret = "function", // Functions never have name in IE name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; if (name) { ret += " " + name; } ret += "("; ret = [ret, dump.parse(fn, "functionArgs"), "){"].join(""); return join(ret, dump.parse(fn, "functionCode"), "}"); }, array: array, nodelist: array, "arguments": array, object: function object(map, stack) { var keys, key, val, i, nonEnumerableProperties, ret = []; if (dump.maxDepth && dump.depth > dump.maxDepth) { return "[object Object]"; } dump.up(); keys = []; for (key in map) { keys.push(key); } // Some properties are not always enumerable on Error objects. nonEnumerableProperties = ["message", "name"]; for (i in nonEnumerableProperties) { key = nonEnumerableProperties[i]; if (key in map && !inArray(key, keys)) { keys.push(key); } } keys.sort(); for (i = 0; i < keys.length; i++) { key = keys[i]; val = map[key]; ret.push(dump.parse(key, "key") + ": " + dump.parse(val, undefined, stack)); } dump.down(); return join("{", ret, "}"); }, node: function node(_node) { var len, i, val, open = dump.HTML ? "&lt;" : "<", close = dump.HTML ? "&gt;" : ">", tag = _node.nodeName.toLowerCase(), ret = open + tag, attrs = _node.attributes; if (attrs) { for (i = 0, len = attrs.length; i < len; i++) { val = attrs[i].nodeValue; // IE6 includes all attributes in .attributes, even ones not explicitly // set. Those have values like undefined, null, 0, false, "" or // "inherit". if (val && val !== "inherit") { ret += " " + attrs[i].nodeName + "=" + dump.parse(val, "attribute"); } } } ret += close; // Show content of TextNode or CDATASection if (_node.nodeType === 3 || _node.nodeType === 4) { ret += _node.nodeValue; } return ret + open + "/" + tag + close; }, // Function calls it internally, it's the arguments part of the function functionArgs: function functionArgs(fn) { var args, l = fn.length; if (!l) { return ""; } args = new Array(l); while (l--) { // 97 is 'a' args[l] = String.fromCharCode(97 + l); } return " " + args.join(", ") + " "; }, // Object calls it internally, the key part of an item in a map key: quote, // Function calls it internally, it's the content of the function functionCode: "[code]", // Node calls it internally, it's a html attribute value attribute: quote, string: quote, date: quote, regexp: literal, number: literal, "boolean": literal, symbol: function symbol(sym) { return sym.toString(); } }, // If true, entities are escaped ( <, >, \t, space and \n ) HTML: false, // Indentation unit indentChar: " ", // If true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; })(); var LISTENERS = Object.create(null); var SUPPORTED_EVENTS = ["runStart", "suiteStart", "testStart", "assertion", "testEnd", "suiteEnd", "runEnd"]; /** * Emits an event with the specified data to all currently registered listeners. * Callbacks will fire in the order in which they are registered (FIFO). This * function is not exposed publicly; it is used by QUnit internals to emit * logging events. * * @private * @method emit * @param {String} eventName * @param {Object} data * @return {Void} */ function emit(eventName, data) { if (objectType(eventName) !== "string") { throw new TypeError("eventName must be a string when emitting an event"); } // Clone the callbacks in case one of them registers a new callback var originalCallbacks = LISTENERS[eventName]; var callbacks = originalCallbacks ? [].concat(toConsumableArray(originalCallbacks)) : []; for (var i = 0; i < callbacks.length; i++) { callbacks[i](data); } } /** * Registers a callback as a listener to the specified event. * * @public * @method on * @param {String} eventName * @param {Function} callback * @return {Void} */ function on(eventName, callback) { if (objectType(eventName) !== "string") { throw new TypeError("eventName must be a string when registering a listener"); } else if (!inArray(eventName, SUPPORTED_EVENTS)) { var events = SUPPORTED_EVENTS.join(", "); throw new Error("\"" + eventName + "\" is not a valid event; must be one of: " + events + "."); } else if (objectType(callback) !== "function") { throw new TypeError("callback must be a function when registering a listener"); } if (!LISTENERS[eventName]) { LISTENERS[eventName] = []; } // Don't register the same callback more than once if (!inArray(callback, LISTENERS[eventName])) { LISTENERS[eventName].push(callback); } } // Register logging callbacks function registerLoggingCallbacks(obj) { var i, l, key, callbackNames = ["begin", "done", "log", "testStart", "testDone", "moduleStart", "moduleDone"]; function registerLoggingCallback(key) { var loggingCallback = function loggingCallback(callback) { if (objectType(callback) !== "function") { throw new Error("QUnit logging methods require a callback function as their first parameters."); } config.callbacks[key].push(callback); }; return loggingCallback; } for (i = 0, l = callbackNames.length; i < l; i++) { key = callbackNames[i]; // Initialize key collection of logging callback if (objectType(config.callbacks[key]) === "undefined") { config.callbacks[key] = []; } obj[key] = registerLoggingCallback(key); } } function runLoggingCallbacks(key, args) { var i, l, callbacks; callbacks = config.callbacks[key]; for (i = 0, l = callbacks.length; i < l; i++) { callbacks[i](args); } } // Doesn't support IE9, it will return undefined on these browsers // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack var fileName = (sourceFromStacktrace(0) || "").replace(/(:\d+)+\)?/, "").replace(/.+\//, ""); function extractStacktrace(e, offset) { offset = offset === undefined ? 4 : offset; var stack, include, i; if (e && e.stack) { stack = e.stack.split("\n"); if (/^error$/i.test(stack[0])) { stack.shift(); } if (fileName) { include = []; for (i = offset; i < stack.length; i++) { if (stack[i].indexOf(fileName) !== -1) { break; } include.push(stack[i]); } if (include.length) { return include.join("\n"); } } return stack[offset]; } } function sourceFromStacktrace(offset) { var error = new Error(); // Support: Safari <=7 only, IE <=10 - 11 only // Not all browsers generate the `stack` property for `new Error()`, see also #636 if (!error.stack) { try { throw error; } catch (err) { error = err; } } return extractStacktrace(error, offset); } var priorityCount = 0; var unitSampler = void 0; /** * Advances the ProcessingQueue to the next item if it is ready. * @param {Boolean} last */ function advance() { var start = now(); config.depth = (config.depth || 0) + 1; while (config.queue.length && !config.blocking) { var elapsedTime = now() - start; if (!defined.setTimeout || config.updateRate <= 0 || elapsedTime < config.updateRate) { if (priorityCount > 0) { priorityCount--; } config.queue.shift()(); } else { setTimeout(advance); break; } } config.depth--; if (!config.blocking && !config.queue.length && config.depth === 0) { done(); } } function addToQueueImmediate(callback) { if (objectType(callback) === "array") { while (callback.length) { addToQueueImmediate(callback.pop()); } return; } config.queue.unshift(callback); priorityCount++; } /** * Adds a function to the ProcessingQueue for execution. * @param {Function|Array} callback * @param {Boolean} priority * @param {String} seed */ function addToQueue(callback, prioritize, seed) { if (prioritize) { config.queue.splice(priorityCount++, 0, callback); } else if (seed) { if (!unitSampler) { unitSampler = unitSamplerGenerator(seed); } // Insert into a random position after all prioritized items var index = Math.floor(unitSampler() * (config.queue.length - priorityCount + 1)); config.queue.splice(priorityCount + index, 0, callback); } else { config.queue.push(callback); } } /** * Creates a seeded "sample" generator which is used for randomizing tests. */ function unitSamplerGenerator(seed) { // 32-bit xorshift, requires only a nonzero seed // http://excamera.com/sphinx/article-xorshift.html var sample = parseInt(generateHash(seed), 16) || -1; return function () { sample ^= sample << 13; sample ^= sample >>> 17; sample ^= sample << 5; // ECMAScript has no unsigned number type if (sample < 0) { sample += 0x100000000; } return sample / 0x100000000; }; } /** * This function is called when the ProcessingQueue is done processing all * items. It handles emitting the final run events. */ function done() { var storage = config.storage; ProcessingQueue.finished = true; var runtime = now() - config.started; var passed = config.stats.all - config.stats.bad; emit("runEnd", globalSuite.end(true)); runLoggingCallbacks("done", { passed: passed, failed: config.stats.bad, total: config.stats.all, runtime: runtime }); // Clear own storage items if all tests passed if (storage && config.stats.bad === 0) { for (var i = storage.length - 1; i >= 0; i--) { var key = storage.key(i); if (key.indexOf("qunit-test-") === 0) { storage.removeItem(key); } } } } var ProcessingQueue = { finished: false, add: addToQueue, addImmediate: addToQueueImmediate, advance: advance }; var TestReport = function () { function TestReport(name, suite, options) { classCallCheck(this, TestReport); this.name = name; this.suiteName = suite.name; this.fullName = suite.fullName.concat(name); this.runtime = 0; this.assertions = []; this.skipped = !!options.skip; this.todo = !!options.todo; this.valid = options.valid; this._startTime = 0; this._endTime = 0; suite.pushTest(this); } createClass(TestReport, [{ key: "start", value: function start(recordTime) { if (recordTime) { this._startTime = Date.now(); } return { name: this.name, suiteName: this.suiteName, fullName: this.fullName.slice() }; } }, { key: "end", value: function end(recordTime) { if (recordTime) { this._endTime = Date.now(); } return extend(this.start(), { runtime: this.getRuntime(), status: this.getStatus(), errors: this.getFailedAssertions(), assertions: this.getAssertions() }); } }, { key: "pushAssertion", value: function pushAssertion(assertion) { this.assertions.push(assertion); } }, { key: "getRuntime", value: function getRuntime() { return this._endTime - this._startTime; } }, { key: "getStatus", value: function getStatus() { if (this.skipped) { return "skipped"; } var testPassed = this.getFailedAssertions().length > 0 ? this.todo : !this.todo; if (!testPassed) { return "failed"; } else if (this.todo) { return "todo"; } else { return "passed"; } } }, { key: "getFailedAssertions", value: function getFailedAssertions() { return this.assertions.filter(function (assertion) { return !assertion.passed; }); } }, { key: "getAssertions", value: function getAssertions() { return this.assertions.slice(); } // Remove actual and expected values from assertions. This is to prevent // leaking memory throughout a test suite. }, { key: "slimAssertions", value: function slimAssertions() { this.assertions = this.assertions.map(function (assertion) { delete assertion.actual; delete assertion.expected; return assertion; }); } }]); return TestReport; }(); var focused$1 = false; function Test(settings) { var i, l; ++Test.count; this.expected = null; this.assertions = []; this.semaphore = 0; this.module = config.currentModule; this.stack = sourceFromStacktrace(3); this.steps = []; this.timeout = undefined; // If a module is skipped, all its tests and the tests of the child suites // should be treated as skipped even if they are defined as `only` or `todo`. // As for `todo` module, all its tests will be treated as `todo` except for // tests defined as `skip` which will be left intact. // // So, if a test is defined as `todo` and is inside a skipped module, we should // then treat that test as if was defined as `skip`. if (this.module.skip) { settings.skip = true; settings.todo = false; // Skipped tests should be left intact } else if (this.module.todo && !settings.skip) { settings.todo = true; } extend(this, settings); this.testReport = new TestReport(settings.testName, this.module.suiteReport, { todo: settings.todo, skip: settings.skip, valid: this.valid() }); // Register unique strings for (i = 0, l = this.module.tests; i < l.length; i++) { if (this.module.tests[i].name === this.testName) { this.testName += " "; } } this.testId = generateHash(this.module.name, this.testName); this.module.tests.push({ name: this.testName, testId: this.testId, skip: !!settings.skip }); if (settings.skip) { // Skipped tests will fully ignore any sent callback this.callback = function () {}; this.async = false; this.expected = 0; } else { if (typeof this.callback !== "function") { var method = this.todo ? "todo" : "test"; // eslint-disable-next-line max-len throw new TypeError("You must provide a function as a test callback to QUnit." + method + "(\"" + settings.testName + "\")"); } this.assert = new Assert(this); } } Test.count = 0; function getNotStartedModules(startModule) { var module = startModule, modules = []; while (module && module.testsRun === 0) { modules.push(module); module = module.parentModule; } return modules; } Test.prototype = { before: function before() { var i, startModule, module = this.module, notStartedModules = getNotStartedModules(module); for (i = notStartedModules.length - 1; i >= 0; i--) { startModule = notStartedModules[i]; startModule.stats = { all: 0, bad: 0, started: now() }; emit("suiteStart", startModule.suiteReport.start(true)); runLoggingCallbacks("moduleStart", { name: startModule.name, tests: startModule.tests }); } config.current = this; this.testEnvironment = extend({}, module.testEnvironment); this.started = now(); emit("testStart", this.testReport.start(true)); runLoggingCallbacks("testStart", { name: this.testName, module: module.name, testId: this.testId, previousFailure: this.previousFailure }); if (!config.pollution) { saveGlobal(); } }, run: function run() { var promise; config.current = this; this.callbackStarted = now(); if (config.notrycatch) { runTest(this); return; } try { runTest(this); } catch (e) { this.pushFailure("Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + (e.message || e), extractStacktrace(e, 0)); // Else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if (config.blocking) { internalRecover(this); } } function runTest(test) { promise = test.callback.call(test.testEnvironment, test.assert); test.resolvePromise(promise); // If the test has a "lock" on it, but the timeout is 0, then we push a // failure as the test should be synchronous. if (test.timeout === 0 && test.semaphore !== 0) { pushFailure("Test did not finish synchronously even though assert.timeout( 0 ) was used.", sourceFromStacktrace(2)); } } }, after: function after() { checkPollution(); }, queueHook: function queueHook(hook, hookName, hookOwner) { var _this = this; var callHook = function callHook() { var promise = hook.call(_this.testEnvironment, _this.assert); _this.resolvePromise(promise, hookName); }; var runHook = function runHook() { if (hookName === "before") { if (hookOwner.unskippedTestsRun !== 0) { return; } _this.preserveEnvironment = true; } if (hookName === "after" && hookOwner.unskippedTestsRun !== numberOfUnskippedTests(hookOwner) - 1 && config.queue.length > 2) { return; } config.current = _this; if (config.notrycatch) { callHook(); return; } try { callHook(); } catch (error) { _this.pushFailure(hookName + " failed on " + _this.testName + ": " + (error.message || error), extractStacktrace(error, 0)); } }; return runHook; }, // Currently only used for module level hooks, can be used to add global level ones hooks: function hooks(handler) { var hooks = []; function processHooks(test, module) { if (module.parentModule) { processHooks(test, module.parentModule); } if (module.hooks[handler].length) { for (var i = 0; i < module.hooks[handler].length; i++) { hooks.push(test.queueHook(module.hooks[handler][i], handler, module)); } } } // Hooks are ignored on skipped tests if (!this.skip) { processHooks(this, this.module); } return hooks; }, finish: function finish() { config.current = this; if (config.requireExpects && this.expected === null) { this.pushFailure("Expected number of assertions to be defined, but expect() was " + "not called.", this.stack); } else if (this.expected !== null && this.expected !== this.assertions.length) { this.pushFailure("Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack); } else if (this.expected === null && !this.assertions.length) { this.pushFailure("Expected at least one assertion, but none were run - call " + "expect(0) to accept zero assertions.", this.stack); } var i, module = this.module, moduleName = module.name, testName = this.testName, skipped = !!this.skip, todo = !!this.todo, bad = 0, storage = config.storage; this.runtime = now() - this.started; config.stats.all += this.assertions.length; module.stats.all += this.assertions.length; for (i = 0; i < this.assertions.length; i++) { if (!this.assertions[i].result) { bad++; config.stats.bad++; module.stats.bad++; } } notifyTestsRan(module, skipped); // Store result when possible if (storage) { if (bad) { storage.setItem("qunit-test-" + moduleName + "-" + testName, bad); } else { storage.removeItem("qunit-test-" + moduleName + "-" + testName); } } // After emitting the js-reporters event we cleanup the assertion data to // avoid leaking it. It is not used by the legacy testDone callbacks. emit("testEnd", this.testReport.end(true)); this.testReport.slimAssertions(); runLoggingCallbacks("testDone", { name: testName, module: moduleName, skipped: skipped, todo: todo, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, runtime: skipped ? 0 : this.runtime, // HTML Reporter use assertions: this.assertions, testId: this.testId, // Source of Test source: this.stack }); if (module.testsRun === numberOfTests(module)) { logSuiteEnd(module); // Check if the parent modules, iteratively, are done. If that the case, // we emit the `suiteEnd` event and trigger `moduleDone` callback. var parent = module.parentModule; while (parent && parent.testsRun === numberOfTests(parent)) { logSuiteEnd(parent); parent = parent.parentModule; } } config.current = undefined; function logSuiteEnd(module) { emit("suiteEnd", module.suiteReport.end(true)); runLoggingCallbacks("moduleDone", { name: module.name, tests: module.tests, failed: module.stats.bad, passed: module.stats.all - module.stats.bad, total: module.stats.all, runtime: now() - module.stats.started }); } }, preserveTestEnvironment: function preserveTestEnvironment() { if (this.preserveEnvironment) { this.module.testEnvironment = this.testEnvironment; this.testEnvironment = extend({}, this.module.testEnvironment); } }, queue: function queue() { var test = this; if (!this.valid()) { return; } function runTest() { // Each of these can by async ProcessingQueue.addImmediate([function () { test.before(); }, test.hooks("before"), function () { test.preserveTestEnvironment(); }, test.hooks("beforeEach"), function () { test.run(); }, test.hooks("afterEach").reverse(), test.hooks("after").reverse(), function () { test.after(); }, function () { test.finish(); }]); } var previousFailCount = config.storage && +config.storage.getItem("qunit-test-" + this.module.name + "-" + this.testName); // Prioritize previously failed tests, detected from storage var prioritize = config.reorder && !!previousFailCount; this.previousFailure = !!previousFailCount; ProcessingQueue.add(runTest, prioritize, config.seed); // If the queue has already finished, we manually process the new test if (ProcessingQueue.finished) { ProcessingQueue.advance(); } }, pushResult: function pushResult(resultInfo) { if (this !== config.current) { throw new Error("Assertion occurred after test had finished."); } // Destructure of resultInfo = { result, actual, expected, message, negative } var source, details = { module: this.module.name, name: this.testName, result: resultInfo.result, message: resultInfo.message, actual: resultInfo.actual, testId: this.testId, negative: resultInfo.negative || false, runtime: now() - this.started, todo: !!this.todo }; if (hasOwn.call(resultInfo, "expected")) { details.expected = resultInfo.expected; } if (!resultInfo.result) { source = resultInfo.source || sourceFromStacktrace(); if (source) { details.source = source; } } this.logAssertion(details); this.assertions.push({ result: !!resultInfo.result, message: resultInfo.message }); }, pushFailure: function pushFailure(message, source, actual) { if (!(this instanceof Test)) { throw new Error("pushFailure() assertion outside test context, was " + sourceFromStacktrace(2)); } this.pushResult({ result: false, message: message || "error", actual: actual || null, source: source }); }, /** * Log assertion details using both the old QUnit.log interface and * QUnit.on( "assertion" ) interface. * * @private */ logAssertion: function logAssertion(details) { runLoggingCallbacks("log", details); var assertion = { passed: details.result, actual: details.actual, expected: details.expected, message: details.message, stack: details.source, todo: details.todo }; this.testReport.pushAssertion(assertion); emit("assertion", assertion); }, resolvePromise: function resolvePromise(promise, phase) { var then, resume, message, test = this; if (promise != null) { then = promise.then; if (objectType(then) === "function") { resume = internalStop(test); if (config.notrycatch) { then.call(promise, function () { resume(); }); } else { then.call(promise, function () { resume(); }, function (error) { message = "Promise rejected " + (!phase ? "during" : phase.replace(/Each$/, "")) + " \"" + test.testName + "\": " + (error && error.message || error); test.pushFailure(message, extractStacktrace(error, 0)); // Else next test will carry the responsibility saveGlobal(); // Unblock resume(); }); } } } }, valid: function valid() { var filter = config.filter, regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec(filter), module = config.module && config.module.toLowerCase(), fullName = this.module.name + ": " + this.testName; function moduleChainNameMatch(testModule) { var testModuleName = testModule.name ? testModule.name.toLowerCase() : null; if (testModuleName === module) { return true; } else if (testModule.parentModule) { return moduleChainNameMatch(testModule.parentModule); } else { return false; } } function moduleChainIdMatch(testModule) { return inArray(testModule.moduleId, config.moduleId) || testModule.parentModule && moduleChainIdMatch(testModule.parentModule); } // Internally-generated tests are always valid if (this.callback && this.callback.validTest) { return true; } if (config.moduleId && config.moduleId.length > 0 && !moduleChainIdMatch(this.module)) { return false; } if (config.testId && config.testId.length > 0 && !inArray(this.testId, config.testId)) { return false; } if (module && !moduleChainNameMatch(this.module)) { return false; } if (!filter) { return true; } return regexFilter ? this.regexFilter(!!regexFilter[1], regexFilter[2], regexFilter[3], fullName) : this.stringFilter(filter, fullName); }, regexFilter: function regexFilter(exclude, pattern, flags, fullName) { var regex = new RegExp(pattern, flags); var match = regex.test(fullName); return match !== exclude; }, stringFilter: function stringFilter(filter, fullName) { filter = filter.toLowerCase(); fullNa