UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

1,486 lines (1,429 loc) 262 kB
/*! * QUnit 2.20.0 * https://qunitjs.com/ * * Copyright OpenJS Foundation and other contributors * Released under the MIT license * https://jquery.org/license */ (function () { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = it.call(o); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } // We don't use global-this-polyfill [1], because it modifies // the globals scope by default. QUnit must not affect the host context // as developers may test their project may be such a polyfill, and/or // they may intentionally test their project with and without certain // polyfills and we must not affect that. It also uses an obscure // mechanism that seems to sometimes causes a runtime error in older // browsers (specifically Safari and IE versions that support // Object.defineProperty but then report _T_ as undefined). // [1] https://github.com/ungap/global-this/blob/v0.4.4/esm/index.js // // Another way is `Function('return this')()`, but doing so relies // on eval which will cause a CSP error on some servers. // // Instead, simply check the four options that already exist // in all supported environments. function getGlobalThis() { if (typeof globalThis !== 'undefined') { // For SpiderMonkey, modern browsers, and recent Node.js // eslint-disable-next-line no-undef return globalThis; } if (typeof self !== 'undefined') { // For web workers // eslint-disable-next-line no-undef return self; } if (typeof window$1 !== 'undefined') { // For document context in browsers return window$1; } if (typeof global !== 'undefined') { // For Node.js // eslint-disable-next-line no-undef return global; } throw new Error('Unable to locate global object'); } // This avoids a simple `export const` assignment as that would lead Rollup // to change getGlobalThis and use the same (generated) variable name there. var g = getGlobalThis(); var window$1 = g.window; var console$1 = g.console; var setTimeout$1 = g.setTimeout; var clearTimeout = g.clearTimeout; var document = window$1 && window$1.document; var navigator = window$1 && window$1.navigator; var localSessionStorage = function () { var x = 'qunit-test-string'; try { g.sessionStorage.setItem(x, x); g.sessionStorage.removeItem(x); return g.sessionStorage; } catch (e) { return undefined; } }(); // Basic fallback for ES6 Map // Support: IE 9-10, Safari 7, PhantomJS; Map is undefined // Support: iOS 8; `new Map(iterable)` is not supported // // Fallback for ES7 Map#keys // Support: IE 11; Map#keys is undefined var StringMap = typeof g.Map === 'function' && typeof g.Map.prototype.keys === 'function' && typeof g.Symbol === 'function' && _typeof(g.Symbol.iterator) === 'symbol' ? g.Map : function StringMap(input) { var _this = this; var store = Object.create(null); var hasOwn = Object.prototype.hasOwnProperty; this.has = function (strKey) { return hasOwn.call(store, strKey); }; this.get = function (strKey) { return store[strKey]; }; this.set = function (strKey, val) { if (!hasOwn.call(store, strKey)) { this.size++; } store[strKey] = val; return this; }; this.delete = function (strKey) { if (hasOwn.call(store, strKey)) { delete store[strKey]; this.size--; } }; this.forEach = function (callback) { for (var strKey in store) { callback(store[strKey], strKey); } }; this.keys = function () { return Object.keys(store); }; this.clear = function () { store = Object.create(null); this.size = 0; }; this.size = 0; if (input) { input.forEach(function (val, strKey) { _this.set(strKey, val); }); } }; // Basic fallback for ES6 Set // Support: IE 11, `new Set(iterable)` parameter not yet implemented // Test for Set#values() which came after Set(iterable). var StringSet = typeof g.Set === 'function' && typeof g.Set.prototype.values === 'function' ? g.Set : function (input) { var set = Object.create(null); if (Array.isArray(input)) { input.forEach(function (item) { set[item] = true; }); } return { add: function add(value) { set[value] = true; }, has: function has(value) { return value in set; }, get size() { return Object.keys(set).length; } }; }; var toString = Object.prototype.toString; var hasOwn$1 = Object.prototype.hasOwnProperty; var performance = { // eslint-disable-next-line compat/compat -- Checked now: window$1 && window$1.performance && window$1.performance.now ? window$1.performance.now.bind(window$1.performance) : Date.now }; // Returns a new Array with the elements that are in a but not in b function diff(a, b) { return a.filter(function (a) { return b.indexOf(a) === -1; }); } /** * Determines whether an element exists in a given array or not. * * @method inArray * @param {any} elem * @param {Array} array * @return {boolean} */ var inArray = Array.prototype.includes ? function (elem, array) { return array.includes(elem); } : function (elem, array) { return array.indexOf(elem) !== -1; }; /** * Recursively clone an object into a plain array or object, taking only the * own enumerable properties. * * @param {any} obj * @param {bool} [allowArray=true] * @return {Object|Array} */ function objectValues(obj) { var allowArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var vals = allowArray && is('array', obj) ? [] : {}; for (var key in obj) { if (hasOwn$1.call(obj, key)) { var val = obj[key]; vals[key] = val === Object(val) ? objectValues(val, allowArray) : val; } } return vals; } /** * Recursively clone an object into a plain object, taking only the * subset of own enumerable properties that exist a given model. * * @param {any} obj * @param {any} model * @return {Object} */ function objectValuesSubset(obj, model) { // Return primitive values unchanged to avoid false positives or confusing // results from assert.propContains(). // E.g. an actual null or false wrongly equaling an empty object, // or an actual string being reported as object not matching a partial object. if (obj !== Object(obj)) { return obj; } // Unlike objectValues(), subset arrays to a plain objects as well. // This enables subsetting [20, 30] with {1: 30}. var subset = {}; for (var key in model) { if (hasOwn$1.call(model, key) && hasOwn$1.call(obj, key)) { subset[key] = objectValuesSubset(obj[key], model[key]); } } return subset; } function extend(a, b, undefOnly) { for (var prop in b) { if (hasOwn$1.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(.*)\]$/); var 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); } } // 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); } /** * Converts an error into a simple string for comparisons. * * @param {Error|any} error * @return {string} */ function errorString(error) { // Use String() instead of toString() to handle non-object values like undefined or null. var resultErrorString = String(error); // If the error wasn't a subclass of Error but something like // an object literal with name and message properties... if (resultErrorString.slice(0, 7) === '[object') { // Based on https://es5.github.io/#x15.11.4.4 return (error.name || 'Error') + (error.message ? ": ".concat(error.message) : ''); } else { return resultErrorString; } } var BOXABLE_TYPES = new StringSet(['boolean', 'number', 'string']); // Memory for previously seen containers (object, array, map, set). // Used for recursion detection, and to avoid repeated comparison. // // Elements are { a: val, b: val }. var memory = []; function useStrictEquality(a, b) { return a === b; } function useObjectValueEquality(a, b) { return a === b || a.valueOf() === b.valueOf(); } function compareConstructors(a, b) { // Comparing constructors is more strict than using `instanceof` return getConstructor(a) === getConstructor(b); } function getConstructor(obj) { var proto = Object.getPrototypeOf(obj); // If the obj prototype descends from a null constructor, treat it // as a null prototype. // Ref https://github.com/qunitjs/qunit/issues/851 // // Allow objects with no prototype, from Object.create(null), to be equivalent to // plain objects that have Object as their constructor. return !proto || proto.constructor === null ? Object : obj.constructor; } function getRegExpFlags(regexp) { return 'flags' in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0]; } // Specialised comparisons after entryTypeCallbacks.object, based on `objectType()` var objTypeCallbacks = { undefined: useStrictEquality, null: useStrictEquality, // Handle boxed boolean boolean: useObjectValueEquality, number: function number(a, b) { // Handle NaN and boxed number return a === b || a.valueOf() === b.valueOf() || isNaN(a.valueOf()) && isNaN(b.valueOf()); }, // Handle boxed string string: useObjectValueEquality, symbol: useStrictEquality, date: useObjectValueEquality, nan: function nan() { return true; }, regexp: function regexp(a, b) { return a.source === b.source && // Include flags in the comparison getRegExpFlags(a) === getRegExpFlags(b); }, // identical reference only function: useStrictEquality, array: function array(a, b) { if (a.length !== b.length) { // Safe and faster return false; } for (var i = 0; i < a.length; i++) { if (!typeEquiv(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( [ X={}, Y=[], Y ] ); // b = new Set( [ Y, X, X ] ); set: function set(a, b) { 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; } var outerEq = true; 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; } var innerEq = false; b.forEach(function (bVal) { // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global memory, as nested typeEquiv() would clobber it var originalMemory = memory; memory = []; if (typeEquiv(bVal, aVal)) { innerEq = true; } // Restore memory = originalMemory; }); 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) { 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; } var outerEq = true; 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; } var innerEq = false; b.forEach(function (bVal, bKey) { // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global memory, as nested typeEquiv() would clobber it var originalMemory = memory; memory = []; if (objTypeCallbacks.array([bVal, bKey], [aVal, aKey])) { innerEq = true; } // Restore memory = originalMemory; }); if (!innerEq) { outerEq = false; } }); return outerEq; } }; // Entry points from typeEquiv, based on `typeof` var entryTypeCallbacks = { undefined: useStrictEquality, null: useStrictEquality, boolean: useStrictEquality, number: function number(a, b) { // Handle NaN return a === b || isNaN(a) && isNaN(b); }, string: useStrictEquality, symbol: useStrictEquality, function: useStrictEquality, object: function object(a, b) { // Handle memory (skip recursion) if (memory.some(function (pair) { return pair.a === a && pair.b === b; })) { return true; } memory.push({ a: a, b: b }); var aObjType = objectType(a); var bObjType = objectType(b); if (aObjType !== 'object' || bObjType !== 'object') { // Handle literal `null` // Handle: Array, Map/Set, Date, Regxp/Function, boxed primitives return aObjType === bObjType && objTypeCallbacks[aObjType](a, b); } // NOTE: Literal null must not make it here as it would throw if (compareConstructors(a, b) === false) { return false; } var aProperties = []; var bProperties = []; // Be strict and go deep, no filtering with hasOwnProperty. for (var 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; } if (!typeEquiv(a[i], b[i])) { return false; } } for (var _i in b) { // Collect b's properties bProperties.push(_i); } return objTypeCallbacks.array(aProperties.sort(), bProperties.sort()); } }; function typeEquiv(a, b) { // Optimization: Only perform type-specific comparison when pairs are not strictly equal. if (a === b) { return true; } var aType = _typeof(a); var bType = _typeof(b); if (aType !== bType) { // Support comparing primitive to boxed primitives // Try again after possibly unwrapping one return (aType === 'object' && BOXABLE_TYPES.has(objectType(a)) ? a.valueOf() : a) === (bType === 'object' && BOXABLE_TYPES.has(objectType(b)) ? b.valueOf() : b); } return entryTypeCallbacks[aType](a, b); } function innerEquiv(a, b) { var res = typeEquiv(a, b); // Release any retained objects and reset recursion detection for next call memory = []; return res; } /** * Test any two types of JavaScript values for equality. * * @author Philippe Rathé <prathe@gmail.com> * @author David Chan <david@troi.org> */ function equiv(a, b) { if (arguments.length === 2) { return a === b || innerEquiv(a, b); } // Given 0 or 1 arguments, just return true (nothing to compare). // Given (A,B,C,D) compare C,D then B,C then A,B. var i = arguments.length - 1; while (i > 0) { if (!innerEquiv(arguments[i - 1], arguments[i])) { return false; } i--; } return true; } /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ var config = { // HTML Reporter: 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, // whether or not to fail when there are zero tests // defaults to `true` failOnZeroTests: true, // Select by pattern or case-insensitive substring match against "moduleName: testName" filter: undefined, // Depth up-to which object will be dumped maxDepth: 5, // Select case-insensitive match of the module name module: undefined, // HTML Reporter: Select module/test by array of internal IDs moduleId: undefined, // By default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // When enabled, all tests must call expect() requireExpects: false, // By default, scroll to top of the page when suite is done scrolltop: true, // The storage module to use for reordering tests storage: localSessionStorage, testId: undefined, // HTML Reporter: List of URL parameters that are given visual controls urlConfig: [], // Internal: The first unnamed module // // By being defined as the intial value for currentModule, it is the // receptacle and implied parent for any global tests. It is as if we // called `QUnit.module( "" );` before any other tests were defined. // // If we reach begin() and no tests were put in it, we dequeue it as if it // never existed, and in that case never expose it to the events and // callbacks API. // // When global tests are defined, then this unnamed module will execute // as any other module, including moduleStart/moduleDone events etc. // // Since this module isn't explicitly created by the user, they have no // access to add hooks for it. The hooks object is defined to comply // with internal expectations of test.js, but they will be empty. // To apply hooks, place tests explicitly in a QUnit.module(), and use // its hooks accordingly. // // For global hooks that apply to all tests and all modules, use QUnit.hooks. // // NOTE: This is *not* a "global module". It is not an ancestor of all modules // and tests. It is merely the parent for any tests defined globally, // before the first QUnit.module(). As such, the events for this unnamed // module will fire as normal, right after its last test, and *not* at // the end of the test run. // // NOTE: This also should probably also not become a global module, unless // we keep it out of the public API. For example, it would likely not // improve the user interface and plugin behaviour if all modules became // wrapped between the start and end events of this module, and thus // needlessly add indentation, indirection, or other visible noise. // Unit tests for the callbacks API would detect that as a regression. currentModule: { name: '', tests: [], childModules: [], testsRun: 0, testsIgnored: 0, hooks: { before: [], beforeEach: [], afterEach: [], after: [] } }, // Internal: Exposed to make resets easier // Ref https://github.com/qunitjs/qunit/pull/1598 globalHooks: {}, // Internal state blocking: true, callbacks: {}, modules: [], queue: [], stats: { all: 0, bad: 0, testCount: 0 } }; // Apply a predefined QUnit.config object // // Ignore QUnit.config if it is a QUnit distribution instead of preconfig. // That means QUnit was loaded twice! (Use the same approach as export.js) var preConfig = g && g.QUnit && !g.QUnit.version && g.QUnit.config; if (preConfig) { extend(config, preConfig); } // Push a loose unnamed module to the modules collection config.modules.push(config.currentModule); 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(); var inner = dump.indent(1); if (arr.join) { arr = arr.join(',' + s + inner); } if (!arr) { return pre + post; } var base = dump.indent(); return [pre, inner + arr, base + post].join(s); } function array(arr, stack) { if (dump.maxDepth && dump.depth > dump.maxDepth) { return '[object Array]'; } this.up(); var i = arr.length; var ret = new Array(i); 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+)/; var dump = { // The objType is used mostly internally, you can fix a (custom) type in advance parse: function parse(obj, objType, stack) { stack = stack || []; var objIndex = stack.indexOf(obj); if (objIndex !== -1) { return "recursion(".concat(objIndex - stack.length, ")"); } objType = objType || this.typeOf(obj); var parser = this.parsers[objType]; var parserType = _typeof(parser); if (parserType === 'function') { stack.push(obj); var res = parser.call(this, obj, stack); stack.pop(); return res; } if (parserType === 'string') { return parser; } return '[ERROR: Missing QUnit.dump formatter for type ' + objType + ']'; }, 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); } 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 + '")'; }, // This has been unused since QUnit 1.0.0. // @todo Deprecate and remove. unknown: '[Unknown]', null: 'null', undefined: 'undefined', function: function _function(fn) { var ret = 'function'; // Functions never have name in IE var 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 ret = []; if (dump.maxDepth && dump.depth > dump.maxDepth) { return '[object Object]'; } dump.up(); var keys = []; for (var key in map) { keys.push(key); } // Some properties are not always enumerable on Error objects. var nonEnumerableProperties = ['message', 'name']; for (var i in nonEnumerableProperties) { var _key = nonEnumerableProperties[i]; if (_key in map && !inArray(_key, keys)) { keys.push(_key); } } keys.sort(); for (var _i = 0; _i < keys.length; _i++) { var _key2 = keys[_i]; var val = map[_key2]; ret.push(dump.parse(_key2, 'key') + ': ' + dump.parse(val, undefined, stack)); } dump.down(); return join('{', ret, '}'); }, node: function node(_node) { var open = dump.HTML ? '&lt;' : '<'; var close = dump.HTML ? '&gt;' : '>'; var tag = _node.nodeName.toLowerCase(); var ret = open + tag; var attrs = _node.attributes; if (attrs) { for (var i = 0; i < attrs.length; i++) { var 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 l = fn.length; if (!l) { return ''; } var 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; })(); // Support: IE 9 // Detect if the console object exists and no-op otherwise. // This allows support for IE 9, which doesn't have a console // object if the developer tools are not open. // Support: IE 9 // Function#bind is supported, but no console.log.bind(). // Support: SpiderMonkey (mozjs 68+) // The console object has a log method, but no warn method. var Logger = { warn: console$1 ? Function.prototype.bind.call(console$1.warn || console$1.log, console$1) : function () {} }; var SuiteReport = /*#__PURE__*/function () { function SuiteReport(name, parentSuite) { _classCallCheck(this, SuiteReport); this.name = name; this.fullName = parentSuite ? parentSuite.fullName.concat(name) : []; // When an "error" event is emitted from onUncaughtException(), the // "runEnd" event should report the status as failed. The "runEnd" event data // is tracked through this property (via the "runSuite" instance). this.globalFailureCount = 0; this.tests = []; this.childSuites = []; if (parentSuite) { parentSuite.pushChildSuite(this); } } _createClass(SuiteReport, [{ key: "start", value: function start(recordTime) { if (recordTime) { this._startTime = performance.now(); } return { name: this.name, fullName: this.fullName.slice(), tests: this.tests.map(function (test) { return test.start(); }), childSuites: this.childSuites.map(function (suite) { return suite.start(); }), testCounts: { total: this.getTestCounts().total } }; } }, { key: "end", value: function end(recordTime) { if (recordTime) { this._endTime = performance.now(); } return { name: this.name, fullName: this.fullName.slice(), tests: this.tests.map(function (test) { return test.end(); }), childSuites: this.childSuites.map(function (suite) { return suite.end(); }), testCounts: this.getTestCounts(), runtime: this.getRuntime(), status: this.getStatus() }; } }, { key: "pushChildSuite", value: function pushChildSuite(suite) { this.childSuites.push(suite); } }, { key: "pushTest", value: function pushTest(test) { this.tests.push(test); } }, { key: "getRuntime", value: function getRuntime() { return Math.round(this._endTime - this._startTime); } }, { key: "getTestCounts", value: function getTestCounts() { var counts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 }; counts.failed += this.globalFailureCount; counts.total += this.globalFailureCount; counts = this.tests.reduce(function (counts, test) { if (test.valid) { counts[test.getStatus()]++; counts.total++; } return counts; }, counts); return this.childSuites.reduce(function (counts, suite) { return suite.getTestCounts(counts); }, counts); } }, { key: "getStatus", value: function getStatus() { var _this$getTestCounts = this.getTestCounts(), total = _this$getTestCounts.total, failed = _this$getTestCounts.failed, skipped = _this$getTestCounts.skipped, todo = _this$getTestCounts.todo; if (failed) { return 'failed'; } else { if (skipped === total) { return 'skipped'; } else if (todo === total) { return 'todo'; } else { return 'passed'; } } } }]); return SuiteReport; }(); var moduleStack = []; var runSuite = new SuiteReport(); function isParentModuleInQueue() { var modulesInQueue = config.modules.filter(function (module) { return !module.ignored; }).map(function (module) { return module.moduleId; }); return moduleStack.some(function (module) { return modulesInQueue.includes(module.moduleId); }); } function createModule(name, testEnvironment, modifiers) { var parentModule = moduleStack.length ? moduleStack.slice(-1)[0] : null; var moduleName = parentModule !== null ? [parentModule.name, name].join(' > ') : name; var parentSuite = parentModule ? parentModule.suiteReport : runSuite; var skip = parentModule !== null && parentModule.skip || modifiers.skip; var todo = parentModule !== null && parentModule.todo || modifiers.todo; var env = {}; if (parentModule) { extend(env, parentModule.testEnvironment); } extend(env, testEnvironment); var module = { name: moduleName, parentModule: parentModule, hooks: { before: [], beforeEach: [], afterEach: [], after: [] }, testEnvironment: env, tests: [], moduleId: generateHash(moduleName), testsRun: 0, testsIgnored: 0, childModules: [], suiteReport: new SuiteReport(name, parentSuite), // Initialised by test.js when the module start executing, // i.e. before the first test in this module (or a child). stats: null, // Pass along `skip` and `todo` properties from parent module, in case // there is one, to childs. And use own otherwise. // This property will be used to mark own tests and tests of child suites // as either `skipped` or `todo`. skip: skip, todo: skip ? false : todo, ignored: modifiers.ignored || false }; if (parentModule) { parentModule.childModules.push(module); } config.modules.push(module); return module; } function setHookFromEnvironment(hooks, environment, name) { var potentialHook = environment[name]; if (typeof potentialHook === 'function') { hooks[name].push(potentialHook); } delete environment[name]; } function makeSetHook(module, hookName) { return function setHook(callback) { if (config.currentModule !== module) { Logger.warn('The `' + hookName + '` hook was called inside the wrong module (`' + config.currentModule.name + '`). ' + 'Instead, use hooks provided by the callback to the containing module (`' + module.name + '`). ' + 'This will become an error in QUnit 3.0.'); } module.hooks[hookName].push(callback); }; } function processModule(name, options, executeNow) { var modifiers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (typeof options === 'function') { executeNow = options; options = undefined; } var module = createModule(name, options, modifiers); // Transfer any initial hooks from the options object to the 'hooks' object var testEnvironment = module.testEnvironment; var hooks = module.hooks; setHookFromEnvironment(hooks, testEnvironment, 'before'); setHookFromEnvironment(hooks, testEnvironment, 'beforeEach'); setHookFromEnvironment(hooks, testEnvironment, 'afterEach'); setHookFromEnvironment(hooks, testEnvironment, 'after'); var moduleFns = { before: makeSetHook(module, 'before'), beforeEach: makeSetHook(module, 'beforeEach'), afterEach: makeSetHook(module, 'afterEach'), after: makeSetHook(module, 'after') }; var prevModule = config.currentModule; config.currentModule = module; if (typeof executeNow === 'function') { moduleStack.push(module); try { var cbReturnValue = executeNow.call(module.testEnvironment, moduleFns); if (cbReturnValue && typeof cbReturnValue.then === 'function') { Logger.warn('Returning a promise from a module callback is not supported. ' + 'Instead, use hooks for async behavior. ' + 'This will become an error in QUnit 3.0.'); } } finally { // If the module closure threw an uncaught error during the load phase, // we let this bubble up to global error handlers. But, not until after // we teardown internal state to ensure correct module nesting. // Ref https://github.com/qunitjs/qunit/issues/1478. moduleStack.pop(); config.currentModule = module.parentModule || prevModule; } } } var focused$1 = false; // indicates that the "only" filter was used function module$1(name, options, executeNow) { var ignored = focused$1 && !isParentModuleInQueue(); processModule(name, options, executeNow, { ignored: ignored }); } module$1.only = function () { if (!focused$1) { // Upon the first module.only() call, // delete any and all previously registered modules and tests. config.modules.length = 0; config.queue.length = 0; // Ignore any tests declared after this block within the same // module parent. https://github.com/qunitjs/qunit/issues/1645 config.currentModule.ignored = true; } focused$1 = true; processModule.apply(void 0, arguments); }; module$1.skip = function (name, options, executeNow) { if (focused$1) { return; } processModule(name, options, executeNow, { skip: true }); }; module$1.todo = function (name, options, executeNow) { if (focused$1) { return; } processModule(name, options, executeNow, { todo: true }); }; // 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+)+\)?/, '') // Remove anything prior to the last slash (Unix/Windows) // from the last frame .replace(/.+[/\\]/, ''); function extractStacktrace(e, offset) { offset = offset === undefined ? 4 : offset; if (e && e.stack) { var stack = e.stack.split('\n'); if (/^error$/i.test(stack[0])) { stack.shift(); } if (fileName) { var include = []; for (var 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 Assert = /*#__PURE__*/function () { function Assert(testContext) { _classCallCheck(this, Assert); this.test = testContext; } _createClass(Assert, [{ key: "timeout", value: function timeout(duration) { if (typeof duration !== 'number') { throw new Error('You must pass a number as the duration to assert.timeout'); } this.test.timeout = duration; // If a timeout has been set, clear it and reset with the new duration if (config.timeout) { clearTimeout(config.timeout); config.timeout = null; if (config.timeoutHandler && this.test.timeout > 0) { this.test.internalResetTimeout(this.test.timeout); } } } // Documents a "step", which is a string value, in a test as a passing assertion }, { key: "step", value: function step(message) { var assertionMessage = message; var result = !!message; this.test.steps.push(message); if (typeof message === 'undefined' || message === '') { assertionMessage = 'You must provide a message to assert.step'; } else if (typeof message !== 'string') { assertionMessage = 'You must provide a string value to assert.step'; result = false; } this.pushResult({ result: result, message: assertionMessage }); } // Verifies the steps in a test match a given array of string values }, { key: "verifySteps", value: function verifySteps(steps, message) { // Since the steps array is just string values, we can clone with slice var actualStepsClone = this.test.steps.slice(); this.deepEqual(actualStepsClone, steps, message); this.test.steps.length = 0; } }, { key: "expect", value: function expect(asserts) { if (arguments.length === 1) { this.test.expected = asserts; } else { return this.test.expected; } } // Create a new async pause and return a new function that can release the pause. }, { key: "async", value: function async(count) { if (count === undefined) { count = 1; } else if (typeof count !== 'number') { throw new TypeError('async takes number as an input'); } var requiredCalls = count; return this.test.internalStop(requiredCalls); } // Exports test.push() to the user API // Alias of pushResult. }, { key: "push", value: function push(result, actual, expected, message, negative) { Logger.warn('assert.push is deprecated and will be removed in QUnit 3.0.' + ' Please use assert.pushResult instead (https://api.qunitjs.com/assert/pushResult).'); var currentAssert = this instanceof Assert ? this : config.current.assert; return currentAssert.pushResult({ result: result, actual: actual, expected: expected, message: message, negative: negative }); } }, { key: "pushResult", value: function pushResult(resultInfo) { // Destructure of resultInfo = { result, actual, expected, message, negative } var assert = this; var currentTest = assert instanceof Assert && assert.test || config.current; // Backwards compatibility fix. // Allows the direct use of global exported assertions and QUnit.assert.* // Although, it's use is not recommended as it can leak assertions // to other tests from async tests, because we only get a reference to the current test, // not exactly the test where assertion were intended to be called. if (!currentTest) { throw new Error('assertion outside test context, in ' + sourceFromStacktrace(2)); } if (!(asse