From 5d0a1401d8c5481280d80b033bb12d26ecbea3ce Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Wed, 11 Feb 2026 14:42:38 -0500 Subject: [PATCH] created new dir for STATICFILES_DIRS in core.settings; all Jasmine test files transferred to new dir src/static_src/; new FT test_jasmine executes Jasmine test runner as part of CI pipeline & base FT has dobules MAX_WAIT to 10s; some cleanup of unused imports in text_simple_list_creation --- .gitignore | 6 +- src/core/settings.py | 3 + src/functional_tests/base.py | 2 +- src/functional_tests/test_jasmine.py | 13 + .../test_simple_list_creation.py | 2 - src/static/tests/lib/jasmine-6.0.1/boot0.js | 68 - src/static/tests/lib/jasmine-6.0.1/boot1.js | 64 - .../tests/lib/jasmine-6.0.1/jasmine-html.js | 1863 --- .../tests/lib/jasmine-6.0.1/jasmine.css | 351 - src/static/tests/lib/jasmine-6.0.1/jasmine.js | 12412 ---------------- src/{static => static_src}/tests/LICENSE | 0 src/{static => static_src}/tests/Spec.js | 0 .../tests/SpecRunner.html | 2 +- 13 files changed, 23 insertions(+), 14763 deletions(-) create mode 100644 src/functional_tests/test_jasmine.py delete mode 100644 src/static/tests/lib/jasmine-6.0.1/boot0.js delete mode 100644 src/static/tests/lib/jasmine-6.0.1/boot1.js delete mode 100644 src/static/tests/lib/jasmine-6.0.1/jasmine-html.js delete mode 100644 src/static/tests/lib/jasmine-6.0.1/jasmine.css delete mode 100644 src/static/tests/lib/jasmine-6.0.1/jasmine.js rename src/{static => static_src}/tests/LICENSE (100%) rename src/{static => static_src}/tests/Spec.js (100%) rename src/{static => static_src}/tests/SpecRunner.html (92%) diff --git a/.gitignore b/.gitignore index 68679e7..92d1679 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ db.sqlite3 db.sqlite3-journal container.db.sqlite3 media -src/static # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ # in your Git repository. Update and uncomment the following line accordingly. @@ -48,6 +47,11 @@ share/python-wheels/ *.egg MANIFEST +# Static files +src/static/* +!src/static/tests/ +!src/static/tests/** + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. diff --git a/src/core/settings.py b/src/core/settings.py index 939f013..031de84 100644 --- a/src/core/settings.py +++ b/src/core/settings.py @@ -140,6 +140,9 @@ USE_TZ = True STATIC_URL = 'static/' STATIC_ROOT = BASE_DIR / 'static' +STATICFILES_DIRS = [ + BASE_DIR / 'static_src', +] LOGGING = { "version": 1, diff --git a/src/functional_tests/base.py b/src/functional_tests/base.py index a39670e..91c7b7e 100644 --- a/src/functional_tests/base.py +++ b/src/functional_tests/base.py @@ -9,7 +9,7 @@ from selenium.webdriver.common.keys import Keys from .container_commands import reset_database -MAX_WAIT = 5 +MAX_WAIT = 10 # Decorator fns diff --git a/src/functional_tests/test_jasmine.py b/src/functional_tests/test_jasmine.py new file mode 100644 index 0000000..946ff51 --- /dev/null +++ b/src/functional_tests/test_jasmine.py @@ -0,0 +1,13 @@ +from selenium.webdriver.common.by import By +from .base import FunctionalTest + + +class JasmineTest(FunctionalTest): + def test_jasmine_specs_pass(self): + self.browser.get(self.live_server_url + "/static/tests/SpecRunner.html") + + def check_results(): + result = self.browser.find_element(By.CSS_SELECTOR, ".jasmine-overall-result") + self.assertIn("0 failures", result.text) + + self.wait_for(check_results) diff --git a/src/functional_tests/test_simple_list_creation.py b/src/functional_tests/test_simple_list_creation.py index 340a7da..e039d7f 100644 --- a/src/functional_tests/test_simple_list_creation.py +++ b/src/functional_tests/test_simple_list_creation.py @@ -3,8 +3,6 @@ from selenium.webdriver.common.keys import Keys from .base import FunctionalTest -MAX_WAIT = 5 - class NewVisitorTest(FunctionalTest): # Test methods def test_can_start_a_todo_list(self): diff --git a/src/static/tests/lib/jasmine-6.0.1/boot0.js b/src/static/tests/lib/jasmine-6.0.1/boot0.js deleted file mode 100644 index 5a97826..0000000 --- a/src/static/tests/lib/jasmine-6.0.1/boot0.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2026 The Jasmine developers - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -'use strict'; - -/** - This file starts the process of "booting" Jasmine. It initializes Jasmine, - makes its globals available, and creates the env. This file should be loaded - after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project - source files or spec files are loaded. - */ -(function() { - const jasmineRequire = window.jasmineRequire || require('./jasmine.js'); - - /** - * ## Require & Instantiate - * - * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. - */ - const jasmine = jasmineRequire.core(jasmineRequire), - global = jasmine.getGlobal(); - global.jasmine = jasmine; - - /** - * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. - */ - jasmineRequire.html(jasmine); - - /** - * Create the Jasmine environment. This is used to run all specs in a project. - */ - const env = jasmine.getEnv(); - - /** - * ## The Global Interface - * - * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. - */ - const jasmineInterface = jasmineRequire.interface(jasmine, env); - - /** - * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. - */ - for (const property in jasmineInterface) { - global[property] = jasmineInterface[property]; - } -})(); diff --git a/src/static/tests/lib/jasmine-6.0.1/boot1.js b/src/static/tests/lib/jasmine-6.0.1/boot1.js deleted file mode 100644 index ebcb5bb..0000000 --- a/src/static/tests/lib/jasmine-6.0.1/boot1.js +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2026 The Jasmine developers - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -'use strict'; - -/** - This file finishes 'booting' Jasmine, performing all of the necessary - initialization before executing the loaded environment and all of a project's - specs. This file should be loaded after `boot0.js` but before any project - source files or spec files are loaded. Thus this file can also be used to - customize Jasmine for a project. - - If a project is using Jasmine via the standalone distribution, this file can - be customized directly. If you only wish to configure the Jasmine env, you - can load another file that calls `jasmine.getEnv().configure({...})` - after `boot0.js` is loaded and before this file is loaded. - */ - -(function() { - const env = jasmine.getEnv(); - const urls = new jasmine.HtmlReporterV2Urls(); - - /** - * Configures Jasmine based on the current set of query parameters. This - * supports all parameters set by the HTML reporter as well as - * spec=partialPath, which filters out specs whose paths don't contain the - * parameter. - */ - env.configure(urls.configFromCurrentUrl()); - - const currentWindowOnload = window.onload; - window.onload = function() { - if (currentWindowOnload) { - currentWindowOnload(); - } - - // The HTML reporter needs to be set up here so it can access the DOM. Other - // reporters can be added at any time before env.execute() is called. - const htmlReporter = new jasmine.HtmlReporterV2({ env, urls }); - env.addReporter(htmlReporter); - env.execute(); - }; -})(); diff --git a/src/static/tests/lib/jasmine-6.0.1/jasmine-html.js b/src/static/tests/lib/jasmine-6.0.1/jasmine-html.js deleted file mode 100644 index c3c92d5..0000000 --- a/src/static/tests/lib/jasmine-6.0.1/jasmine-html.js +++ /dev/null @@ -1,1863 +0,0 @@ -/* -Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2026 The Jasmine developers - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -// eslint-disable-next-line no-var -var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); - -jasmineRequire.html = function(j$) { - j$.private.ResultsNode = jasmineRequire.ResultsNode(); - j$.private.ResultsStateBuilder = jasmineRequire.ResultsStateBuilder(j$); - j$.private.htmlReporterUtils = jasmineRequire.htmlReporterUtils(j$); - j$.private.AlertsView = jasmineRequire.AlertsView(j$); - j$.private.OverallStatusBar = jasmineRequire.OverallStatusBar(j$); - j$.private.Banner = jasmineRequire.Banner(j$); - j$.private.SymbolsView = jasmineRequire.SymbolsView(j$); - j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$); - j$.private.FailuresView = jasmineRequire.FailuresView(j$); - j$.private.PerformanceView = jasmineRequire.PerformanceView(j$); - j$.private.TabBar = jasmineRequire.TabBar(j$); - j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); - j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$); - j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$); - j$.QueryString = jasmineRequire.QueryString(); - j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(j$); - j$.private.HtmlSpecFilterV2 = jasmineRequire.HtmlSpecFilterV2(); -}; - -jasmineRequire.HtmlReporter = function(j$) { - 'use strict'; - - const { createDom, noExpectations } = j$.private.htmlReporterUtils; - - /** - * @class HtmlReporter - * @classdesc Displays results and allows re-running individual specs and suites. - * @implements {Reporter} - * @param options Options object. See lib/jasmine-core/boot1.js for details. - * @since 1.2.0 - * @deprecated Use {@link HtmlReporterV2} instead. - */ - class HtmlReporter { - #env; - #getContainer; - #navigateWithNewParam; - #urlBuilder; - #filterSpecs; - #stateBuilder; - #config; - #htmlReporterMain; - - // Sub-views - #alerts; - #symbols; - #banner; - #failures; - - constructor(options) { - this.#env = options.env; - - this.#getContainer = options.getContainer; - this.#navigateWithNewParam = - options.navigateWithNewParam || function() {}; - this.#urlBuilder = new UrlBuilder( - options.addToExistingQueryString || defaultQueryString - ); - this.#filterSpecs = options.filterSpecs; - } - - /** - * Initializes the reporter. Should be called before {@link Env#execute}. - * @function - * @name HtmlReporter#initialize - */ - initialize() { - this.#env.deprecated( - 'HtmlReporter and HtmlSpecFilter are deprecated. Use HtmlReporterV2 instead.' - ); - this.#clearPrior(); - this.#config = this.#env ? this.#env.configuration() : {}; - - this.#stateBuilder = new j$.private.ResultsStateBuilder(); - - this.#alerts = new j$.private.AlertsView(this.#urlBuilder); - this.#symbols = new j$.private.SymbolsView(); - this.#banner = new j$.private.Banner(this.#navigateWithNewParam); - this.#failures = new j$.private.FailuresView(this.#urlBuilder); - this.#htmlReporterMain = createDom( - 'div', - { className: 'jasmine_html-reporter' }, - this.#banner.rootEl, - this.#symbols.rootEl, - this.#alerts.rootEl, - this.#failures.rootEl - ); - this.#getContainer().appendChild(this.#htmlReporterMain); - } - - jasmineStarted(options) { - this.#stateBuilder.jasmineStarted(options); - } - - suiteStarted(result) { - this.#stateBuilder.suiteStarted(result); - } - - suiteDone(result) { - this.#stateBuilder.suiteDone(result); - - if (result.status === 'failed') { - this.#failures.append(result, this.#stateBuilder.currentParent); - } - } - - specStarted() {} - - specDone(result) { - this.#stateBuilder.specDone(result); - this.#symbols.append(result, this.#config); - - if (noExpectations(result)) { - const noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; - if (result.status === 'failed') { - // eslint-disable-next-line no-console - console.error(noSpecMsg); - } else { - // eslint-disable-next-line no-console - console.warn(noSpecMsg); - } - } - - if (result.status === 'failed') { - this.#failures.append(result, this.#stateBuilder.currentParent); - } - } - - jasmineDone(doneResult) { - this.#stateBuilder.jasmineDone(doneResult); - this.#banner.showOptionsMenu(this.#config); - - if ( - this.#stateBuilder.specsExecuted < this.#stateBuilder.totalSpecsDefined - ) { - this.#alerts.addSkipped( - this.#stateBuilder.specsExecuted, - this.#stateBuilder.totalSpecsDefined - ); - } - - const statusBar = new j$.private.OverallStatusBar(this.#urlBuilder); - statusBar.showDone(doneResult, this.#stateBuilder); - this.#alerts.addBar(statusBar.rootEl); - - if (doneResult.failedExpectations) { - for (const f of doneResult.failedExpectations) { - this.#alerts.addGlobalFailure(f); - } - } - - for (const dw of this.#stateBuilder.deprecationWarnings) { - this.#alerts.addDeprecationWarning(dw); - } - - const results = this.#find('.jasmine-results'); - const summary = new j$.private.SummaryTreeView( - this.#urlBuilder, - this.#filterSpecs - ); - summary.addResults(this.#stateBuilder.topResults); - results.appendChild(summary.rootEl); - - if (this.#stateBuilder.anyNonTopSuiteFailures) { - this.#addFailureToggle(); - this.#setMenuModeTo('jasmine-failure-list'); - this.#failures.show(); - } - } - - #addFailureToggle() { - const onClickFailures = () => this.#setMenuModeTo('jasmine-failure-list'); - const onClickSpecList = () => this.#setMenuModeTo('jasmine-spec-list'); - const failuresLink = createDom( - 'a', - { className: 'jasmine-failures-menu', href: '#' }, - 'Failures' - ); - let specListLink = createDom( - 'a', - { className: 'jasmine-spec-list-menu', href: '#' }, - 'Spec List' - ); - - failuresLink.onclick = function() { - onClickFailures(); - return false; - }; - - specListLink.onclick = function() { - onClickSpecList(); - return false; - }; - - this.#alerts.addBar( - createDom( - 'span', - { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, - [createDom('span', {}, 'Spec List | '), failuresLink] - ) - ); - this.#alerts.addBar( - createDom( - 'span', - { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, - [specListLink, createDom('span', {}, ' | Failures ')] - ) - ); - } - - #find(selector) { - return this.#getContainer().querySelector( - '.jasmine_html-reporter ' + selector - ); - } - - #clearPrior() { - const oldReporter = this.#find(''); - - if (oldReporter) { - this.#getContainer().removeChild(oldReporter); - } - } - - #setMenuModeTo(mode) { - this.#htmlReporterMain.setAttribute( - 'class', - 'jasmine_html-reporter ' + mode - ); - } - } - - class UrlBuilder { - #addToExistingQueryString; - - constructor(addToExistingQueryString) { - this.#addToExistingQueryString = function(k, v) { - // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 - return ( - (window.location.pathname || '') + addToExistingQueryString(k, v) - ); - }; - } - - suiteHref(suite) { - const els = []; - - while (suite && suite.parent) { - els.unshift(suite.result.description); - suite = suite.parent; - } - - return this.#addToExistingQueryString('spec', els.join(' ')); - } - - specHref(result) { - return this.#addToExistingQueryString('spec', result.fullName); - } - - runAllHref() { - return this.#addToExistingQueryString('spec', ''); - } - - seedHref(seed) { - return this.#addToExistingQueryString('seed', seed); - } - } - - function defaultQueryString(key, value) { - return '?' + key + '=' + value; - } - - return HtmlReporter; -}; - -jasmineRequire.HtmlSpecFilter = function(j$) { - 'use strict'; - - /** - * @class HtmlSpecFilter - * @param options Options object. See lib/jasmine-core/boot1.js for details. - * @deprecated Use {@link HtmlReporterV2Urls} instead. - */ - function HtmlSpecFilter(options) { - const env = options?.env ?? j$.getEnv(); - env.deprecated( - 'HtmlReporter and HtmlSpecFilter are deprecated. Use HtmlReporterV2 instead.' - ); - - const filterString = - options && - options.filterString && - options.filterString() && - options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); - const filterPattern = new RegExp(filterString); - - /** - * Determines whether the spec with the specified name should be executed. - * @name HtmlSpecFilter#matches - * @function - * @param {string} specName The full name of the spec - * @returns {boolean} - */ - this.matches = function(specName) { - return filterPattern.test(specName); - }; - } - - return HtmlSpecFilter; -}; - -jasmineRequire.ResultsNode = function() { - 'use strict'; - - function ResultsNode(result, type, parent) { - this.result = result; - this.type = type; - this.parent = parent; - - this.children = []; - - this.addChild = function(result, type) { - this.children.push(new ResultsNode(result, type, this)); - }; - - this.last = function() { - return this.children[this.children.length - 1]; - }; - - this.updateResult = function(result) { - this.result = result; - }; - } - - return ResultsNode; -}; - -jasmineRequire.QueryString = function() { - 'use strict'; - - /** - * Reads and manipulates the query string. - * @since 2.0.0 - */ - class QueryString { - #getWindowLocation; - - /** - * @param options Object with a getWindowLocation property, which should be - * a function returning the current value of window.location. - */ - constructor(options) { - this.#getWindowLocation = options.getWindowLocation; - } - - /** - * Sets the specified query parameter and navigates to the resulting URL. - * @param {string} key - * @param {string} value - */ - navigateWithNewParam(key, value) { - this.#getWindowLocation().search = this.fullStringWithNewParam( - key, - value - ); - } - - /** - * Returns a new URL based on the current location, with the specified - * query parameter set. - * @param {string} key - * @param {string} value - * @return {string} - */ - fullStringWithNewParam(key, value) { - const paramMap = this.#queryStringToParamMap(); - paramMap[key] = value; - return toQueryString(paramMap); - } - - /** - * Gets the value of the specified query parameter. - * @param {string} key - * @return {string} - */ - getParam(key) { - return this.#queryStringToParamMap()[key]; - } - - #queryStringToParamMap() { - const paramStr = this.#getWindowLocation().search.substring(1); - let params = []; - const paramMap = {}; - - if (paramStr.length > 0) { - params = paramStr.split('&'); - for (let i = 0; i < params.length; i++) { - const p = params[i].split('='); - let value = decodeURIComponent(p[1]); - if (value === 'true' || value === 'false') { - value = JSON.parse(value); - } - paramMap[decodeURIComponent(p[0])] = value; - } - } - - return paramMap; - } - } - - function toQueryString(paramMap) { - const qStrPairs = []; - for (const prop in paramMap) { - qStrPairs.push( - encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]) - ); - } - return '?' + qStrPairs.join('&'); - } - - return QueryString; -}; - -jasmineRequire.AlertsView = function(j$) { - 'use strict'; - - const { createDom } = j$.private.htmlReporterUtils; - const errorBarClassName = 'jasmine-bar jasmine-errored'; - const afterAllMessagePrefix = 'AfterAll '; - - class AlertsView { - #urlBuilder; - - constructor(urlBuilder) { - this.#urlBuilder = urlBuilder; - this.rootEl = createDom('div', { className: 'jasmine-alert' }); - } - - addSkipped(numExecuted, numDefined) { - this.#createAndAdd( - 'jasmine-bar jasmine-skipped', - createDom( - 'a', - { href: this.#urlBuilder.runAllHref(), title: 'Run all specs' }, - `Ran ${numExecuted} of ${numDefined} specs - run all` - ) - ); - } - - addGlobalFailure(failure) { - this.#createAndAdd( - errorBarClassName, - this.#globalFailureMessage(failure) - ); - } - - #globalFailureMessage(failure) { - if (failure.globalErrorType === 'load') { - const prefix = 'Error during loading: ' + failure.message; - - if (failure.filename) { - return prefix + ' in ' + failure.filename + ' line ' + failure.lineno; - } else { - return prefix; - } - } else if (failure.globalErrorType === 'afterAll') { - return afterAllMessagePrefix + failure.message; - } else { - return failure.message; - } - } - - addDeprecationWarning(dw) { - const children = []; - let context; - - switch (dw.runnableType) { - case 'spec': - context = '(in spec: ' + dw.runnableName + ')'; - break; - case 'suite': - context = '(in suite: ' + dw.runnableName + ')'; - break; - default: - context = ''; - } - - for (const line of dw.message.split('\n')) { - children.push(line); - children.push(createDom('br')); - } - - children[0] = 'DEPRECATION: ' + children[0]; - children.push(context); - - if (dw.stack) { - children.push(this.#createExpander(dw.stack)); - } - - this.#createAndAdd('jasmine-bar jasmine-warning', children); - } - - addBar(el) { - this.rootEl.appendChild(el); - } - - #createAndAdd(className, children) { - this.rootEl.appendChild(createDom('span', { className }, children)); - } - - #createExpander(stackTrace) { - const expandLink = createDom('a', { href: '#' }, 'Show stack trace'); - const root = createDom( - 'div', - { className: 'jasmine-expander' }, - expandLink, - createDom( - 'div', - { className: 'jasmine-expander-contents jasmine-stack-trace' }, - stackTrace - ) - ); - - expandLink.addEventListener('click', function(e) { - e.preventDefault(); - - if (root.classList.contains('jasmine-expanded')) { - root.classList.remove('jasmine-expanded'); - expandLink.textContent = 'Show stack trace'; - } else { - root.classList.add('jasmine-expanded'); - expandLink.textContent = 'Hide stack trace'; - } - }); - - return root; - } - } - - return AlertsView; -}; - -jasmineRequire.Banner = function(j$) { - 'use strict'; - - const { createDom } = j$.private.htmlReporterUtils; - - class Banner { - #navigateWithNewParam; - #omitHideDisabled; - - constructor(navigateWithNewParam, omitHideDisabled) { - this.#navigateWithNewParam = navigateWithNewParam; - this.#omitHideDisabled = omitHideDisabled; - this.rootEl = createDom( - 'div', - { className: 'jasmine-banner' }, - createDom('a', { - className: 'jasmine-title', - href: 'http://jasmine.github.io/', - target: '_blank' - }), - createDom('span', { className: 'jasmine-version' }, j$.version) - ); - } - - showOptionsMenu(config) { - this.rootEl.appendChild(this.#optionsMenu(config)); - } - - #optionsMenu(config) { - const items = [ - createDom( - 'div', - { className: 'jasmine-stop-on-failure' }, - createDom('input', { - className: 'jasmine-fail-fast', - id: 'jasmine-fail-fast', - type: 'checkbox' - }), - createDom( - 'label', - { className: 'jasmine-label', for: 'jasmine-fail-fast' }, - 'stop execution on spec failure' - ) - ), - createDom( - 'div', - { className: 'jasmine-throw-failures' }, - createDom('input', { - className: 'jasmine-throw', - id: 'jasmine-throw-failures', - type: 'checkbox' - }), - createDom( - 'label', - { className: 'jasmine-label', for: 'jasmine-throw-failures' }, - 'stop spec on expectation failure' - ) - ), - createDom( - 'div', - { className: 'jasmine-random-order' }, - createDom('input', { - className: 'jasmine-random', - id: 'jasmine-random-order', - type: 'checkbox' - }), - createDom( - 'label', - { className: 'jasmine-label', for: 'jasmine-random-order' }, - 'run tests in random order' - ) - ) - ]; - - if (!this.#omitHideDisabled) { - items.push( - createDom( - 'div', - { className: 'jasmine-hide-disabled' }, - createDom('input', { - className: 'jasmine-disabled', - id: 'jasmine-hide-disabled', - type: 'checkbox' - }), - createDom( - 'label', - { className: 'jasmine-label', for: 'jasmine-hide-disabled' }, - 'hide disabled tests' - ) - ) - ); - } - - const optionsMenuDom = createDom( - 'div', - { className: 'jasmine-run-options' }, - createDom('span', { className: 'jasmine-trigger' }, 'Options'), - createDom('div', { className: 'jasmine-payload' }, items) - ); - - const failFastCheckbox = optionsMenuDom.querySelector( - '#jasmine-fail-fast' - ); - failFastCheckbox.checked = config.stopOnSpecFailure; - failFastCheckbox.onclick = () => { - this.#navigateWithNewParam( - 'stopOnSpecFailure', - !config.stopOnSpecFailure - ); - }; - - const throwCheckbox = optionsMenuDom.querySelector( - '#jasmine-throw-failures' - ); - throwCheckbox.checked = config.stopSpecOnExpectationFailure; - throwCheckbox.onclick = () => { - this.#navigateWithNewParam( - 'stopSpecOnExpectationFailure', - !config.stopSpecOnExpectationFailure - ); - }; - - const randomCheckbox = optionsMenuDom.querySelector( - '#jasmine-random-order' - ); - randomCheckbox.checked = config.random; - randomCheckbox.onclick = () => { - this.#navigateWithNewParam('random', !config.random); - }; - - if (!this.#omitHideDisabled) { - const hideDisabled = optionsMenuDom.querySelector( - '#jasmine-hide-disabled' - ); - hideDisabled.checked = config.hideDisabled; - hideDisabled.onclick = () => { - this.#navigateWithNewParam('hideDisabled', !config.hideDisabled); - }; - } - - const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), - optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), - isOpen = /\bjasmine-open\b/; - - optionsTrigger.onclick = function() { - if (isOpen.test(optionsPayload.className)) { - optionsPayload.className = optionsPayload.className.replace( - isOpen, - '' - ); - } else { - optionsPayload.className += ' jasmine-open'; - } - }; - - return optionsMenuDom; - } - } - - return Banner; -}; - -jasmineRequire.FailuresView = function(j$) { - 'use strict'; - - const { createDom } = j$.private.htmlReporterUtils; - - class FailuresView { - #urlBuilder; - #failureEls; - #showing; - - constructor(urlBuilder) { - this.#urlBuilder = urlBuilder; - this.#failureEls = []; - this.#showing = false; - this.rootEl = createDom( - 'div', - { className: 'jasmine-results' }, - createDom('div', { className: 'jasmine-failures' }) - ); - } - - append(result, parent) { - // TODO: Figure out why the result is wrong if we build the DOM node later - const el = this.#makeFailureEl(result, parent); - - if (this.#showing) { - this.rootEl.querySelector('.jasmine-failures').appendChild(el); - } else { - this.#failureEls.push(el); - } - } - - show() { - const failureNode = this.rootEl.querySelector('.jasmine-failures'); - - for (const el of this.#failureEls) { - failureNode.appendChild(el); - } - - this.#showing = true; - } - - #makeFailureEl(result, parent) { - const failure = createDom( - 'div', - { className: 'jasmine-spec-detail jasmine-failed' }, - this.#failureDescription(result, parent), - createDom('div', { className: 'jasmine-messages' }) - ); - const messages = failure.childNodes[1]; - - for (let i = 0; i < result.failedExpectations.length; i++) { - const expectation = result.failedExpectations[i]; - messages.appendChild( - createDom( - 'div', - { className: 'jasmine-result-message' }, - expectation.message - ) - ); - messages.appendChild( - createDom( - 'div', - { className: 'jasmine-stack-trace' }, - expectation.stack - ) - ); - } - - if (result.failedExpectations.length === 0) { - messages.appendChild( - createDom( - 'div', - { className: 'jasmine-result-message' }, - 'Spec has no expectations' - ) - ); - } - - if (result.debugLogs) { - messages.appendChild(this.#debugLogTable(result.debugLogs)); - } - - return failure; - } - - #failureDescription(result, suite) { - const wrapper = createDom( - 'div', - { className: 'jasmine-description' }, - createDom( - 'a', - { - title: result.description, - href: this.#urlBuilder.specHref(result) - }, - result.description - ) - ); - let suiteLink; - - while (suite && suite.parent) { - wrapper.insertBefore( - document.createTextNode(' > '), - wrapper.firstChild - ); - suiteLink = createDom( - 'a', - { href: this.#urlBuilder.suiteHref(suite) }, - suite.result.description - ); - wrapper.insertBefore(suiteLink, wrapper.firstChild); - - suite = suite.parent; - } - - return wrapper; - } - - #debugLogTable(debugLogs) { - const tbody = createDom('tbody'); - - for (const entry of debugLogs) { - tbody.appendChild( - createDom( - 'tr', - {}, - createDom('td', {}, entry.timestamp.toString()), - createDom( - 'td', - { className: 'jasmine-debug-log-msg' }, - entry.message - ) - ) - ); - } - - return createDom( - 'div', - { className: 'jasmine-debug-log' }, - createDom( - 'div', - { className: 'jasmine-debug-log-header' }, - 'Debug logs' - ), - createDom( - 'table', - {}, - createDom( - 'thead', - {}, - createDom( - 'tr', - {}, - createDom('th', {}, 'Time (ms)'), - createDom('th', {}, 'Message') - ) - ), - tbody - ) - ); - } - } - - return FailuresView; -}; - -jasmineRequire.htmlReporterUtils = function(j$) { - 'use strict'; - - function createDom(type, attrs, childrenArrayOrVarArgs) { - const el = document.createElement(type); - let children; - - if (Array.isArray(childrenArrayOrVarArgs)) { - children = childrenArrayOrVarArgs; - } else { - children = []; - - for (let i = 2; i < arguments.length; i++) { - children.push(arguments[i]); - } - } - - for (let i = 0; i < children.length; i++) { - const child = children[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { - el.appendChild(child); - } - } - } - - for (const attr in attrs) { - if (attr === 'className') { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; - } - - function noExpectations(result) { - const allExpectations = - result.failedExpectations.length + result.passedExpectations.length; - - return ( - allExpectations === 0 && - (result.status === 'passed' || result.status === 'failed') - ); - } - - return { createDom, noExpectations }; -}; - -jasmineRequire.HtmlReporterV2 = function(j$) { - 'use strict'; - - const { createDom, noExpectations } = j$.private.htmlReporterUtils; - - const specListTabId = 'jasmine-specListTab'; - const failuresTabId = 'jasmine-failuresTab'; - const perfTabId = 'jasmine-perfTab'; - - /** - * @class HtmlReporterV2 - * @classdesc Displays results and allows re-running individual specs and suites. - * @implements {Reporter} - * @param options Options object - * @since 6.0.0 - * @example - * const env = jasmine.getEnv(); - * const urls = new jasmine.HtmlReporterV2Urls(); - * const reporter = new jasmine.HtmlReporterV2({ - * env, - * urls, - * // container is optional and defaults to document.body. - * container: someElement - * }); - */ - class HtmlReporterV2 { - #container; - #queryString; - #urlBuilder; - #filterSpecs; - #stateBuilder; - #config; - #htmlReporterMain; - - // Sub-views - #alerts; - #statusBar; - #tabBar; - #progress; - #banner; - #failures; - - constructor(options) { - this.#container = options.container || document.body; - this.#queryString = - options.queryString || - new j$.QueryString({ - getWindowLocation() { - return window.location; - } - }); - this.#urlBuilder = new UrlBuilder({ - queryString: this.#queryString, - getSuiteById: id => this.#stateBuilder.suitesById[id] - }); - this.#filterSpecs = options.urls.filteringSpecs(); - - this.#config = options.env ? options.env.configuration() : {}; - - this.#stateBuilder = new j$.private.ResultsStateBuilder(); - - this.#alerts = new j$.private.AlertsView(this.#urlBuilder); - this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder); - this.#statusBar.showRunning(); - this.#alerts.addBar(this.#statusBar.rootEl); - - this.#tabBar = new j$.private.TabBar( - [ - { id: specListTabId, label: 'Spec List' }, - { id: failuresTabId, label: 'Failures' }, - { id: perfTabId, label: 'Performance' } - ], - tabId => { - if (tabId === specListTabId) { - this.#setMenuModeTo('jasmine-spec-list'); - } else if (tabId === failuresTabId) { - this.#setMenuModeTo('jasmine-failure-list'); - } else { - this.#setMenuModeTo('jasmine-performance'); - } - } - ); - this.#alerts.addBar(this.#tabBar.rootEl); - - this.#progress = new ProgressView(); - this.#banner = new j$.private.Banner( - this.#queryString.navigateWithNewParam.bind(this.#queryString), - true - ); - this.#failures = new j$.private.FailuresView(this.#urlBuilder); - this.#htmlReporterMain = createDom( - 'div', - { className: 'jasmine_html-reporter' }, - this.#banner.rootEl, - this.#progress.rootEl, - this.#alerts.rootEl, - this.#failures.rootEl - ); - this.#container.appendChild(this.#htmlReporterMain); - this.#failures.show(); - } - - jasmineStarted(options) { - this.#stateBuilder.jasmineStarted(options); - this.#progress.start( - options.totalSpecsDefined - options.numExcludedSpecs - ); - } - - suiteStarted(result) { - this.#stateBuilder.suiteStarted(result); - } - - suiteDone(result) { - this.#stateBuilder.suiteDone(result); - - if (result.status === 'failed') { - this.#failures.append(result, this.#stateBuilder.currentParent); - this.#statusBar.showFailing(); - } - } - - specDone(result) { - this.#stateBuilder.specDone(result); - this.#progress.specDone(result, this.#config); - - if (noExpectations(result)) { - const noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; - if (result.status === 'failed') { - // eslint-disable-next-line no-console - console.error(noSpecMsg); - } else { - // eslint-disable-next-line no-console - console.warn(noSpecMsg); - } - } - - if (result.status === 'failed') { - this.#failures.append(result, this.#stateBuilder.currentParent); - this.#statusBar.showFailing(); - } - } - - jasmineDone(doneResult) { - this.#stateBuilder.jasmineDone(doneResult); - this.#progress.rootEl.style.visibility = 'hidden'; - this.#banner.showOptionsMenu(this.#config); - - if ( - this.#stateBuilder.specsExecuted < this.#stateBuilder.totalSpecsDefined - ) { - this.#alerts.addSkipped( - this.#stateBuilder.specsExecuted, - this.#stateBuilder.totalSpecsDefined - ); - } - - this.#statusBar.showDone(doneResult, this.#stateBuilder); - - if (doneResult.failedExpectations) { - for (const f of doneResult.failedExpectations) { - this.#alerts.addGlobalFailure(f); - } - } - - for (const dw of this.#stateBuilder.deprecationWarnings) { - this.#alerts.addDeprecationWarning(dw); - } - - const results = this.#find('.jasmine-results'); - const summary = new j$.private.SummaryTreeView( - this.#urlBuilder, - this.#filterSpecs - ); - summary.addResults(this.#stateBuilder.topResults); - results.appendChild(summary.rootEl); - const perf = new j$.private.PerformanceView(); - perf.addResults(this.#stateBuilder.topResults); - results.appendChild(perf.rootEl); - this.#tabBar.showTab(specListTabId); - this.#tabBar.showTab(perfTabId); - - if (this.#stateBuilder.anyNonTopSuiteFailures) { - this.#tabBar.showTab(failuresTabId); - this.#tabBar.selectTab(failuresTabId); - } else { - this.#tabBar.selectTab(specListTabId); - } - } - - #find(selector) { - return this.#container.querySelector( - '.jasmine_html-reporter ' + selector - ); - } - - #setMenuModeTo(mode) { - this.#htmlReporterMain.setAttribute( - 'class', - 'jasmine_html-reporter ' + mode - ); - } - } - - class ProgressView { - constructor() { - this.rootEl = createDom('progress', { value: 0 }); - } - - start(totalSpecsDefined) { - this.rootEl.max = totalSpecsDefined; - } - - specDone(result) { - if (result.status !== 'excluded') { - this.rootEl.value = this.rootEl.value + 1; - } - - if (result.status === 'failed') { - this.rootEl.classList.add('failed'); - } - } - } - - class UrlBuilder { - #queryString; - #getSuiteById; - - constructor(options) { - this.#queryString = options.queryString; - this.#getSuiteById = options.getSuiteById; - } - - suiteHref(suite) { - const path = this.#suitePath(suite); - return this.#specPathHref(path); - } - - specHref(specResult) { - const suite = this.#getSuiteById(specResult.parentSuiteId); - const path = this.#suitePath(suite); - path.push(specResult.description); - return this.#specPathHref(path); - } - - runAllHref() { - return this.#addToExistingQueryString('path', ''); - } - - seedHref(seed) { - return this.#addToExistingQueryString('seed', seed); - } - - #suitePath(suite) { - const path = []; - - while (suite && suite.parent) { - path.unshift(suite.result.description); - suite = suite.parent; - } - - return path; - } - - #specPathHref(specPath) { - return this.#addToExistingQueryString('path', JSON.stringify(specPath)); - } - - #addToExistingQueryString(k, v) { - // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 - return ( - (window.location.pathname || '') + - this.#queryString.fullStringWithNewParam(k, v) - ); - } - } - - return HtmlReporterV2; -}; - -jasmineRequire.HtmlReporterV2Urls = function(j$) { - 'use strict'; - - // TODO unify with V2 UrlBuilder? - /** - * @class HtmlReporterV2Urls - * @classdesc Processes URLs for {@link HtmlReporterV2}. - * @since 6.0.0 - */ - class HtmlReporterV2Urls { - constructor(options = {}) { - // queryString is injectable for use in our own tests, but user code will - // not pass any options. - this.queryString = - options.queryString || - new jasmine.QueryString({ - getWindowLocation: function() { - return window.location; - } - }); - } - - /** - * Creates a {@link Configuration} from the current page's URL. Supported - * query string parameters include all those set by {@link HtmlReporterV2} - * as well as spec=partialPath, which filters out specs whose paths don't - * contain partialPath. - * @returns {Configuration} - * @example - * const urls = new jasmine.HtmlReporterV2Urls(); - * env.configure(urls.configFromCurrentUrl()); - */ - configFromCurrentUrl() { - const config = { - stopOnSpecFailure: this.queryString.getParam('stopOnSpecFailure'), - stopSpecOnExpectationFailure: this.queryString.getParam( - 'stopSpecOnExpectationFailure' - ) - }; - - const random = this.queryString.getParam('random'); - - if (random !== undefined && random !== '') { - config.random = random; - } - - const seed = this.queryString.getParam('seed'); - if (seed) { - config.seed = seed; - } - - const specFilter = new j$.private.HtmlSpecFilterV2({ - filterParams: () => ({ - path: this.queryString.getParam('path'), - spec: this.queryString.getParam('spec') - }) - }); - - config.specFilter = function(spec) { - return specFilter.matches(spec); - }; - - return config; - } - - filteringSpecs() { - return !!this.queryString.getParam('path'); - } - } - - return HtmlReporterV2Urls; -}; - -jasmineRequire.HtmlSpecFilterV2 = function() { - class HtmlSpecFilterV2 { - #getFilterParams; - - constructor(options) { - this.#getFilterParams = options.filterParams; - } - - matches(spec) { - const params = this.#getFilterParams(); - - if (params.path) { - return this.#matchesPath(spec, JSON.parse(params.path)); - } else if (params.spec) { - // Like legacy HtmlSpecFilter, retained because it's convenient for - // hand-constructing filter URLs - return spec.getFullName().includes(params.spec); - } - - return true; - } - - #matchesPath(spec, path) { - const specPath = spec.getPath(); - - if (path.length > specPath.length) { - return false; - } - - for (let i = 0; i < path.length; i++) { - if (specPath[i] !== path[i]) { - return false; - } - } - - return true; - } - } - - return HtmlSpecFilterV2; -}; - -jasmineRequire.OverallStatusBar = function(j$) { - 'use strict'; - - const { createDom } = j$.private.htmlReporterUtils; - const staticClassNames = 'jasmine-overall-result jasmine-bar'; - - class OverallStatusBar { - #urlBuilder; - - constructor(urlBuilder) { - this.#urlBuilder = urlBuilder; - this.rootEl = createDom('span', { - className: staticClassNames, - 'aria-live': 'polite' - }); - } - - showRunning() { - this.rootEl.textContent = 'Running...'; - this.rootEl.classList.add('jasmine-in-progress'); - } - - showFailing() { - this.rootEl.textContent = 'Failing...'; - this.rootEl.classList.add('jasmine-failed'); - } - - showDone(doneResult, stateBuilder) { - // Clear any classes added to represent in-progress state - this.rootEl.className = staticClassNames; - - let statusBarMessage = ''; - const globalFailures = - (doneResult && doneResult.failedExpectations) || []; - const failed = stateBuilder.failureCount + globalFailures.length > 0; - - if (stateBuilder.totalSpecsDefined > 0 || failed) { - statusBarMessage += - pluralize('spec', stateBuilder.specsExecuted) + - ', ' + - pluralize('failure', stateBuilder.failureCount); - if (stateBuilder.pendingSpecCount) { - statusBarMessage += - ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); - } - } - - if (doneResult.overallStatus === 'passed') { - this.rootEl.classList.add('jasmine-passed'); - } else if (doneResult.overallStatus === 'incomplete') { - this.rootEl.classList.add('jasmine-incomplete'); - statusBarMessage = - 'Incomplete: ' + - doneResult.incompleteReason + - ', ' + - statusBarMessage; - } else { - this.rootEl.classList.add('jasmine-failed'); - } - - // Replace any existing children with the message - this.rootEl.textContent = statusBarMessage; - - const order = doneResult.order; - if (order && order.random) { - this.#addSeedBar(order); - } - - this.#addDuration(doneResult); - } - - #addSeedBar(order) { - this.rootEl.appendChild( - createDom( - 'span', - { className: 'jasmine-seed-bar' }, - ', randomized with seed ', - createDom( - 'a', - { - title: 'randomized with seed ' + order.seed, - href: this.#urlBuilder.seedHref(order.seed) - }, - order.seed - ) - ) - ); - } - - #addDuration(doneResult) { - const secs = doneResult.totalTime / 1000; - this.rootEl.appendChild( - createDom( - 'span', - { className: 'jasmine-duration' }, - `finished in ${secs}s` - ) - ); - } - } - - function pluralize(singular, count) { - const word = count === 1 ? singular : singular + 's'; - return '' + count + ' ' + word; - } - - return OverallStatusBar; -}; - -jasmineRequire.PerformanceView = function(j$) { - const createDom = j$.private.htmlReporterUtils.createDom; - const MAX_SLOW_SPECS = 20; - - class PerformanceView { - #summary; - #tbody; - - constructor() { - this.#tbody = document.createElement('tbody'); - this.#summary = document.createElement('div'); - this.rootEl = createDom( - 'div', - { className: 'jasmine-performance-view' }, - createDom('h2', {}, 'Performance'), - this.#summary, - createDom('h3', {}, 'Slowest Specs'), - createDom( - 'table', - {}, - createDom( - 'thead', - {}, - createDom( - 'tr', - {}, - createDom('th', {}, 'Duration'), - createDom('th', {}, 'Spec Name') - ) - ), - this.#tbody - ) - ); - } - - addResults(resultsTree) { - const specResults = []; - getSpecResults(resultsTree, specResults); - - if (specResults.length === 0) { - return; - } - - specResults.sort(function(a, b) { - if (a.duration < b.duration) { - return 1; - } else if (a.duration > b.duration) { - return -1; - } else { - return 0; - } - }); - - this.#populateSumary(specResults); - this.#populateTable(specResults); - } - - #populateSumary(specResults) { - const total = specResults.map(r => r.duration).reduce((a, b) => a + b, 0); - const mean = total / specResults.length; - const median = specResults[Math.floor(specResults.length / 2)].duration; - this.#summary.appendChild( - document.createTextNode(`Mean spec run time: ${mean.toFixed(0)}ms`) - ); - this.#summary.appendChild(document.createElement('br')); - this.#summary.appendChild( - document.createTextNode(`Median spec run time: ${median}ms`) - ); - } - - #populateTable(specResults) { - specResults = specResults.slice(0, MAX_SLOW_SPECS); - - for (const r of specResults) { - this.#tbody.appendChild( - createDom( - 'tr', - {}, - createDom('td', {}, `${r.duration}ms`), - createDom('td', {}, r.fullName) - ) - ); - } - } - } - - function getSpecResults(resultsTree, dest) { - for (const node of resultsTree.children) { - if (node.type === 'suite') { - getSpecResults(node, dest); - } else if (node.result.status !== 'excluded') { - dest.push(node.result); - } - } - } - - return PerformanceView; -}; - -jasmineRequire.ResultsStateBuilder = function(j$) { - 'use strict'; - - class ResultsStateBuilder { - constructor() { - this.topResults = new j$.private.ResultsNode({}, '', null); - this.currentParent = this.topResults; - this.suitesById = {}; - this.totalSpecsDefined = 0; - this.specsExecuted = 0; - this.failureCount = 0; - this.anyNonTopSuiteFailures = false; - this.pendingSpecCount = 0; - this.deprecationWarnings = []; - } - - suiteStarted(result) { - this.currentParent.addChild(result, 'suite'); - this.currentParent = this.currentParent.last(); - this.suitesById[result.id] = this.currentParent; - } - - suiteDone(result) { - this.currentParent.updateResult(result); - this.#addDeprecationWarnings(result, 'suite'); - - if (this.currentParent !== this.topResults) { - this.currentParent = this.currentParent.parent; - } - - if (result.status === 'failed') { - this.failureCount++; - this.anyNonTopSuiteFailures = true; - } - } - - specDone(result) { - this.currentParent.addChild(result, 'spec'); - this.#addDeprecationWarnings(result, 'spec'); - - if (result.status !== 'excluded') { - this.specsExecuted++; - } - - if (result.status === 'failed') { - this.failureCount++; - this.anyNonTopSuiteFailures = true; - } - - if (result.status == 'pending') { - this.pendingSpecCount++; - } - } - - jasmineStarted(result) { - this.totalSpecsDefined = result.totalSpecsDefined; - } - - jasmineDone(result) { - if (result.failedExpectations) { - this.failureCount += result.failedExpectations.length; - } - - this.#addDeprecationWarnings(result); - } - - #addDeprecationWarnings(result, runnableType) { - if (result.deprecationWarnings) { - for (const dw of result.deprecationWarnings) { - this.deprecationWarnings.push({ - message: dw.message, - stack: dw.stack, - runnableName: result.fullName, - runnableType: runnableType - }); - } - } - } - } - - return ResultsStateBuilder; -}; - -jasmineRequire.SummaryTreeView = function(j$) { - 'use strict'; - - const { createDom, noExpectations } = j$.private.htmlReporterUtils; - - class SummaryTreeView { - #urlBuilder; - #filterSpecs; - - constructor(urlBuilder, filterSpecs) { - this.#urlBuilder = urlBuilder; - this.#filterSpecs = filterSpecs; - this.rootEl = createDom('div', { - className: 'jasmine-summary' - }); - } - - addResults(resultsTree) { - this.#addResults(resultsTree, this.rootEl); - } - - #addResults(resultsTree, domParent) { - let specListNode; - for (let i = 0; i < resultsTree.children.length; i++) { - const resultNode = resultsTree.children[i]; - if (this.#filterSpecs && !hasActiveSpec(resultNode)) { - continue; - } - if (resultNode.type === 'suite') { - const suiteListNode = createDom( - 'ul', - { className: 'jasmine-suite', id: 'suite-' + resultNode.result.id }, - createDom( - 'li', - { - className: - 'jasmine-suite-detail jasmine-' + resultNode.result.status - }, - createDom( - 'a', - { href: this.#urlBuilder.specHref(resultNode.result) }, - resultNode.result.description - ) - ) - ); - - this.#addResults(resultNode, suiteListNode); - domParent.appendChild(suiteListNode); - } - if (resultNode.type === 'spec') { - if (domParent.getAttribute('class') !== 'jasmine-specs') { - specListNode = createDom('ul', { - className: 'jasmine-specs' - }); - domParent.appendChild(specListNode); - } - let specDescription = resultNode.result.description; - if (noExpectations(resultNode.result)) { - specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; - } - if (resultNode.result.status === 'pending') { - if (resultNode.result.pendingReason !== '') { - specDescription += - ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason; - } else { - specDescription += ' PENDING'; - } - } - specListNode.appendChild( - createDom( - 'li', - { - className: 'jasmine-' + resultNode.result.status, - id: 'spec-' + resultNode.result.id - }, - createDom( - 'a', - { href: this.#urlBuilder.specHref(resultNode.result) }, - specDescription - ), - createDom( - 'span', - { className: 'jasmine-spec-duration' }, - '(' + resultNode.result.duration + 'ms)' - ) - ) - ); - } - } - } - } - - function hasActiveSpec(resultNode) { - if (resultNode.type === 'spec' && resultNode.result.status !== 'excluded') { - return true; - } - - if (resultNode.type === 'suite') { - for (let i = 0, j = resultNode.children.length; i < j; i++) { - if (hasActiveSpec(resultNode.children[i])) { - return true; - } - } - } - } - - return SummaryTreeView; -}; - -jasmineRequire.SymbolsView = function(j$) { - 'use strict'; - - const { createDom, noExpectations } = j$.private.htmlReporterUtils; - - class SymbolsView { - constructor() { - this.rootEl = createDom('ul', { - className: 'jasmine-symbol-summary' - }); - } - - append(result, config) { - this.rootEl.appendChild( - createDom('li', { - className: this.#className(result, config), - id: 'spec_' + result.id, - title: result.fullName - }) - ); - } - - #className(result, config) { - if (noExpectations(result) && result.status === 'passed') { - return 'jasmine-empty'; - } else if (result.status === 'excluded') { - if (config.hideDisabled) { - return 'jasmine-excluded-no-display'; - } else { - return 'jasmine-excluded'; - } - } else { - return 'jasmine-' + result.status; - } - } - } - - return SymbolsView; -}; - -jasmineRequire.TabBar = function(j$) { - const createDom = j$.private.htmlReporterUtils.createDom; - - class TabBar { - #tabs; - #onSelectTab; - - // tabSpecs should be an array of {id, label}. - // All tabs are initially not visible and not selected. - constructor(tabSpecs, onSelectTab) { - this.#onSelectTab = onSelectTab; - this.#tabs = []; - this.#tabs = tabSpecs.map(ts => new Tab(ts, () => this.selectTab(ts.id))); - - this.rootEl = createDom( - 'span', - { className: 'jasmine-menu jasmine-bar' }, - this.#tabs.map(t => t.rootEl) - ); - } - - showTab(id) { - for (const tab of this.#tabs) { - if (tab.rootEl.id === id) { - tab.setVisibility(true); - } - } - } - - selectTab(id) { - for (const tab of this.#tabs) { - tab.setSelected(tab.rootEl.id === id); - } - - this.#onSelectTab(id); - } - } - - class Tab { - #spec; - #onClick; - - constructor(spec, onClick) { - this.#spec = spec; - this.#onClick = onClick; - this.rootEl = createDom( - 'span', - { id: spec.id, className: 'jasmine-tab jasmine-hidden' }, - this.#createLink() - ); - } - - setVisibility(visible) { - this.rootEl.classList.toggle('jasmine-hidden', !visible); - } - - setSelected(selected) { - if (selected) { - this.rootEl.textContent = this.#spec.label; - } else { - this.rootEl.textContent = ''; - this.rootEl.appendChild(this.#createLink()); - } - } - - #createLink() { - const link = createDom('a', { href: '#' }, this.#spec.label); - link.addEventListener('click', e => { - e.preventDefault(); - this.#onClick(); - }); - return link; - } - } - - return TabBar; -}; diff --git a/src/static/tests/lib/jasmine-6.0.1/jasmine.css b/src/static/tests/lib/jasmine-6.0.1/jasmine.css deleted file mode 100644 index 3be6101..0000000 --- a/src/static/tests/lib/jasmine-6.0.1/jasmine.css +++ /dev/null @@ -1,351 +0,0 @@ -@charset "UTF-8"; -body { - overflow-y: scroll; -} - -.jasmine_html-reporter { - width: 100%; - background-color: #eee; - padding: 5px; - margin: -8px; - font-size: 12px; - font-family: Monaco, "Lucida Console", monospace; - line-height: 14px; - color: #333; -} -.jasmine_html-reporter a { - text-decoration: none; -} -.jasmine_html-reporter a:hover { - text-decoration: underline; -} -.jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { - margin: 0; - line-height: 14px; -} -.jasmine_html-reporter .jasmine-banner, -.jasmine_html-reporter .jasmine-symbol-summary, -.jasmine_html-reporter .jasmine-summary, -.jasmine_html-reporter .jasmine-result-message, -.jasmine_html-reporter .jasmine-spec .jasmine-description, -.jasmine_html-reporter .jasmine-spec-detail .jasmine-description, -.jasmine_html-reporter .jasmine-alert .jasmine-bar, -.jasmine_html-reporter .jasmine-stack-trace { - padding-left: 9px; - padding-right: 9px; -} -.jasmine_html-reporter .jasmine-banner { - position: relative; -} -.jasmine_html-reporter .jasmine-banner .jasmine-title { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==") no-repeat; - background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=") no-repeat, none; - background-size: 100%; - display: block; - float: left; - width: 90px; - height: 25px; -} -.jasmine_html-reporter .jasmine-banner .jasmine-version { - margin-left: 14px; - position: relative; - top: 6px; -} -.jasmine_html-reporter #jasmine_content { - position: fixed; - right: 100%; -} -.jasmine_html-reporter .jasmine-banner { - margin-top: 14px; -} -.jasmine_html-reporter .jasmine-duration { - color: #fff; - float: right; - line-height: 28px; - padding-right: 9px; - font-size: 12px; -} -.jasmine_html-reporter .jasmine-symbol-summary { - overflow: hidden; - margin: 14px 0; -} -.jasmine_html-reporter .jasmine-symbol-summary li { - display: inline-block; - height: 10px; - width: 14px; - font-size: 16px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed { - font-size: 14px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed:before { - color: #007069; - content: "•"; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed { - line-height: 9px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { - color: #ca3a11; - content: "×"; - font-weight: bold; - margin-left: -1px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded { - font-size: 14px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before { - color: #bababa; - content: "•"; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded-no-display { - font-size: 14px; - display: none; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { - line-height: 17px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { - color: #ba9d37; - content: "*"; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { - font-size: 14px; -} -.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty:before { - color: #ba9d37; - content: "•"; -} -.jasmine_html-reporter progress { - width: 100%; -} -.jasmine_html-reporter progress[value] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} -.jasmine_html-reporter progress[value]::-webkit-progress-value, .jasmine_html-reporter progress[value]::-moz-progress-bar { - background: #007069; -} -.failed .jasmine_html-reporter progress[value]::-webkit-progress-value, .failed .jasmine_html-reporter progress[value]::-moz-progress-bar { - background: #ca3a11; -} -.jasmine_html-reporter progress.failed[value]::-webkit-progress-value, .jasmine_html-reporter progress.failed[value]::-moz-progress-bar { - background: #ca3a11; -} -.jasmine_html-reporter .jasmine-run-options { - float: right; - margin-right: 5px; - border: 1px solid #8a4182; - color: #8a4182; - position: relative; - line-height: 20px; -} -.jasmine_html-reporter .jasmine-run-options .jasmine-trigger { - cursor: pointer; - padding: 8px 16px; -} -.jasmine_html-reporter .jasmine-run-options .jasmine-payload { - position: absolute; - display: none; - right: -1px; - border: 1px solid #8a4182; - background-color: #eee; - white-space: nowrap; - padding: 4px 8px; -} -.jasmine_html-reporter .jasmine-run-options .jasmine-payload.jasmine-open { - display: block; -} -.jasmine_html-reporter .jasmine-bar { - line-height: 28px; - font-size: 14px; - display: block; - color: #eee; -} -.jasmine_html-reporter .jasmine-bar.jasmine-in-progress { - color: #333; -} -.jasmine_html-reporter .jasmine-bar.jasmine-failed, .jasmine_html-reporter .jasmine-bar.jasmine-errored { - background-color: #ca3a11; - color: #eee; - border-bottom: 1px solid #eee; -} -.jasmine_html-reporter .jasmine-bar.jasmine-passed { - background-color: #007069; -} -.jasmine_html-reporter .jasmine-bar.jasmine-incomplete { - background-color: #bababa; -} -.jasmine_html-reporter .jasmine-bar.jasmine-skipped { - background-color: #bababa; -} -.jasmine_html-reporter .jasmine-bar.jasmine-warning { - margin-top: 14px; - margin-bottom: 14px; - background-color: #ba9d37; - color: #333; -} -.jasmine_html-reporter .jasmine-bar.jasmine-menu { - background-color: #fff; - color: #000; -} -.jasmine_html-reporter .jasmine-bar.jasmine-menu a { - color: blue; - text-decoration: underline; -} -.jasmine_html-reporter .jasmine-bar a { - color: white; -} -.jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list, -.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures, -.jasmine_html-reporter.jasmine-spec-list .jasmine-performance-view { - display: none; -} -.jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list, -.jasmine_html-reporter.jasmine-failure-list .jasmine-summary, -.jasmine_html-reporter.jasmine-failure-list .jasmine-performance-view { - display: none; -} -.jasmine_html-reporter.jasmine-performance .jasmine-results .jasmine-failures, -.jasmine_html-reporter.jasmine-performance .jasmine-summary { - display: none; -} -.jasmine_html-reporter .jasmine-results { - margin-top: 14px; -} -.jasmine_html-reporter .jasmine-summary { - margin-top: 14px; -} -.jasmine_html-reporter .jasmine-summary ul { - list-style-type: none; - margin-left: 14px; - padding-top: 0; - padding-left: 0; -} -.jasmine_html-reporter .jasmine-summary ul.jasmine-suite { - margin-top: 7px; - margin-bottom: 7px; -} -.jasmine_html-reporter .jasmine-summary li.jasmine-passed a { - color: #007069; -} -.jasmine_html-reporter .jasmine-summary li.jasmine-failed a { - color: #ca3a11; -} -.jasmine_html-reporter .jasmine-summary li.jasmine-empty a { - color: #ba9d37; -} -.jasmine_html-reporter .jasmine-summary li.jasmine-pending a { - color: #ba9d37; -} -.jasmine_html-reporter .jasmine-summary li.jasmine-excluded a { - color: #bababa; -} -.jasmine_html-reporter .jasmine-specs li.jasmine-passed a:before { - content: "• "; -} -.jasmine_html-reporter .jasmine-specs li.jasmine-failed a:before { - content: "× "; -} -.jasmine_html-reporter .jasmine-specs li.jasmine-empty a:before { - content: "* "; -} -.jasmine_html-reporter .jasmine-specs li.jasmine-pending a:before { - content: "• "; -} -.jasmine_html-reporter .jasmine-specs li.jasmine-excluded a:before { - content: "• "; -} -.jasmine_html-reporter .jasmine-specs li .jasmine-spec-duration { - margin-left: 1em; -} -.jasmine_html-reporter .jasmine-description + .jasmine-suite { - margin-top: 0; -} -.jasmine_html-reporter .jasmine-suite { - margin-top: 14px; -} -.jasmine_html-reporter .jasmine-suite a { - color: #333; -} -.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { - margin-bottom: 28px; -} -.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { - background-color: #ca3a11; - color: white; -} -.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { - color: white; -} -.jasmine_html-reporter .jasmine-result-message { - padding-top: 14px; - color: #333; - white-space: pre-wrap; -} -.jasmine_html-reporter .jasmine-result-message span.jasmine-result { - display: block; -} -.jasmine_html-reporter .jasmine-stack-trace { - margin: 5px 0 0 0; - max-height: 224px; - overflow: auto; - line-height: 18px; - color: #666; - border: 1px solid #ddd; - background: white; - white-space: pre; -} -.jasmine_html-reporter .jasmine-expander a { - display: block; - margin-left: 14px; - color: blue; - text-decoration: underline; -} -.jasmine_html-reporter .jasmine-expander-contents { - display: none; -} -.jasmine_html-reporter .jasmine-expanded { - padding-bottom: 10px; -} -.jasmine_html-reporter .jasmine-expanded .jasmine-expander-contents { - display: block; - margin-left: 14px; - padding: 5px; -} -.jasmine_html-reporter .jasmine-debug-log { - margin: 5px 0 0 0; - padding: 5px; - color: #666; - border: 1px solid #ddd; - background: white; -} -.jasmine_html-reporter .jasmine-debug-log table { - border-spacing: 0; -} -.jasmine_html-reporter .jasmine-debug-log table, .jasmine_html-reporter .jasmine-debug-log th, .jasmine_html-reporter .jasmine-debug-log td { - border: 1px solid #ddd; -} -.jasmine_html-reporter .jasmine-debug-log .jasmine-debug-log-msg { - white-space: pre; -} - -.jasmine-hidden { - display: none; -} - -.jasmine-tab + .jasmine-tab:before { - content: " | "; -} - -.jasmine-performance-view h2, .jasmine-performance-view h3 { - margin-top: 1em; - margin-bottom: 1em; -} -.jasmine-performance-view table { - border-spacing: 5px; -} -.jasmine-performance-view th, .jasmine-performance-view td { - text-align: left; -} \ No newline at end of file diff --git a/src/static/tests/lib/jasmine-6.0.1/jasmine.js b/src/static/tests/lib/jasmine-6.0.1/jasmine.js deleted file mode 100644 index 5d5700b..0000000 --- a/src/static/tests/lib/jasmine-6.0.1/jasmine.js +++ /dev/null @@ -1,12412 +0,0 @@ -/* -Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2026 The Jasmine developers - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -// eslint-disable-next-line no-unused-vars,no-var -var getJasmineRequireObj = (function() { - 'use strict'; - let jasmineRequire; - - if ( - typeof module !== 'undefined' && - module.exports && - typeof exports !== 'undefined' - ) { - // Node - jasmineRequire = exports; - } else { - // Browser - jasmineRequire = globalThis.jasmineRequire = {}; - } - - function getJasmineRequire() { - return jasmineRequire; - } - - const loadedAsBrowserEsm = - globalThis.document && !globalThis.document.currentScript; - - getJasmineRequire().core = function(jRequire) { - const j$ = {}; - Object.defineProperty(j$, 'private', { - enumerable: true, - value: {} - }); - - jRequire.base(j$, globalThis); - j$.private.deprecateMonkeyPatching = jRequire.deprecateMonkeyPatching(j$); - j$.private.util = jRequire.util(j$); - j$.private.errors = jRequire.errors(); - j$.private.formatErrorMsg = jRequire.formatErrorMsg(j$); - j$.private.AllOf = jRequire.AllOf(j$); - j$.private.Any = jRequire.Any(j$); - j$.private.Anything = jRequire.Anything(j$); - j$.private.CallTracker = jRequire.CallTracker(j$); - j$.private.MockDate = jRequire.MockDate(j$); - j$.private.getStackClearer = jRequire.StackClearer(j$); - j$.private.Clock = jRequire.Clock(j$); - j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); - j$.private.Deprecator = jRequire.Deprecator(j$); - j$.private.Configuration = jRequire.Configuration(j$); - j$.private.Env = jRequire.Env(j$); - j$.private.StackTrace = jRequire.StackTrace(j$); - j$.private.ExceptionFormatter = jRequire.ExceptionFormatter(j$); - j$.private.ExpectationFilterChain = jRequire.ExpectationFilterChain(); - j$.private.Expector = jRequire.Expector(j$); - j$.private.Expectation = jRequire.Expectation(j$); - j$.private.buildExpectationResult = jRequire.buildExpectationResult(j$); - j$.private.JsApiReporter = jRequire.JsApiReporter(j$); - j$.private.makePrettyPrinter = jRequire.makePrettyPrinter(j$); - j$.private.basicPrettyPrinter = j$.private.makePrettyPrinter(); - j$.private.MatchersUtil = jRequire.MatchersUtil(j$); - j$.private.ObjectContaining = jRequire.ObjectContaining(j$); - j$.private.ArrayContaining = jRequire.ArrayContaining(j$); - j$.private.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); - j$.private.MapContaining = jRequire.MapContaining(j$); - j$.private.SetContaining = jRequire.SetContaining(j$); - j$.private.QueueRunner = jRequire.QueueRunner(j$); - j$.private.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); - j$.private.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( - j$ - ); - j$.private.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( - j$ - ); - j$.private.reporterEvents = jRequire.reporterEvents(j$); - j$.private.ReportDispatcher = jRequire.ReportDispatcher(j$); - j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$); - j$.private.CurrentRunableTracker = jRequire.CurrentRunableTracker(); - j$.private.RunableResources = jRequire.RunableResources(j$); - j$.private.Runner = jRequire.Runner(j$); - j$.private.Spec = jRequire.Spec(j$); - j$.private.Spy = jRequire.Spy(j$); - j$.private.SpyFactory = jRequire.SpyFactory(j$); - j$.private.SpyRegistry = jRequire.SpyRegistry(j$); - j$.private.SpyStrategy = jRequire.SpyStrategy(j$); - j$.private.StringMatching = jRequire.StringMatching(j$); - j$.private.StringContaining = jRequire.StringContaining(j$); - j$.private.UserContext = jRequire.UserContext(j$); - j$.private.Suite = jRequire.Suite(j$); - j$.private.SuiteBuilder = jRequire.SuiteBuilder(j$); - j$.Timer = jRequire.Timer(); - j$.private.TreeProcessor = jRequire.TreeProcessor(j$); - j$.private.TreeRunner = jRequire.TreeRunner(j$); - j$.version = jRequire.version(); - j$.private.Order = jRequire.Order(); - j$.private.DiffBuilder = jRequire.DiffBuilder(j$); - j$.private.NullDiffBuilder = jRequire.NullDiffBuilder(j$); - j$.private.ObjectPath = jRequire.ObjectPath(j$); - j$.private.MismatchTree = jRequire.MismatchTree(j$); - j$.private.GlobalErrors = jRequire.GlobalErrors(j$); - j$.private.Truthy = jRequire.Truthy(j$); - j$.private.Falsy = jRequire.Falsy(j$); - j$.private.Empty = jRequire.Empty(j$); - j$.private.NotEmpty = jRequire.NotEmpty(j$); - j$.private.Is = jRequire.Is(j$); - - j$.private.matchers = jRequire.requireMatchers(jRequire, j$); - j$.private.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$); - - j$.private.loadedAsBrowserEsm = loadedAsBrowserEsm; - - j$.private.deprecateMonkeyPatching(j$, [ - // These are meant to be set by users. - 'DEFAULT_TIMEOUT_INTERVAL', - 'MAX_PRETTY_PRINT_ARRAY_LENGTH', - 'MAX_PRETTY_PRINT_CHARS', - 'MAX_PRETTY_PRINT_DEPTH', - - // These are part of the deprecation warning mechanism. To avoid infinite - // recursion, they're separately protected in a way that doesn't emit - // deprecation warnings. - 'private', - 'getEnv' - ]); - - return j$; - }; - - return getJasmineRequire; -})(this); - -getJasmineRequireObj().requireMatchers = function(jRequire, j$) { - 'use strict'; - - const availableMatchers = [ - 'nothing', - 'toBe', - 'toBeCloseTo', - 'toBeDefined', - 'toBeInstanceOf', - 'toBeFalse', - 'toBeFalsy', - 'toBeGreaterThan', - 'toBeGreaterThanOrEqual', - 'toBeLessThan', - 'toBeLessThanOrEqual', - 'toBeNaN', - 'toBeNegativeInfinity', - 'toBeNull', - 'toBePositiveInfinity', - 'toBeTrue', - 'toBeTruthy', - 'toBeUndefined', - 'toBeNullish', - 'toContain', - 'toEqual', - 'toHaveSize', - 'toHaveBeenCalled', - 'toHaveBeenCalledBefore', - 'toHaveBeenCalledOnceWith', - 'toHaveBeenCalledTimes', - 'toHaveBeenCalledWith', - 'toHaveClass', - 'toHaveClasses', - 'toHaveSpyInteractions', - 'toHaveNoOtherSpyInteractions', - 'toMatch', - 'toThrow', - 'toThrowError', - 'toThrowMatching' - ], - matchers = {}; - - for (const name of availableMatchers) { - matchers[name] = jRequire[name](j$); - } - - return matchers; -}; - -getJasmineRequireObj().base = function(j$, jasmineGlobal) { - 'use strict'; - - /** - * Maximum object depth the pretty printer will print to. - * Set this to a lower value to speed up pretty printing if you have large objects. - * @name jasmine.MAX_PRETTY_PRINT_DEPTH - * @default 8 - * @since 1.3.0 - */ - j$.MAX_PRETTY_PRINT_DEPTH = 8; - /** - * Maximum number of array elements to display when pretty printing objects. - * This will also limit the number of keys and values displayed for an object. - * Elements past this number will be ellipised. - * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH - * @default 50 - * @since 2.7.0 - */ - j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50; - /** - * Maximum number of characters to display when pretty printing objects. - * Characters past this number will be ellipised. - * @name jasmine.MAX_PRETTY_PRINT_CHARS - * @default 1000 - * @since 2.9.0 - */ - j$.MAX_PRETTY_PRINT_CHARS = 1000; - /** - * Default number of milliseconds Jasmine will wait for an asynchronous spec, - * before, or after function to complete. This can be overridden on a case by - * case basis by passing a time limit as the third argument to {@link it}, - * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or - * {@link afterAll}. The value must be no greater than the largest number of - * milliseconds supported by setTimeout, which is usually 2147483647. - * - * While debugging tests, you may want to set this to a large number (or pass - * a large number to one of the functions mentioned above) so that Jasmine - * does not move on to after functions or the next spec while you're debugging. - * @name jasmine.DEFAULT_TIMEOUT_INTERVAL - * @default 5000 - * @since 1.3.0 - */ - let DEFAULT_TIMEOUT_INTERVAL = 5000; - Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', { - get: function() { - return DEFAULT_TIMEOUT_INTERVAL; - }, - set: function(newValue) { - j$.private.util.validateTimeout( - newValue, - 'jasmine.DEFAULT_TIMEOUT_INTERVAL' - ); - DEFAULT_TIMEOUT_INTERVAL = newValue; - } - }); - - j$.getGlobal = function() { - return jasmineGlobal; - }; - - /** - * Get the currently booted Jasmine Environment. - * - * @name jasmine.getEnv - * @since 1.3.0 - * @function - * @return {Env} - */ - Object.defineProperty(j$, 'getEnv', { - enumerable: true, - value: function(options) { - const env = (j$.private.currentEnv_ = - j$.private.currentEnv_ || new j$.private.Env(options)); - //jasmine. singletons in here (setTimeout blah blah). - return env; - } - }); - - j$.private.isObject = function(value) { - return ( - value !== undefined && value !== null && j$.private.isA('Object', value) - ); - }; - - j$.private.isString = function(value) { - return j$.private.isA('String', value); - }; - - j$.private.isNumber = function(value) { - return j$.private.isA('Number', value); - }; - - j$.private.isFunction = function(value) { - return j$.private.isA('Function', value); - }; - - j$.private.isAsyncFunction = function(value) { - return j$.private.isA('AsyncFunction', value); - }; - - j$.private.isGeneratorFunction = function(value) { - return j$.private.isA('GeneratorFunction', value); - }; - - j$.private.isTypedArray = function(value) { - return ( - j$.private.isA('Float32Array', value) || - j$.private.isA('Float64Array', value) || - j$.private.isA('Int16Array', value) || - j$.private.isA('Int32Array', value) || - j$.private.isA('Int8Array', value) || - j$.private.isA('Uint16Array', value) || - j$.private.isA('Uint32Array', value) || - j$.private.isA('Uint8Array', value) || - j$.private.isA('Uint8ClampedArray', value) - ); - }; - - j$.private.isA = function(typeName, value) { - return j$.private.getType(value) === '[object ' + typeName + ']'; - }; - - j$.private.isError = function(value) { - if (!value) { - return false; - } - - if (value instanceof Error) { - return true; - } - - return typeof value.stack === 'string' && typeof value.message === 'string'; - }; - - j$.private.isAsymmetricEqualityTester = function(obj) { - return obj ? j$.private.isA('Function', obj.asymmetricMatch) : false; - }; - - j$.private.getType = function(value) { - return Object.prototype.toString.apply(value); - }; - - j$.private.isDomNode = function(obj) { - // Node is a function, because constructors - return typeof jasmineGlobal.Node !== 'undefined' - ? obj instanceof jasmineGlobal.Node - : obj !== null && - typeof obj === 'object' && - typeof obj.nodeType === 'number' && - typeof obj.nodeName === 'string'; - // return obj.nodeType > 0; - }; - - j$.private.isMap = function(obj) { - return ( - obj !== null && - typeof obj !== 'undefined' && - obj.constructor === jasmineGlobal.Map - ); - }; - - j$.private.isSet = function(obj) { - return ( - obj !== null && - typeof obj !== 'undefined' && - obj.constructor === jasmineGlobal.Set - ); - }; - - j$.private.isWeakMap = function(obj) { - return ( - obj !== null && - typeof obj !== 'undefined' && - obj.constructor === jasmineGlobal.WeakMap - ); - }; - - j$.private.isURL = function(obj) { - return ( - obj !== null && - typeof obj !== 'undefined' && - obj.constructor === jasmineGlobal.URL - ); - }; - - j$.private.isIterable = function(value) { - return value && !!value[Symbol.iterator]; - }; - - j$.private.isDataView = function(obj) { - return ( - obj !== null && - typeof obj !== 'undefined' && - obj.constructor === jasmineGlobal.DataView - ); - }; - - j$.private.isPromise = function(obj) { - return !!obj && obj.constructor === jasmineGlobal.Promise; - }; - - j$.private.isPromiseLike = function(obj) { - return !!obj && j$.private.isFunction(obj.then); - }; - - j$.private.fnNameFor = function(func) { - if (func.name) { - return func.name; - } - - const matches = - func.toString().match(/^\s*function\s*(\w+)\s*\(/) || - func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/); - - return matches ? matches[1] : ''; - }; - - j$.private.isPending = function(promise) { - const sentinel = {}; - return Promise.race([promise, Promise.resolve(sentinel)]).then( - function(result) { - return result === sentinel; - }, - function() { - return false; - } - ); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared matches every provided equality tester. - * @name asymmetricEqualityTesters.allOf - * @emittedName jasmine.allOf - * @since 5.13.0 - * @function - * @param {...*} arguments - The asymmetric equality checkers to compare. - */ - j$.allOf = function() { - return new j$.AllOf(...arguments); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is an instance of the specified class/constructor. - * @name asymmetricEqualityTesters.any - * @emittedName jasmine.any - * @since 1.3.0 - * @function - * @param {Constructor} clazz - The constructor to check against. - */ - j$.any = function(clazz) { - return new j$.private.Any(clazz); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is not `null` and not `undefined`. - * @name asymmetricEqualityTesters.anything - * @emittedName jasmine.anything - * @since 2.2.0 - * @function - */ - j$.anything = function() { - return new j$.private.Anything(); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is `true` or anything truthy. - * @name asymmetricEqualityTesters.truthy - * @emittedName jasmine.truthy - * @since 3.1.0 - * @function - */ - j$.truthy = function() { - return new j$.private.Truthy(); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is `null`, `undefined`, `0`, `false` or anything - * falsy. - * @name asymmetricEqualityTesters.falsy - * @emittedName jasmine.falsy - * @since 3.1.0 - * @function - */ - j$.falsy = function() { - return new j$.private.Falsy(); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is empty. - * @name asymmetricEqualityTesters.empty - * @emittedName jasmine.empty - * @since 3.1.0 - * @function - */ - j$.empty = function() { - return new j$.private.Empty(); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that passes if the actual value is - * the same as the sample as determined by the `===` operator. - * @name asymmetricEqualityTesters.is - * @emittedName jasmine.is - * @function - * @param {Object} sample - The value to compare the actual to. - */ - j$.is = function(sample) { - return new j$.private.Is(sample); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared is not empty. - * @name asymmetricEqualityTesters.notEmpty - * @emittedName jasmine.notEmpty - * @since 3.1.0 - * @function - */ - j$.notEmpty = function() { - return new j$.private.NotEmpty(); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value being compared contains at least the specified keys and values. - * @name asymmetricEqualityTesters.objectContaining - * @emittedName jasmine.objectContaining - * @since 1.3.0 - * @function - * @param {Object} sample - The subset of properties that _must_ be in the actual. - */ - j$.objectContaining = function(sample) { - return new j$.private.ObjectContaining(sample); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value is a `String` that matches the `RegExp` or `String`. - * @name asymmetricEqualityTesters.stringMatching - * @emittedName jasmine.stringMatching - * @since 2.2.0 - * @function - * @param {RegExp|String} expected - */ - j$.stringMatching = function(expected) { - return new j$.private.StringMatching(expected); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value is a `String` that contains the specified `String`. - * @name asymmetricEqualityTesters.stringContaining - * @emittedName jasmine.stringContaining - * @since 3.10.0 - * @function - * @param {String} expected - */ - j$.stringContaining = function(expected) { - return new j$.private.StringContaining(expected); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value is an `Array` that contains at least the elements in the sample. - * @name asymmetricEqualityTesters.arrayContaining - * @emittedName jasmine.arrayContaining - * @since 2.2.0 - * @function - * @param {Array} sample - */ - j$.arrayContaining = function(sample) { - return new j$.private.ArrayContaining(sample); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if the actual - * value is an `Array` that contains all of the elements in the sample in - * any order. - * @name asymmetricEqualityTesters.arrayWithExactContents - * @emittedName jasmine.arrayWithExactContents - * @since 2.8.0 - * @function - * @param {Array} sample - */ - j$.arrayWithExactContents = function(sample) { - return new j$.private.ArrayWithExactContents(sample); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if every - * key/value pair in the sample passes the deep equality comparison - * with at least one key/value pair in the actual value being compared - * @name asymmetricEqualityTesters.mapContaining - * @emittedName jasmine.mapContaining - * @since 3.5.0 - * @function - * @param {Map} sample - The subset of items that _must_ be in the actual. - */ - j$.mapContaining = function(sample) { - return new j$.private.MapContaining(sample); - }; - - /** - * Get an {@link AsymmetricEqualityTester} that will succeed if every item - * in the sample passes the deep equality comparison - * with at least one item in the actual value being compared - * @name asymmetricEqualityTesters.setContaining - * @emittedName jasmine.setContaining - * @since 3.5.0 - * @function - * @param {Set} sample - The subset of items that _must_ be in the actual. - */ - j$.setContaining = function(sample) { - return new j$.private.SetContaining(sample); - }; - - /** - * Determines whether the provided function is a Jasmine spy. - * @name jasmine.isSpy - * @since 2.0.0 - * @function - * @param {Function} putativeSpy - The function to check. - * @return {Boolean} - */ - j$.isSpy = function(putativeSpy) { - if (!putativeSpy) { - return false; - } - return ( - putativeSpy.and instanceof j$.private.SpyStrategy && - putativeSpy.calls instanceof j$.private.CallTracker - ); - }; - - /** - * Logs a message for use in debugging. If the spec fails, trace messages - * will be included in the {@link SpecDoneEvent|result} passed to the - * reporter's specDone method. - * - * This method should be called only when a spec (including any associated - * beforeEach or afterEach functions) is running. - * @function - * @name jasmine.debugLog - * @since 4.0.0 - * @param {String} msg - The message to log - */ - j$.debugLog = function(msg) { - j$.getEnv().debugLog(msg); - }; - - /** - * Replaces Jasmine's global error handling with a spy. This prevents Jasmine - * from treating uncaught exceptions and unhandled promise rejections - * as spec failures and allows them to be inspected using the spy's - * {@link Spy#calls|calls property} and related matchers such as - * {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}. - * - * After installing the spy, spyOnGlobalErrorsAsync immediately calls its - * argument, which must be an async or promise-returning function. The spy - * will be passed as the first argument to that callback. Normal error - * handling will be restored when the promise returned from the callback is - * settled. - * - * When the JavaScript runtime reports an uncaught error or unhandled rejection, - * the spy will be called with a single parameter representing Jasmine's best - * effort at describing the error. This parameter may be of any type, because - * JavaScript allows anything to be thrown or used as the reason for a - * rejected promise, but Error instances and strings are most common. - * - * Note: The JavaScript runtime may deliver uncaught error events and unhandled - * rejection events asynchronously, especially in browsers. If the event - * occurs after the promise returned from the callback is settled, it won't - * be routed to the spy even if the underlying error occurred previously. - * It's up to you to ensure that all of the error/rejection events that you - * want to handle have occurred before you resolve the promise returned from - * the callback. - * - * You must ensure that the `it`/`beforeEach`/etc fn that called - * `spyOnGlobalErrorsAsync` does not signal completion until after the - * promise returned by `spyOnGlobalErrorsAsync` is resolved. Normally this is - * done by `await`ing the returned promise. Leaving the global error spy - * installed after the `it`/`beforeEach`/etc fn that installed it signals - * completion is likely to cause problems and is not supported. - * @name jasmine.spyOnGlobalErrorsAsync - * @function - * @async - * @param {AsyncFunction} fn - A function to run, during which the global error spy will be effective - * @example - * it('demonstrates global error spies', async function() { - * await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) { - * setTimeout(function() { - * throw new Error('the expected error'); - * }); - * await new Promise(function(resolve) { - * setTimeout(resolve); - * }); - * const expected = new Error('the expected error'); - * expect(globalErrorSpy).toHaveBeenCalledWith(expected); - * }); - * }); - */ - j$.spyOnGlobalErrorsAsync = async function(fn) { - await jasmine.getEnv().spyOnGlobalErrorsAsync(fn); - }; -}; - -getJasmineRequireObj().util = function(j$) { - 'use strict'; - - const util = {}; - - util.clone = function(obj) { - if (Object.prototype.toString.apply(obj) === '[object Array]') { - return obj.slice(); - } - - const cloned = {}; - for (const prop in obj) { - if (obj.hasOwnProperty(prop)) { - cloned[prop] = obj[prop]; - } - } - - return cloned; - }; - - util.cloneArgs = function(args) { - return Array.from(args).map(function(arg) { - const str = Object.prototype.toString.apply(arg), - primitives = /^\[object (Boolean|String|RegExp|Number)/; - - // All falsey values are either primitives, `null`, or `undefined. - if (!arg || str.match(primitives)) { - return arg; - } else if (str === '[object Date]') { - return new Date(arg.valueOf()); - } else { - return j$.private.util.clone(arg); - } - }); - }; - - util.getPropertyDescriptor = function(obj, methodName) { - let descriptor, - proto = obj; - - do { - descriptor = Object.getOwnPropertyDescriptor(proto, methodName); - proto = Object.getPrototypeOf(proto); - } while (!descriptor && proto); - - return descriptor; - }; - - util.has = function(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); - }; - - function callerFile() { - const trace = new j$.private.StackTrace(new Error()); - return trace.frames[1].file; - } - - util.jasmineFile = (function() { - let result; - - return function() { - if (!result) { - result = callerFile(); - } - - return result; - }; - })(); - - util.validateTimeout = function(timeout, msgPrefix) { - // Timeouts are implemented with setTimeout, which only supports a limited - // range of values. The limit is unspecified, as is the behavior when it's - // exceeded. But on all currently supported JS runtimes, setTimeout calls - // the callback immediately when the timeout is greater than 2147483647 - // (the maximum value of a signed 32 bit integer). - const max = 2147483647; - - if (timeout > max) { - throw new Error( - (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max - ); - } - }; - - util.assertReporterCloneable = function(v, msgPrefix) { - try { - // Reporter events are cloned internally via structuredClone, and it's - // common for reporters (including jasmine-browser-runner's) to JSON - // serialize them. - JSON.stringify(structuredClone(v)); - } catch (e) { - throw new Error(`${msgPrefix} can't be cloned`, { cause: e }); - } - }; - - return util; -}; - -getJasmineRequireObj().Spec = function(j$) { - 'use strict'; - - class Spec { - #autoCleanClosures; - #throwOnExpectationFailure; - #timer; - #metadata; - #executionState; - - constructor(attrs) { - this.expectationFactory = attrs.expectationFactory; - this.asyncExpectationFactory = attrs.asyncExpectationFactory; - this.id = attrs.id; - this.filename = attrs.filename; - this.parentSuiteId = attrs.parentSuiteId; - this.description = attrs.description || ''; - this.queueableFn = attrs.queueableFn; - this.beforeAndAfterFns = - attrs.beforeAndAfterFns || - function() { - return { befores: [], afters: [] }; - }; - this.userContext = - attrs.userContext || - function() { - return {}; - }; - this.getPath = function() { - return attrs.getPath ? attrs.getPath(this) : []; - }; - - this.#autoCleanClosures = - attrs.autoCleanClosures === undefined - ? true - : !!attrs.autoCleanClosures; - this.onLateError = attrs.onLateError || function() {}; - this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - this.#timer = attrs.timer || new j$.Timer(); - - this.reset(); - - if (!this.queueableFn.fn) { - this.exclude(); - } - } - - addExpectationResult(passed, data, isError) { - const expectationResult = j$.private.buildExpectationResult(data); - - if (passed) { - this.#executionState.passedExpectations.push(expectationResult); - } else { - if (this.reportedDone) { - this.onLateError(expectationResult); - } else { - this.#executionState.failedExpectations.push(expectationResult); - } - - if (this.#throwOnExpectationFailure && !isError) { - throw new j$.private.errors.ExpectationFailed(); - } - } - } - - getSpecProperty(key) { - this.#executionState.properties = this.#executionState.properties || {}; - return this.#executionState.properties[key]; - } - - setSpecProperty(key, value) { - // Key and value will eventually be cloned during reporting. The error - // thrown at that point if they aren't cloneable isn't very helpful. - // Throw a better one now. - if (!j$.private.isString(key)) { - throw new Error('Key must be a string'); - } - j$.private.util.assertReporterCloneable(value, 'Value'); - - this.#executionState.properties = this.#executionState.properties || {}; - this.#executionState.properties[key] = value; - } - - executionStarted() { - this.#timer.start(); - } - - executionFinished(excluded, failSpecWithNoExp) { - this.#executionState.dynamicallyExcluded = excluded; - this.#executionState.requireExpectations = failSpecWithNoExp; - - if (this.#autoCleanClosures) { - this.queueableFn.fn = null; - } - - this.#executionState.duration = this.#timer.elapsed(); - - if (this.status() !== 'failed') { - this.#executionState.debugLogs = null; - } - } - - hadBeforeAllFailure() { - this.addExpectationResult( - false, - { - passed: false, - message: - 'Not run because a beforeAll function failed. The ' + - 'beforeAll failure will be reported on the suite that ' + - 'caused it.' - }, - true - ); - } - - reset() { - this.#executionState = { - failedExpectations: [], - passedExpectations: [], - deprecationWarnings: [], - pendingReason: this.excludeMessage || '', - duration: null, - properties: null, - debugLogs: null, - // TODO: better naming. Don't make 'excluded' mean two things. - dynamicallyExcluded: false, - requireExpectations: false, - markedPending: this.markedExcluding - }; - this.reportedDone = false; - } - - startedEvent() { - /** - * @typedef SpecStartedEvent - * @property {String} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe(). - * @property {String} filename - Deprecated. The name of the file the spec was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `it`/`fit`/`xit` have been replaced with versions that don't maintain the - * same call stack height as the originals. This property may be removed in - * a future version unless there is enough user interest in keeping it. - * See {@link https://github.com/jasmine/jasmine/issues/2065}. - * @since 2.0.0 - */ - return this.#commonEventFields(); - } - - doneEvent() { - /** - * @typedef SpecDoneEvent - * @property {String} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe(). - * @property {String} filename - The name of the file the spec was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `it`/`fit`/`xit` have been replaced with versions that don't maintain the - * same call stack height as the originals. You can fix that by setting - * {@link Configuration#extraItStackFrames}. - * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec. - * @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec. - * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. - * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. - * @property {String} status - The result of this spec. May be 'passed', 'failed', 'pending', or 'excluded'. - * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} - * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. - * @since 2.0.0 - */ - const event = { - ...this.#commonEventFields(), - status: this.status() - }; - const toCopy = [ - 'failedExpectations', - 'passedExpectations', - 'deprecationWarnings', - 'pendingReason', - 'duration', - 'properties', - 'debugLogs' - ]; - - for (const k of toCopy) { - event[k] = this.#executionState[k]; - } - - return event; - } - - #commonEventFields() { - return { - id: this.id, - description: this.description, - fullName: this.getFullName(), - parentSuiteId: this.parentSuiteId, - filename: this.filename - }; - } - - handleException(e) { - if (Spec.isPendingSpecException(e)) { - this.pend(extractCustomPendingMessage(e)); - return; - } - - if (e instanceof j$.private.errors.ExpectationFailed) { - return; - } - - this.addExpectationResult( - false, - { - matcherName: '', - passed: false, - error: e - }, - true - ); - } - - pend(message) { - this.#executionState.markedPending = true; - if (message) { - this.#executionState.pendingReason = message; - } - } - - get markedPending() { - return this.#executionState.markedPending; - } - - // Like pend(), but pending state will survive reset(). - // Useful for fit, xit, where pending state remains. - exclude(message) { - this.markedExcluding = true; - if (this.message) { - this.excludeMessage = message; - } - this.pend(message); - } - - status() { - if (this.#executionState.dynamicallyExcluded) { - return 'excluded'; - } - - if (this.markedPending) { - return 'pending'; - } - - if ( - this.#executionState.failedExpectations.length > 0 || - (this.#executionState.requireExpectations && - this.#executionState.failedExpectations.length + - this.#executionState.passedExpectations.length === - 0) - ) { - return 'failed'; - } - - return 'passed'; - } - - getFullName() { - return this.getPath().join(' '); - } - - addDeprecationWarning(deprecation) { - if (typeof deprecation === 'string') { - deprecation = { message: deprecation }; - } - this.#executionState.deprecationWarnings.push( - j$.private.buildExpectationResult(deprecation) - ); - } - - debugLog(msg) { - if (!this.#executionState.debugLogs) { - this.#executionState.debugLogs = []; - } - - /** - * @typedef DebugLogEntry - * @property {String} message - The message that was passed to {@link jasmine.debugLog}. - * @property {number} timestamp - The time when the entry was added, in - * milliseconds from the spec's start time - */ - this.#executionState.debugLogs.push({ - message: msg, - timestamp: this.#timer.elapsed() - }); - } - - /** - * @interface Spec - * @see Configuration#specFilter - * @since 2.0.0 - */ - get metadata() { - // NOTE: Although most of jasmine-core only exposes these metadata objects, - // actual Spec instances are still passed to Configuration#specFilter. Until - // that is fixed, it's important to make sure that all metadata properties - // also exist in compatible form on the underlying Spec. - if (!this.#metadata) { - this.#metadata = { - /** - * The unique ID of this spec. - * @name Spec#id - * @readonly - * @type {string} - * @since 2.0.0 - */ - id: this.id, - - /** - * The description passed to the {@link it} that created this spec. - * @name Spec#description - * @readonly - * @type {string} - * @since 2.0.0 - */ - description: this.description, - - /** - * The full description including all ancestors of this spec. - * @name Spec#getFullName - * @function - * @returns {string} - * @since 2.0.0 - */ - getFullName: this.getFullName.bind(this), - - /** - * The full path of the spec, as an array of names. - * @name Spec#getPath - * @function - * @returns {Array.} - * @since 5.7.0 - */ - getPath: this.getPath.bind(this), - - /** - * The name of the file the spec was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `it`/`fit`/`xit` have been replaced with versions that don't maintain the - * same call stack height as the originals. You can fix that by setting - * {@link Configuration#extraItStackFrames}. - * @name Spec#filename - * @readonly - * @type {string} - * @since 5.13.0 - */ - filename: this.filename - }; - } - - return this.#metadata; - } - } - - const extractCustomPendingMessage = function(e) { - const fullMessage = e.toString(), - boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), - boilerplateEnd = - boilerplateStart + Spec.pendingSpecExceptionMessage.length; - - return fullMessage.slice(boilerplateEnd); - }; - - Spec.pendingSpecExceptionMessage = '=> marked Pending'; - - Spec.isPendingSpecException = function(e) { - return !!( - e && - e.toString && - e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1 - ); - }; - - return Spec; -}; - -getJasmineRequireObj().Order = function() { - 'use strict'; - - function Order(options) { - this.random = 'random' in options ? options.random : true; - const seed = (this.seed = options.seed || generateSeed()); - this.sort = this.random ? randomOrder : naturalOrder; - - function naturalOrder(items) { - return items; - } - - function randomOrder(items) { - const copy = items.slice(); - copy.sort(function(a, b) { - return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id); - }); - return copy; - } - - function generateSeed() { - return String(Math.random()).slice(-5); - } - - // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function - // used to get a different output when the key changes slightly. - // We use your return to sort the children randomly in a consistent way when - // used in conjunction with a seed - - function jenkinsHash(key) { - let hash, i; - for (hash = i = 0; i < key.length; ++i) { - hash += key.charCodeAt(i); - hash += hash << 10; - hash ^= hash >> 6; - } - hash += hash << 3; - hash ^= hash >> 11; - hash += hash << 15; - return hash; - } - } - - return Order; -}; - -getJasmineRequireObj().Env = function(j$) { - 'use strict'; - - const DEFAULT_IT_DESCRIBE_STACK_DEPTH = 3; - - /** - * @class Env - * @since 2.0.0 - * @classdesc The Jasmine environment.
- * _Note:_ Do not construct this directly. You can obtain the Env instance by - * calling {@link jasmine.getEnv}. - * @hideconstructor - */ - function Env(envOptions) { - envOptions = envOptions || {}; - - const self = this; - const GlobalErrors = envOptions.GlobalErrors || j$.private.GlobalErrors; - const global = envOptions.global || j$.getGlobal(); - - const realSetTimeout = global.setTimeout; - const realClearTimeout = global.clearTimeout; - const stackClearer = j$.private.getStackClearer(global); - this.clock = new j$.private.Clock( - global, - function() { - return new j$.private.DelayedFunctionScheduler(); - }, - new j$.private.MockDate(global) - ); - - const globalErrors = new GlobalErrors( - global, - // Configuration is late-bound because GlobalErrors needs to be constructed - // before it's set to detect load-time errors in browsers - () => this.configuration() - ); - const { installGlobalErrors, uninstallGlobalErrors } = (function() { - let installed = false; - - return { - installGlobalErrors() { - if (!installed) { - globalErrors.install(); - installed = true; - } - }, - uninstallGlobalErrors() { - if (installed) { - globalErrors.uninstall(); - installed = false; - } - } - }; - })(); - - const runableResources = new j$.private.RunableResources({ - getCurrentRunableId: function() { - const r = runner.currentRunable(); - return r ? r.id : null; - }, - globalErrors - }); - - let reportDispatcher; - let topSuite; - let runner; - let parallelLoadingState = null; // 'specs', 'helpers', or null for non-parallel - - const config = new j$.private.Configuration(); - - if (!envOptions.suppressLoadErrors) { - installGlobalErrors(); - globalErrors.pushListener(function loadtimeErrorHandler(error) { - topSuite.addExpectationResult(false, { - passed: false, - globalErrorType: 'load', - message: error.message, - stack: error.stack, - filename: error.filename, - lineno: error.lineno - }); - }); - } - - /** - * Configure your jasmine environment - * @name Env#configure - * @since 3.3.0 - * @argument {Configuration} configuration - * @function - */ - this.configure = function(changes) { - if (parallelLoadingState) { - throw new Error( - 'Jasmine cannot be configured via Env in parallel mode' - ); - } - - config.update(changes); - deprecator.verboseDeprecations(config.verboseDeprecations); - stackClearer.setSafariYieldStrategy(config.safariYieldStrategy); - }; - - /** - * Get the current configuration for your jasmine environment - * @name Env#configuration - * @since 3.3.0 - * @function - * @returns {Configuration} - */ - this.configuration = function() { - return config.copy(); - }; - - this.setDefaultSpyStrategy = function(defaultStrategyFn) { - runableResources.setDefaultSpyStrategy(defaultStrategyFn); - }; - - this.addSpyStrategy = function(name, fn) { - runableResources.customSpyStrategies()[name] = fn; - }; - - this.addCustomEqualityTester = function(tester) { - runableResources.customEqualityTesters().push(tester); - }; - - this.addMatchers = function(matchersToAdd) { - runableResources.addCustomMatchers(matchersToAdd); - }; - - this.addAsyncMatchers = function(matchersToAdd) { - runableResources.addCustomAsyncMatchers(matchersToAdd); - }; - - this.addCustomObjectFormatter = function(formatter) { - runableResources.customObjectFormatters().push(formatter); - }; - - j$.private.Expectation.addCoreMatchers(j$.private.matchers); - j$.private.Expectation.addAsyncCoreMatchers(j$.private.asyncMatchers); - - const expectationFactory = function(actual, spec) { - return j$.private.Expectation.factory({ - matchersUtil: runableResources.makeMatchersUtil(), - customMatchers: runableResources.customMatchers(), - actual: actual, - addExpectationResult: addExpectationResult - }); - - function addExpectationResult(passed, result) { - return spec.addExpectationResult(passed, result); - } - }; - - const handleThrowUnlessFailure = function(passed, result) { - if (!passed) { - /** - * @interface - * @name ThrowUnlessFailure - * @extends Error - * @description Represents a failure of an expectation evaluated with - * {@link throwUnless}. Properties of this error are a subset of the - * properties of {@link ExpectationResult} and have the same values. - * - * @property {String} matcherName - The name of the matcher that was executed for this expectation. - * @property {String} message - The failure message for the expectation. - */ - const error = new Error(result.message); - error.message = result.message; - error.matcherName = result.matcherName; - throw error; - } - }; - - const throwUnlessFactory = function(actual, spec) { - return j$.private.Expectation.factory({ - matchersUtil: runableResources.makeMatchersUtil(), - customMatchers: runableResources.customMatchers(), - actual: actual, - addExpectationResult: handleThrowUnlessFailure - }); - }; - - const throwUnlessAsyncFactory = function(actual, spec) { - return j$.private.Expectation.asyncFactory({ - matchersUtil: runableResources.makeMatchersUtil(), - customAsyncMatchers: runableResources.customAsyncMatchers(), - actual: actual, - addExpectationResult: handleThrowUnlessFailure - }); - }; - - // TODO: Unify recordLateError with recordLateExpectation? The extra - // diagnostic info added by the latter is probably useful in most cases. - function recordLateError(error) { - const isExpectationResult = - error.matcherName !== undefined && error.passed !== undefined; - const result = isExpectationResult - ? error - : j$.private.buildExpectationResult({ - error, - passed: false, - matcherName: '', - expected: '', - actual: '' - }); - routeLateFailure(result); - } - - function recordLateExpectation(runable, runableType, result) { - const delayedExpectationResult = {}; - Object.keys(result).forEach(function(k) { - delayedExpectationResult[k] = result[k]; - }); - delayedExpectationResult.passed = false; - delayedExpectationResult.globalErrorType = 'lateExpectation'; - delayedExpectationResult.message = - runableType + - ' "' + - runable.getFullName() + - '" ran a "' + - result.matcherName + - '" expectation after it finished.\n'; - - if (result.message) { - delayedExpectationResult.message += - 'Message: "' + result.message + '"\n'; - } - - delayedExpectationResult.message += - '1. Did you forget to return or await the result of expectAsync?\n' + - '2. Was done() invoked before an async operation completed?\n' + - '3. Did an expectation follow a call to done()?'; - - topSuite.addExpectationResult(false, delayedExpectationResult); - } - - function routeLateFailure(expectationResult) { - // Report the result on the nearest ancestor suite that hasn't already - // been reported done. - for (let r = runner.currentRunable(); r; r = r.parentSuite) { - if (!r.reportedDone) { - if (r === topSuite) { - expectationResult.globalErrorType = 'lateError'; - } - - r.addExpectationResult(false, expectationResult); - return; - } - } - - // If we get here, all results have been reported and there's nothing we - // can do except log the result and hope the user sees it. - // eslint-disable-next-line no-console - console.error('Jasmine received a result after the suite finished:'); - // eslint-disable-next-line no-console - console.error(expectationResult); - } - - const asyncExpectationFactory = function(actual, spec, runableType) { - return j$.private.Expectation.asyncFactory({ - matchersUtil: runableResources.makeMatchersUtil(), - customAsyncMatchers: runableResources.customAsyncMatchers(), - actual: actual, - addExpectationResult: addExpectationResult - }); - - function addExpectationResult(passed, result) { - if (runner.currentRunable() !== spec) { - recordLateExpectation(spec, runableType, result); - } - return spec.addExpectationResult(passed, result); - } - }; - - /** - * Causes a deprecation warning to be logged to the console and reported to - * reporters. - * - * The optional second parameter is an object that can have either of the - * following properties: - * - * omitStackTrace: Whether to omit the stack trace. Optional. Defaults to - * false. This option is ignored if the deprecation is an Error. Set this - * when the stack trace will not contain anything that helps the user find - * the source of the deprecation. - * - * ignoreRunnable: Whether to log the deprecation on the root suite, ignoring - * the spec or suite that's running when it happens. Optional. Defaults to - * false. - * - * @name Env#deprecated - * @since 2.99 - * @function - * @param {String|Error} deprecation The deprecation message - * @param {Object} [options] Optional extra options, as described above - */ - Object.defineProperty(this, 'deprecated', { - enumerable: true, - value: function(deprecation, options) { - const runable = runner.currentRunable() || topSuite; - deprecator.addDeprecationWarning(runable, deprecation, options); - } - }); - - function runQueue(options) { - options.clearStack = options.clearStack || stackClearer; - options.timeout = { - setTimeout: realSetTimeout, - clearTimeout: realClearTimeout - }; - options.fail = self.fail; - options.globalErrors = globalErrors; - options.onException = - options.onException || - function(e) { - (runner.currentRunable() || topSuite).handleException(e); - }; - - new j$.private.QueueRunner(options).execute(); - } - - const suiteBuilder = new j$.private.SuiteBuilder({ - env: this, - expectationFactory, - asyncExpectationFactory, - onLateError: recordLateError, - runQueue - }); - topSuite = suiteBuilder.topSuite; - const deprecator = - envOptions?.deprecator ?? new j$.private.Deprecator(topSuite); - - /** - * Provides the root suite, through which all suites and specs can be - * accessed. - * @function - * @name Env#topSuite - * @return {Suite} the root suite - * @since 2.0.0 - */ - this.topSuite = function() { - ensureNonParallel('topSuite'); - return topSuite.metadata; - }; - - /** - * This represents the available reporter callback for an object passed to {@link Env#addReporter}. - * @interface Reporter - * @see custom_reporter - */ - reportDispatcher = new j$.private.ReportDispatcher( - j$.private.reporterEvents, - function(options) { - options.SkipPolicy = j$.private.NeverSkipPolicy; - return runQueue(options); - }, - recordLateError - ); - - runner = new j$.private.Runner({ - topSuite, - totalSpecsDefined: () => suiteBuilder.totalSpecsDefined, - focusedRunables: () => suiteBuilder.focusedRunables, - runableResources, - reportDispatcher, - runQueue, - TreeProcessor: j$.private.TreeProcessor, - globalErrors, - getConfig: () => config - }); - - this.setParallelLoadingState = function(state) { - parallelLoadingState = state; - }; - - this.parallelReset = function() { - suiteBuilder.parallelReset(); - runner.parallelReset(); - }; - - /** - * Executes the specs. - * - * If called with no parameter or with a falsy parameter, - * all specs will be executed except those that are excluded by a - * [spec filter]{@link Configuration#specFilter} or other mechanism. If the - * parameter is a list of spec/suite IDs, only those specs/suites will - * be run. - * - * execute should not be called more than once unless the env has been - * configured with `{autoCleanClosures: false}`. - * - * execute returns a promise. The promise will be resolved to the same - * {@link JasmineDoneInfo|overall result} that's passed to a reporter's - * `jasmineDone` method, even if the suite did not pass. To determine - * whether the suite passed, check the value that the promise resolves to - * or use a {@link Reporter}. The promise will be rejected in the case of - * certain serious errors that prevent execution from starting. - * - * @name Env#execute - * @since 2.0.0 - * @function - * @async - * @param {(string[])=} runablesToRun IDs of suites and/or specs to run - * @return {Promise} - */ - this.execute = async function(runablesToRun) { - installGlobalErrors(); - - // Karma incorrectly loads jasmine-core as an ES module. It isn't one, - // and we don't test that configuration. Warn about it. - if (j$.private.loadedAsBrowserEsm) { - this.deprecated( - "jasmine-core isn't an ES module but it was loaded as one. This is not a supported configuration." - ); - } - - if (parallelLoadingState) { - validateConfigForParallel(); - } - - const result = await runner.execute(runablesToRun); - this.cleanup_(); - return result; - }; - - /** - * Add a custom reporter to the Jasmine environment. - * @name Env#addReporter - * @since 2.0.0 - * @function - * @param {Reporter} reporterToAdd The reporter to be added. - * @see custom_reporter - */ - this.addReporter = function(reporterToAdd) { - if (parallelLoadingState) { - throw new Error('Reporters cannot be added via Env in parallel mode'); - } - - reportDispatcher.addReporter(reporterToAdd); - }; - - /** - * Provide a fallback reporter if no other reporters have been specified. - * @name Env#provideFallbackReporter - * @since 2.5.0 - * @function - * @param {Reporter} reporterToAdd The reporter - * @see custom_reporter - */ - this.provideFallbackReporter = function(reporterToAdd) { - reportDispatcher.provideFallbackReporter(reporterToAdd); - }; - - /** - * Clear all registered reporters - * @name Env#clearReporters - * @since 2.5.2 - * @function - */ - this.clearReporters = function() { - if (parallelLoadingState) { - throw new Error('Reporters cannot be removed via Env in parallel mode'); - } - - reportDispatcher.clearReporters(); - }; - - /** - * Configures whether Jasmine should allow the same function to be spied on - * more than once during the execution of a spec. By default, spying on - * a function that is already a spy will cause an error. - * @name Env#allowRespy - * @function - * @since 2.5.0 - * @param {boolean} allow Whether to allow respying - */ - this.allowRespy = function(allow) { - runableResources.spyRegistry.allowRespy(allow); - }; - - this.spyOn = function() { - return runableResources.spyRegistry.spyOn.apply( - runableResources.spyRegistry, - arguments - ); - }; - - this.spyOnProperty = function() { - return runableResources.spyRegistry.spyOnProperty.apply( - runableResources.spyRegistry, - arguments - ); - }; - - this.spyOnAllFunctions = function() { - return runableResources.spyRegistry.spyOnAllFunctions.apply( - runableResources.spyRegistry, - arguments - ); - }; - - this.createSpy = function(name, originalFn) { - return runableResources.spyFactory.createSpy(name, originalFn); - }; - - this.createSpyObj = function(baseName, methodNames, propertyNames) { - return runableResources.spyFactory.createSpyObj( - baseName, - methodNames, - propertyNames - ); - }; - - this.spyOnGlobalErrorsAsync = async function(fn) { - const spy = this.createSpy('global error handler'); - const associatedRunable = runner.currentRunable(); - let cleanedUp = false; - - globalErrors.setOverrideListener(spy, () => { - if (!cleanedUp) { - const message = - 'Global error spy was not uninstalled. (Did you ' + - 'forget to await the return value of spyOnGlobalErrorsAsync?)'; - associatedRunable.addExpectationResult(false, { - matcherName: '', - passed: false, - expected: '', - actual: '', - message, - error: null - }); - } - - cleanedUp = true; - }); - - try { - const maybePromise = fn(spy); - - if (!j$.private.isPromiseLike(maybePromise)) { - throw new Error( - 'The callback to spyOnGlobalErrorsAsync must be an async or promise-returning function' - ); - } - - await maybePromise; - } finally { - if (!cleanedUp) { - cleanedUp = true; - globalErrors.removeOverrideListener(); - } - } - }; - - function ensureIsNotNested(method) { - const runable = runner.currentRunable(); - if (runable !== null && runable !== undefined) { - throw new Error( - "'" + method + "' should only be used in 'describe' function" - ); - } - } - - function ensureNonParallel(method) { - if (parallelLoadingState) { - throw new Error(`'${method}' is not available in parallel mode`); - } - } - - function ensureNonParallelOrInDescribe(msg) { - if (parallelLoadingState && !suiteBuilder.inDescribe()) { - throw new Error(msg); - } - } - - function ensureNonParallelOrInHelperOrInDescribe(method) { - if (parallelLoadingState === 'specs' && !suiteBuilder.inDescribe()) { - throw new Error( - 'In parallel mode, ' + - method + - ' must be in a describe block or in a helper file' - ); - } - } - - function validateConfigForParallel() { - if (!config.random) { - throw new Error('Randomization cannot be disabled in parallel mode'); - } - - if (config.seed !== null && config.seed !== undefined) { - throw new Error('Random seed cannot be set in parallel mode'); - } - } - - this.describe = function(description, definitionFn) { - ensureIsNotNested('describe'); - const filename = indirectCallerFilename(describeStackDepth()); - return suiteBuilder.describe(description, definitionFn, filename) - .metadata; - }; - - this.xdescribe = function(description, definitionFn) { - ensureIsNotNested('xdescribe'); - const filename = indirectCallerFilename(describeStackDepth()); - return suiteBuilder.xdescribe(description, definitionFn, filename) - .metadata; - }; - - this.fdescribe = function(description, definitionFn) { - ensureIsNotNested('fdescribe'); - ensureNonParallel('fdescribe'); - const filename = indirectCallerFilename(describeStackDepth()); - return suiteBuilder.fdescribe(description, definitionFn, filename) - .metadata; - }; - - this.it = function(description, fn, timeout) { - ensureIsNotNested('it'); - const filename = indirectCallerFilename(itStackDepth()); - return suiteBuilder.it(description, fn, timeout, filename).metadata; - }; - - this.xit = function(description, fn, timeout) { - ensureIsNotNested('xit'); - const filename = indirectCallerFilename(itStackDepth()); - return suiteBuilder.xit(description, fn, timeout, filename).metadata; - }; - - this.fit = function(description, fn, timeout) { - ensureIsNotNested('fit'); - ensureNonParallel('fit'); - const filename = indirectCallerFilename(itStackDepth()); - return suiteBuilder.fit(description, fn, timeout, filename).metadata; - }; - - function itStackDepth() { - return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraItStackFrames; - } - - function describeStackDepth() { - return DEFAULT_IT_DESCRIBE_STACK_DEPTH + config.extraDescribeStackFrames; - } - - /** - * Get a user-defined property as part of the properties field of {@link SpecDoneEvent} - * @name Env#getSpecProperty - * @since 5.10.0 - * @function - * @param {String} key The name of the property - * @returns {*} The value of the property - */ - this.getSpecProperty = function(key) { - if ( - !runner.currentRunable() || - runner.currentRunable() == runner.currentSuite() - ) { - throw new Error( - "'getSpecProperty' was used when there was no current spec" - ); - } - return runner.currentRunable().getSpecProperty(key); - }; - - /** - * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} - * @name Env#setSpecProperty - * @since 3.6.0 - * @function - * @param {String} key The name of the property - * @param {*} value The value of the property - */ - this.setSpecProperty = function(key, value) { - if ( - !runner.currentRunable() || - runner.currentRunable() == runner.currentSuite() - ) { - throw new Error( - "'setSpecProperty' was used when there was no current spec" - ); - } - runner.currentRunable().setSpecProperty(key, value); - }; - - /** - * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} - * @name Env#setSuiteProperty - * @since 3.6.0 - * @function - * @param {String} key The name of the property - * @param {*} value The value of the property - */ - this.setSuiteProperty = function(key, value) { - if (!runner.currentSuite()) { - throw new Error( - "'setSuiteProperty' was used when there was no current suite" - ); - } - runner.currentSuite().setSuiteProperty(key, value); - }; - - this.debugLog = function(msg) { - const maybeSpec = runner.currentRunable(); - - if (!maybeSpec || !maybeSpec.debugLog) { - throw new Error("'debugLog' was called when there was no current spec"); - } - - maybeSpec.debugLog(msg); - }; - - this.expect = function(actual) { - const runable = runner.currentRunable(); - - if (!runable) { - throw new Error( - "'expect' was used when there was no current spec, this could be because an asynchronous test timed out" - ); - } - - return runable.expectationFactory(actual, runable); - }; - - this.expectAsync = function(actual) { - const runable = runner.currentRunable(); - - if (!runable) { - throw new Error( - "'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out" - ); - } - - return runable.asyncExpectationFactory(actual, runable); - }; - - this.throwUnless = function(actual) { - const runable = runner.currentRunable(); - return throwUnlessFactory(actual, runable); - }; - - this.throwUnlessAsync = function(actual) { - const runable = runner.currentRunable(); - return throwUnlessAsyncFactory(actual, runable); - }; - - this.beforeEach = function(beforeEachFunction, timeout) { - ensureIsNotNested('beforeEach'); - ensureNonParallelOrInHelperOrInDescribe('beforeEach'); - suiteBuilder.beforeEach(beforeEachFunction, timeout); - }; - - this.beforeAll = function(beforeAllFunction, timeout) { - ensureIsNotNested('beforeAll'); - // This message is -npm-specific, but currently parallel operation is - // only supported via -npm. - ensureNonParallelOrInDescribe( - "In parallel mode, 'beforeAll' " + - 'must be in a describe block. Use the globalSetup config ' + - 'property for exactly-once setup in parallel mode.' - ); - suiteBuilder.beforeAll(beforeAllFunction, timeout); - }; - - this.afterEach = function(afterEachFunction, timeout) { - ensureIsNotNested('afterEach'); - ensureNonParallelOrInHelperOrInDescribe('afterEach'); - suiteBuilder.afterEach(afterEachFunction, timeout); - }; - - this.afterAll = function(afterAllFunction, timeout) { - ensureIsNotNested('afterAll'); - // This message is -npm-specific, but currently parallel operation is - // only supported via -npm. - ensureNonParallelOrInDescribe( - "In parallel mode, 'afterAll' " + - 'must be in a describe block. Use the globalTeardown config ' + - 'property for exactly-once teardown in parallel mode.' - ); - suiteBuilder.afterAll(afterAllFunction, timeout); - }; - - this.pending = function(message) { - let fullMessage = j$.private.Spec.pendingSpecExceptionMessage; - if (message) { - fullMessage += message; - } - throw fullMessage; - }; - - this.fail = function(error) { - if (!runner.currentRunable()) { - throw new Error( - "'fail' was used when there was no current spec, this could be because an asynchronous test timed out" - ); - } - - let message = 'Failed'; - if (error) { - message += ': '; - if (error.message) { - message += error.message; - } else if (j$.private.isString(error)) { - message += error; - } else { - // pretty print all kind of objects. This includes arrays. - const pp = runableResources.makePrettyPrinter(); - message += pp(error); - } - } - - runner.currentRunable().addExpectationResult(false, { - matcherName: '', - passed: false, - expected: '', - actual: '', - message: message, - error: error && error.message ? error : null - }); - - if (config.stopSpecOnExpectationFailure) { - throw new Error(message); - } - }; - - this.pp = function(value) { - const pp = runner.currentRunable() - ? runableResources.makePrettyPrinter() - : j$.private.basicPrettyPrinter; - return pp(value); - }; - - this.cleanup_ = function() { - uninstallGlobalErrors(); - }; - - j$.private.deprecateMonkeyPatching(this, ['deprecated']); - } - - function indirectCallerFilename(depth) { - const frames = new j$.private.StackTrace(new Error()).frames; - // The specified frame should always exist except in Jasmine's own tests, - // which bypass the global it/describe layer, but could be absent in case - // of misconfiguration. Don't crash if it's absent. - return frames[depth] && frames[depth].file; - } - - return Env; -}; - -getJasmineRequireObj().JsApiReporter = function(j$) { - 'use strict'; - - // TODO: remove in 7.0. - /** - * @name jsApiReporter - * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object. - * @class - * @hideconstructor - * @deprecated In most cases jsApiReporter can simply be removed. If necessary, it can be replaced with a {@link Reporter|custom reporter}. - */ - function JsApiReporter(options) { - const timer = options.timer || new j$.Timer(); - let status = 'loaded'; - - this.started = false; - this.finished = false; - this.runDetails = {}; - - this.jasmineStarted = function() { - this.started = true; - status = 'started'; - timer.start(); - }; - - let executionTime; - - this.jasmineDone = function(runDetails) { - this.finished = true; - this.runDetails = runDetails; - executionTime = timer.elapsed(); - status = 'done'; - }; - - /** - * Get the current status for the Jasmine environment. - * @name jsApiReporter#status - * @since 2.0.0 - * @function - * @return {String} - One of `loaded`, `started`, or `done` - */ - this.status = function() { - return status; - }; - - const suites = [], - suites_hash = {}; - - this.suiteStarted = function(result) { - suites_hash[result.id] = result; - }; - - this.suiteDone = function(result) { - storeSuite(result); - }; - - /** - * Get the results for a set of suites. - * - * Retrievable in slices for easier serialization. - * @name jsApiReporter#suiteResults - * @since 2.1.0 - * @function - * @param {Number} index - The position in the suites list to start from. - * @param {Number} length - Maximum number of suite results to return. - * @return {SuiteResult[]} - */ - this.suiteResults = function(index, length) { - return suites.slice(index, index + length); - }; - - function storeSuite(result) { - suites.push(result); - suites_hash[result.id] = result; - } - - /** - * Get all of the suites in a single object, with their `id` as the key. - * @name jsApiReporter#suites - * @since 2.0.0 - * @function - * @return {Object} - Map of suite id to {@link SuiteResult} - */ - this.suites = function() { - return suites_hash; - }; - - const specs = []; - - this.specDone = function(result) { - specs.push(result); - }; - - /** - * Get the results for a set of specs. - * - * Retrievable in slices for easier serialization. - * @name jsApiReporter#specResults - * @since 2.0.0 - * @function - * @param {Number} index - The position in the specs list to start from. - * @param {Number} length - Maximum number of specs results to return. - * @return {SpecDoneEvent[]} - */ - this.specResults = function(index, length) { - return specs.slice(index, index + length); - }; - - /** - * Get all spec results. - * @name jsApiReporter#specs - * @since 2.0.0 - * @function - * @return {SpecDoneEvent[]} - */ - this.specs = function() { - return specs; - }; - - /** - * Get the number of milliseconds it took for the full Jasmine suite to run. - * @name jsApiReporter#executionTime - * @since 2.0.0 - * @function - * @return {Number} - */ - this.executionTime = function() { - return executionTime; - }; - } - - return JsApiReporter; -}; - -getJasmineRequireObj().AllOf = function(j$) { - 'use strict'; - - function AllOf() { - const expectedValues = Array.from(arguments); - if (expectedValues.length === 0) { - throw new TypeError( - 'jasmine.allOf() expects at least one argument to be passed.' - ); - } - this.expectedValues = expectedValues; - } - - AllOf.prototype.asymmetricMatch = function(other, matchersUtil) { - for (const expectedValue of this.expectedValues) { - if (!matchersUtil.equals(other, expectedValue)) { - return false; - } - } - - return true; - }; - - AllOf.prototype.jasmineToString = function(pp) { - return ''; - }; - - return AllOf; -}; - -getJasmineRequireObj().Any = function(j$) { - 'use strict'; - - function Any(expectedObject) { - if (typeof expectedObject === 'undefined') { - throw new TypeError( - 'jasmine.any() expects to be passed a constructor function. ' + - 'Please pass one or use jasmine.anything() to match any object.' - ); - } - this.expectedObject = expectedObject; - } - - Any.prototype.asymmetricMatch = function(other) { - if (this.expectedObject == String) { - return typeof other == 'string' || other instanceof String; - } - - if (this.expectedObject == Number) { - return typeof other == 'number' || other instanceof Number; - } - - if (this.expectedObject == Function) { - return typeof other == 'function' || other instanceof Function; - } - - if (this.expectedObject == Object) { - return other !== null && typeof other == 'object'; - } - - if (this.expectedObject == Boolean) { - return typeof other == 'boolean'; - } - - if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) { - return typeof other == 'symbol'; - } - - return other instanceof this.expectedObject; - }; - - Any.prototype.jasmineToString = function() { - return ''; - }; - - return Any; -}; - -getJasmineRequireObj().Anything = function(j$) { - 'use strict'; - - function Anything() {} - - Anything.prototype.asymmetricMatch = function(other) { - return other !== undefined && other !== null; - }; - - Anything.prototype.jasmineToString = function() { - return ''; - }; - - return Anything; -}; - -getJasmineRequireObj().ArrayContaining = function(j$) { - 'use strict'; - - function ArrayContaining(sample) { - this.sample = sample; - } - - ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) { - if (!Array.isArray(this.sample)) { - throw new Error( - 'You must provide an array to arrayContaining, not ' + - j$.private.basicPrettyPrinter(this.sample) + - '.' - ); - } - - // If the actual parameter is not an array, we can fail immediately, since it couldn't - // possibly be an "array containing" anything. However, we also want an empty sample - // array to match anything, so we need to double-check we aren't in that case - if (!Array.isArray(other) && this.sample.length > 0) { - return false; - } - - for (const item of this.sample) { - if (!matchersUtil.contains(other, item)) { - return false; - } - } - - return true; - }; - - ArrayContaining.prototype.jasmineToString = function(pp) { - return ''; - }; - - return ArrayContaining; -}; - -getJasmineRequireObj().ArrayWithExactContents = function(j$) { - 'use strict'; - - function ArrayWithExactContents(sample) { - this.sample = sample; - } - - ArrayWithExactContents.prototype.asymmetricMatch = function( - other, - matchersUtil - ) { - if (!Array.isArray(this.sample)) { - throw new Error( - 'You must provide an array to arrayWithExactContents, not ' + - j$.private.basicPrettyPrinter(this.sample) + - '.' - ); - } - - if (this.sample.length !== other.length) { - return false; - } - - for (const item of this.sample) { - if (!matchersUtil.contains(other, item)) { - return false; - } - } - - return true; - }; - - ArrayWithExactContents.prototype.jasmineToString = function(pp) { - return ''; - }; - - return ArrayWithExactContents; -}; - -getJasmineRequireObj().Empty = function(j$) { - 'use strict'; - - function Empty() {} - - Empty.prototype.asymmetricMatch = function(other) { - if ( - j$.private.isString(other) || - Array.isArray(other) || - j$.private.isTypedArray(other) - ) { - return other.length === 0; - } - - if (j$.private.isMap(other) || j$.private.isSet(other)) { - return other.size === 0; - } - - if (j$.private.isObject(other)) { - return Object.keys(other).length === 0; - } - return false; - }; - - Empty.prototype.jasmineToString = function() { - return ''; - }; - - return Empty; -}; - -getJasmineRequireObj().Falsy = function(j$) { - 'use strict'; - - function Falsy() {} - - Falsy.prototype.asymmetricMatch = function(other) { - return !other; - }; - - Falsy.prototype.jasmineToString = function() { - return ''; - }; - - return Falsy; -}; - -getJasmineRequireObj().Is = function(j$) { - 'use strict'; - - class Is { - constructor(expected) { - this.expected_ = expected; - } - - asymmetricMatch(actual) { - return actual === this.expected_; - } - - jasmineToString(pp) { - return ``; - } - } - - return Is; -}; - -getJasmineRequireObj().MapContaining = function(j$) { - 'use strict'; - - function MapContaining(sample) { - if (!j$.private.isMap(sample)) { - throw new Error( - 'You must provide a map to `mapContaining`, not ' + - j$.private.basicPrettyPrinter(sample) - ); - } - - this.sample = sample; - } - - MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) { - if (!j$.private.isMap(other)) { - return false; - } - - for (const [key, value] of this.sample) { - // for each key/value pair in `sample` - // there should be at least one pair in `other` whose key and value both match - let hasMatch = false; - for (const [oKey, oValue] of other) { - if ( - matchersUtil.equals(oKey, key) && - matchersUtil.equals(oValue, value) - ) { - hasMatch = true; - break; - } - } - - if (!hasMatch) { - return false; - } - } - - return true; - }; - - MapContaining.prototype.jasmineToString = function(pp) { - return ''; - }; - - return MapContaining; -}; - -getJasmineRequireObj().NotEmpty = function(j$) { - 'use strict'; - - function NotEmpty() {} - - NotEmpty.prototype.asymmetricMatch = function(other) { - if ( - j$.private.isString(other) || - Array.isArray(other) || - j$.private.isTypedArray(other) - ) { - return other.length !== 0; - } - - if (j$.private.isMap(other) || j$.private.isSet(other)) { - return other.size !== 0; - } - - if (j$.private.isObject(other)) { - return Object.keys(other).length !== 0; - } - - return false; - }; - - NotEmpty.prototype.jasmineToString = function() { - return ''; - }; - - return NotEmpty; -}; - -getJasmineRequireObj().ObjectContaining = function(j$) { - 'use strict'; - - function ObjectContaining(sample) { - this.sample = sample; - } - - function hasProperty(obj, property) { - if (!obj || typeof obj !== 'object') { - return false; - } - - if (Object.prototype.hasOwnProperty.call(obj, property)) { - return true; - } - - return hasProperty(Object.getPrototypeOf(obj), property); - } - - ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) { - if (typeof this.sample !== 'object') { - throw new Error( - "You must provide an object to objectContaining, not '" + - this.sample + - "'." - ); - } - if (typeof other !== 'object') { - return false; - } - - for (const property in this.sample) { - if ( - !hasProperty(other, property) || - !matchersUtil.equals(this.sample[property], other[property]) - ) { - return false; - } - } - - return true; - }; - - ObjectContaining.prototype.valuesForDiff_ = function(other, pp) { - if (!j$.private.isObject(other)) { - return { - self: this.jasmineToString(pp), - other: other - }; - } - - const filteredOther = {}; - Object.keys(this.sample).forEach(function(k) { - // eq short-circuits comparison of objects that have different key sets, - // so include all keys even if undefined. - filteredOther[k] = other[k]; - }); - - return { - self: this.sample, - other: filteredOther - }; - }; - - ObjectContaining.prototype.jasmineToString = function(pp) { - return ''; - }; - - return ObjectContaining; -}; - -getJasmineRequireObj().SetContaining = function(j$) { - 'use strict'; - - function SetContaining(sample) { - if (!j$.private.isSet(sample)) { - throw new Error( - 'You must provide a set to `setContaining`, not ' + - j$.private.basicPrettyPrinter(sample) - ); - } - - this.sample = sample; - } - - SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) { - if (!j$.private.isSet(other)) { - return false; - } - - for (const item of this.sample) { - // for each item in `sample` there should be at least one matching item in `other` - // (not using `matchersUtil.contains` because it compares set members by reference, - // not by deep value equality) - let hasMatch = false; - for (const oItem of other) { - if (matchersUtil.equals(oItem, item)) { - hasMatch = true; - break; - } - } - - if (!hasMatch) { - return false; - } - } - - return true; - }; - - SetContaining.prototype.jasmineToString = function(pp) { - return ''; - }; - - return SetContaining; -}; - -getJasmineRequireObj().StringContaining = function(j$) { - 'use strict'; - - function StringContaining(expected) { - if (!j$.private.isString(expected)) { - throw new Error('Expected is not a String'); - } - - this.expected = expected; - } - - StringContaining.prototype.asymmetricMatch = function(other) { - if (!j$.private.isString(other)) { - // Arrays, etc. don't match no matter what their indexOf returns. - return false; - } - - return other.indexOf(this.expected) !== -1; - }; - - StringContaining.prototype.jasmineToString = function() { - return ''; - }; - - return StringContaining; -}; - -getJasmineRequireObj().StringMatching = function(j$) { - 'use strict'; - - function StringMatching(expected) { - if (!j$.private.isString(expected) && !j$.private.isA('RegExp', expected)) { - throw new Error('Expected is not a String or a RegExp'); - } - - this.regexp = new RegExp(expected); - } - - StringMatching.prototype.asymmetricMatch = function(other) { - return this.regexp.test(other); - }; - - StringMatching.prototype.jasmineToString = function() { - return ''; - }; - - return StringMatching; -}; - -getJasmineRequireObj().Truthy = function(j$) { - 'use strict'; - - function Truthy() {} - - Truthy.prototype.asymmetricMatch = function(other) { - return !!other; - }; - - Truthy.prototype.jasmineToString = function() { - return ''; - }; - - return Truthy; -}; - -//TODO: expectation result may make more sense as a presentation of an expectation. -getJasmineRequireObj().buildExpectationResult = function(j$) { - 'use strict'; - - function buildExpectationResult(options) { - const exceptionFormatter = new j$.private.ExceptionFormatter(); - - /** - * Describes the result of evaluating an expectation - * - * @typedef ExpectationResult - * @property {String} matcherName - The name of the matcher that was executed for this expectation. - * @property {String} message - The failure message for the expectation. - * @property {String} stack - The stack trace for the failure if available. - * @property {Boolean} passed - Whether the expectation passed or failed. - * @property {String|undefined} globalErrorType - The type of an error that - * is reported on the top suite. Valid values are undefined, "afterAll", - * "load", "lateExpectation", and "lateError". - */ - const result = { - matcherName: options.matcherName, - message: message(), - stack: options.omitStackTrace ? '' : stack(), - passed: options.passed, - globalErrorType: options.globalErrorType - }; - - if (options.filename !== undefined) { - result.filename = options.filename; - } - if (options.lineno !== undefined) { - result.lineno = options.lineno; - } - - if (!result.passed) { - if (options.error && !j$.private.isString(options.error)) { - if ('code' in options.error) { - result.code = options.error.code; - } - - if (options.error.code === 'ERR_ASSERTION') { - result.matcherName = 'assert ' + options.error.operator; - } - } - } - - return result; - - function message() { - if (options.passed) { - return 'Passed.'; - } else if (options.message) { - return options.message; - } else if (options.error) { - return exceptionFormatter.message(options.error); - } - return ''; - } - - function stack() { - if (options.passed) { - return ''; - } - - let error = options.error; - - if (!error) { - if (options.errorForStack) { - error = options.errorForStack; - } else if (options.stack) { - error = options; - } else { - error = new Error(message()); - } - } - // Omit the message from the stack trace because it will be - // included elsewhere. - return exceptionFormatter.stack(error, { omitMessage: true }); - } - } - - return buildExpectationResult; -}; - -getJasmineRequireObj().CallTracker = function(j$) { - 'use strict'; - - /** - * @namespace Spy#calls - * @since 2.0.0 - */ - function CallTracker() { - let calls = []; - const opts = {}; - - this.track = function(context) { - if (opts.cloneArgs) { - context.args = opts.argsCloner(context.args); - } - calls.push(context); - }; - - /** - * Check whether this spy has been invoked. - * @name Spy#calls#any - * @since 2.0.0 - * @function - * @return {Boolean} - */ - this.any = function() { - return !!calls.length; - }; - - /** - * Get the number of invocations of this spy. - * @name Spy#calls#count - * @since 2.0.0 - * @function - * @return {Integer} - */ - this.count = function() { - return calls.length; - }; - - /** - * Get the arguments that were passed to a specific invocation of this spy. - * @name Spy#calls#argsFor - * @since 2.0.0 - * @function - * @param {Integer} index The 0-based invocation index. - * @return {Array} - */ - this.argsFor = function(index) { - const call = calls[index]; - return call ? call.args : []; - }; - - /** - * Get the "this" object that was passed to a specific invocation of this spy. - * @name Spy#calls#thisFor - * @since 3.8.0 - * @function - * @param {Integer} index The 0-based invocation index. - * @return {Object?} - */ - this.thisFor = function(index) { - const call = calls[index]; - return call ? call.object : undefined; - }; - - /** - * Get the raw calls array for this spy. - * @name Spy#calls#all - * @since 2.0.0 - * @function - * @return {Spy.callData[]} - */ - this.all = function() { - return calls; - }; - - /** - * Get all of the arguments for each invocation of this spy in the order they were received. - * @name Spy#calls#allArgs - * @since 2.0.0 - * @function - * @return {Array} - */ - this.allArgs = function() { - return calls.map(c => c.args); - }; - - /** - * Get the first invocation of this spy. - * @name Spy#calls#first - * @since 2.0.0 - * @function - * @return {ObjecSpy.callData} - */ - this.first = function() { - return calls[0]; - }; - - /** - * Get the most recent invocation of this spy. - * @name Spy#calls#mostRecent - * @since 2.0.0 - * @function - * @return {ObjecSpy.callData} - */ - this.mostRecent = function() { - return calls[calls.length - 1]; - }; - - /** - * Reset this spy as if it has never been called. - * @name Spy#calls#reset - * @since 2.0.0 - * @function - */ - this.reset = function() { - calls = []; - }; - - /** - * Set this spy to do a clone of arguments passed to each invocation. - * @name Spy#calls#saveArgumentsByValue - * @since 2.5.0 - * @param {Function} [argsCloner] A function to use to clone the arguments. Defaults to a shallow cloning function. - * @function - */ - this.saveArgumentsByValue = function( - argsCloner = j$.private.util.cloneArgs - ) { - opts.cloneArgs = true; - opts.argsCloner = argsCloner; - }; - - this.unverifiedCount = function() { - return calls.reduce((count, call) => count + (call.verified ? 0 : 1), 0); - }; - } - - return CallTracker; -}; - -getJasmineRequireObj().Clock = function(j$) { - 'use strict'; - - /* global process */ - const NODE_JS = - typeof process !== 'undefined' && - process.versions && - typeof process.versions.node === 'string'; - - const IsMockClockTimingFn = Symbol('IsMockClockTimingFn'); - - /** - * @class Clock - * @since 1.3.0 - * @classdesc Jasmine's mock clock is used when testing time dependent code.
- * _Note:_ Do not construct this directly. You can get the current clock with - * {@link jasmine.clock}. - * @hideconstructor - */ - function Clock(global, delayedFunctionSchedulerFactory, mockDate) { - const realTimingFunctions = { - setTimeout: global.setTimeout, - clearTimeout: global.clearTimeout, - setInterval: global.setInterval, - clearInterval: global.clearInterval - }; - const fakeTimingFunctions = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setInterval: setInterval, - clearInterval: clearInterval - }; - let installed = false; - let delayedFunctionScheduler; - let timer; - // Tracks how the clock ticking behaves. - // By default, the clock only ticks when the user manually calls a tick method. - // There is also an 'auto' mode which will advance the clock automatically to - // to the next task. Once enabled, there is currently no mechanism for users - // to disable the auto ticking. - let tickMode = { - mode: 'manual', - counter: 0 - }; - - this.FakeTimeout = FakeTimeout; - - /** - * Install the mock clock over the built-in methods. - * @name Clock#install - * @since 2.0.0 - * @function - * @return {Clock} - */ - this.install = function() { - if (!originalTimingFunctionsIntact()) { - throw new Error( - 'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?' - ); - } - replace(global, fakeTimingFunctions); - timer = fakeTimingFunctions; - delayedFunctionScheduler = delayedFunctionSchedulerFactory(); - installed = true; - - return this; - }; - - /** - * Uninstall the mock clock, returning the built-in methods to their places. - * @name Clock#uninstall - * @since 2.0.0 - * @function - */ - this.uninstall = function() { - // Ensure auto ticking loop is aborted when clock is uninstalled - if (tickMode.mode === 'auto') { - tickMode = { mode: 'manual', counter: tickMode.counter + 1 }; - } - delayedFunctionScheduler = null; - mockDate.uninstall(); - replace(global, realTimingFunctions); - - timer = realTimingFunctions; - installed = false; - }; - - /** - * Execute a function with a mocked Clock - * - * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes. - * @name Clock#withMock - * @since 2.3.0 - * @function - * @param {Function} closure The function to be called. - */ - this.withMock = function(closure) { - this.install(); - try { - closure(); - } finally { - this.uninstall(); - } - }; - - /** - * Instruct the installed Clock to also mock the date returned by `new Date()` - * @name Clock#mockDate - * @since 2.1.0 - * @function - * @param {Date} [initialDate=now] The `Date` to provide. - */ - this.mockDate = function(initialDate) { - mockDate.install(initialDate); - }; - - this.setTimeout = function(fn, delay, params) { - return Function.prototype.apply.apply(timer.setTimeout, [ - global, - arguments - ]); - }; - - this.setInterval = function(fn, delay, params) { - return Function.prototype.apply.apply(timer.setInterval, [ - global, - arguments - ]); - }; - - this.clearTimeout = function(id) { - return Function.prototype.call.apply(timer.clearTimeout, [global, id]); - }; - - this.clearInterval = function(id) { - return Function.prototype.call.apply(timer.clearInterval, [global, id]); - }; - - /** - * Tick the Clock forward, running any enqueued timeouts along the way - * @name Clock#tick - * @since 1.3.0 - * @function - * @param {int} millis The number of milliseconds to tick. - */ - this.tick = function(millis) { - if (installed) { - delayedFunctionScheduler.tick(millis, function(millis) { - mockDate.tick(millis); - }); - } else { - throw new Error( - 'Mock clock is not installed, use jasmine.clock().install()' - ); - } - }; - - /** - * Updates the clock to automatically advance time. - * - * With this mode, the clock advances to the first scheduled timer and fires it, in a loop. - * Between each timer, it will also break the event loop, allowing any scheduled promise -callbacks to execute _before_ running the next one. - * - * This mode allows tests to be authored in a way that does not need to be aware of the - * mock clock. Consequently, tests which have been authored without a mock clock installed - * can one with auto tick enabled without any other updates to the test logic. - * - * In many cases, this can greatly improve test execution speed because asynchronous tasks - * will execute as quickly as possible rather than waiting real time to complete. - * - * Furthermore, tests can be authored in a consistent manner. They can always be written in an asynchronous style - * rather than having `tick` sprinkled throughout the tests with mock time in order to manually - * advance the clock. - * - * When auto tick is enabled, `tick` can still be used to synchronously advance the clock if necessary. - * @name Clock#autoTick - * @function - * @since 5.7.0 - */ - this.autoTick = function() { - if (tickMode.mode === 'auto') { - return; - } - - tickMode = { mode: 'auto', counter: tickMode.counter + 1 }; - advanceUntilModeChanges(); - }; - - setTimeout[IsMockClockTimingFn] = true; - clearTimeout[IsMockClockTimingFn] = true; - setInterval[IsMockClockTimingFn] = true; - clearInterval[IsMockClockTimingFn] = true; - - j$.private.deprecateMonkeyPatching(this); - - return this; - - // Advances the Clock's time until the mode changes. - // - // The time is advanced asynchronously, giving microtasks and events a chance - // to run before each timer runs. - // - // @function - // @return {!Promise} - async function advanceUntilModeChanges() { - if (!installed) { - throw new Error( - 'Mock clock is not installed, use jasmine.clock().install()' - ); - } - const { counter } = tickMode; - - while (true) { - await newMacrotask(); - - if ( - tickMode.counter !== counter || - !installed || - delayedFunctionScheduler === null - ) { - return; - } - - if (!delayedFunctionScheduler.isEmpty()) { - delayedFunctionScheduler.runNextQueuedFunction(function(millis) { - mockDate.tick(millis); - }); - } - } - } - - // Waits until a new macro task. - // - // Used with autoTick(), which is meant to act when the test is waiting, we need - // to insert ourselves in the macro task queue. - // - // @return {!Promise} - async function newMacrotask() { - if (NODE_JS) { - // setImmediate is generally faster than setTimeout in Node - // https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick#setimmediate-vs-settimeout - return new Promise(resolve => void setImmediate(resolve)); - } - - // MessageChannel ensures that setTimeout is not throttled to 4ms. - // https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified - // https://stackblitz.com/edit/stackblitz-starters-qtlpcc - // Note: This trick does not work in Safari, which will still throttle the setTimeout - const channel = new MessageChannel(); - await new Promise(resolve => { - channel.port1.onmessage = resolve; - channel.port2.postMessage(undefined); - }); - channel.port1.close(); - channel.port2.close(); - // setTimeout ensures that we interleave with other setTimeouts. - await new Promise(resolve => { - realTimingFunctions.setTimeout.call(global, resolve); - }); - } - - function originalTimingFunctionsIntact() { - return ( - global.setTimeout === realTimingFunctions.setTimeout && - global.clearTimeout === realTimingFunctions.clearTimeout && - global.setInterval === realTimingFunctions.setInterval && - global.clearInterval === realTimingFunctions.clearInterval - ); - } - - function replace(dest, source) { - for (const prop in source) { - dest[prop] = source[prop]; - } - } - - function setTimeout(fn, delay) { - if (!NODE_JS) { - return delayedFunctionScheduler.scheduleFunction( - fn, - delay, - argSlice(arguments, 2) - ); - } - - const timeout = new FakeTimeout(); - - delayedFunctionScheduler.scheduleFunction( - fn, - delay, - argSlice(arguments, 2), - false, - timeout - ); - - return timeout; - } - - function clearTimeout(id) { - return delayedFunctionScheduler.removeFunctionWithId(id); - } - - function setInterval(fn, interval) { - if (!NODE_JS) { - return delayedFunctionScheduler.scheduleFunction( - fn, - interval, - argSlice(arguments, 2), - true - ); - } - - const timeout = new FakeTimeout(); - - delayedFunctionScheduler.scheduleFunction( - fn, - interval, - argSlice(arguments, 2), - true, - timeout - ); - - return timeout; - } - - function clearInterval(id) { - return delayedFunctionScheduler.removeFunctionWithId(id); - } - - function argSlice(argsObj, n) { - return Array.prototype.slice.call(argsObj, n); - } - } - - /** - * Mocks Node.js Timeout class - */ - function FakeTimeout() {} - - FakeTimeout.prototype.ref = function() { - return this; - }; - - FakeTimeout.prototype.unref = function() { - return this; - }; - - Clock.IsMockClockTimingFn = IsMockClockTimingFn; - return Clock; -}; - -getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { - 'use strict'; - - function CompleteOnFirstErrorSkipPolicy(queueableFns) { - this.queueableFns_ = queueableFns; - this.erroredFnIx_ = null; - } - - CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { - let i; - - for ( - i = lastRanFnIx + 1; - i < this.queueableFns_.length && this.shouldSkip_(i); - i++ - ) {} - return i; - }; - - CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { - this.erroredFnIx_ = fnIx; - }; - - CompleteOnFirstErrorSkipPolicy.prototype.shouldSkip_ = function(fnIx) { - if (this.erroredFnIx_ === null) { - return false; - } - - const fn = this.queueableFns_[fnIx]; - const candidateSuite = fn.suite; - const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; - const wasCleanupFn = - fn.type === 'afterEach' || - fn.type === 'afterAll' || - fn.type === 'specCleanup'; - return ( - !wasCleanupFn || - (candidateSuite && isDescendent(candidateSuite, errorSuite)) - ); - }; - - function isDescendent(candidate, ancestor) { - if (!candidate.parentSuite) { - return false; - } else if (candidate.parentSuite === ancestor) { - return true; - } else { - return isDescendent(candidate.parentSuite, ancestor); - } - } - - return CompleteOnFirstErrorSkipPolicy; -}; - -getJasmineRequireObj().Configuration = function(j$) { - 'use strict'; - - /** - * This represents the available options to configure Jasmine. - * Options that are not provided will use their default values. - * @see Env#configure - * @interface Configuration - * @since 3.3.0 - */ - const defaultConfig = { - /** - * Whether to randomize spec execution order - * @name Configuration#random - * @since 3.3.0 - * @type Boolean - * @default true - */ - random: true, - /** - * Seed to use as the basis of randomization. - * Null causes the seed to be determined randomly at the start of execution. - * @name Configuration#seed - * @since 3.3.0 - * @type (number|string) - * @default null - */ - seed: null, - /** - * Whether to stop execution of the suite after the first spec failure - * - *

In parallel mode, `stopOnSpecFailure` works on a "best effort" - * basis. Jasmine will stop execution as soon as practical after a failure - * but it might not be immediate.

- * @name Configuration#stopOnSpecFailure - * @since 3.9.0 - * @type Boolean - * @default false - */ - stopOnSpecFailure: false, - /** - * Whether to fail the spec if it ran no expectations. By default - * a spec that ran no expectations is reported as passed. Setting this - * to true will report such spec as a failure. - * @name Configuration#failSpecWithNoExpectations - * @since 3.5.0 - * @type Boolean - * @default false - */ - failSpecWithNoExpectations: false, - /** - * Whether to cause specs to only have one expectation failure. - * @name Configuration#stopSpecOnExpectationFailure - * @since 3.3.0 - * @type Boolean - * @default false - */ - stopSpecOnExpectationFailure: false, - /** - * A function that takes a spec and returns true if it should be executed - * or false if it should be skipped. - * @callback SpecFilter - * @param {Spec} spec - The spec that the filter is being applied to. - * @return boolean - */ - /** - * Function to use to filter specs - * @name Configuration#specFilter - * @since 3.3.0 - * @type SpecFilter - * @default A function that always returns true. - */ - specFilter: function() { - return true; - }, - - // TODO: remove hideDisabled when HtmlReporter is removed - /** - * Whether reporters should hide disabled specs from their output. - * Currently only supported by Jasmine's HTMLReporter - * @name Configuration#hideDisabled - * @since 3.3.0 - * @type Boolean - * @default false - * @deprecated - */ - hideDisabled: false, - /** - * Clean closures when a suite is done running (done by clearing the stored function reference). - * This prevents memory leaks, but you won't be able to run jasmine multiple times. - * @name Configuration#autoCleanClosures - * @since 3.10.0 - * @type boolean - * @default true - */ - autoCleanClosures: true, - /** - * Whether to forbid duplicate spec or suite names. If set to true, using - * the same name multiple times in the same immediate parent suite is an - * error. - * @name Configuration#forbidDuplicateNames - * @type boolean - * @default true - */ - forbidDuplicateNames: true, - /** - * Whether to issue warnings for certain deprecated functionality - * every time it's used. If not set or set to false, deprecation warnings - * for methods that tend to be called frequently will be issued only once - * or otherwise throttled to prevent the suite output from being flooded - * with warnings. - * @name Configuration#verboseDeprecations - * @since 3.6.0 - * @type Boolean - * @default false - */ - verboseDeprecations: false, - - /** - * Whether to detect late promise rejection handling during spec - * execution. If this option is enabled, a promise rejection that triggers - * the JavaScript runtime's unhandled rejection event will not be treated - * as an error as long as it's handled before the spec finishes. - * - * This option is off by default because it imposes a performance penalty. - * @name Configuration#detectLateRejectionHandling - * @since 5.10.0 - * @type Boolean - * @default false - */ - detectLateRejectionHandling: false, - - /** - * The number of extra stack frames inserted by a wrapper around {@link it} - * or by some other local modification. Jasmine uses this to determine the - * filename for {@link SpecStartedEvent} and {@link SpecDoneEvent}. - * @name Configuration#extraItStackFrames - * @since 5.13.0 - * @type number - * @default 0 - */ - extraItStackFrames: 0, - - /** - * The number of extra stack frames inserted by a wrapper around - * {@link describe} or by some other local modification. Jasmine uses this - * to determine the filename for {@link SpecStartedEvent} and - * {@link SpecDoneEvent}. - * @name Configuration#extraDescribeStackFrames - * @since 5.13.0 - * @type number - * @default 0 - */ - extraDescribeStackFrames: 0, - - /** - * The strategy to use in Safari and similar browsers to determine how often - * to yield control by calling setTimeout. If set to "count", the default, - * the frequency of setTimeout calls is based on the number of relevant - * function calls. If set to "time", the frequency of setTimeout calls is - * based on elapsed time. Using "time" may provide a significant performance - * improvement, but as of 6.0 it hasn't been tested with a wide variety of - * workloads and should be considered experimental. - * @name Configuration#safariYieldStrategy - * @since 6.0.0 - * @type 'count' | 'time' - * @default 'count' - */ - safariYieldStrategy: 'count' - }; - Object.freeze(defaultConfig); - - class Configuration { - #values; - - constructor() { - this.#values = { ...defaultConfig }; - - for (const k of Object.keys(defaultConfig)) { - Object.defineProperty(this, k, { - enumerable: true, - get() { - return this.#values[k]; - } - }); - } - } - - copy() { - return { ...this.#values }; - } - - update(changes) { - const booleanProps = [ - 'random', - 'failSpecWithNoExpectations', - 'hideDisabled', - 'stopOnSpecFailure', - 'stopSpecOnExpectationFailure', - 'autoCleanClosures', - 'forbidDuplicateNames', - 'detectLateRejectionHandling', - 'verboseDeprecations' - ]; - - for (const k of booleanProps) { - if (typeof changes[k] !== 'undefined') { - this.#values[k] = changes[k]; - } - } - - if (changes.specFilter) { - this.#values.specFilter = changes.specFilter; - } - - // 0 and null are valid values, so a truthiness check wouldn't work - if (typeof changes.seed !== 'undefined') { - this.#values.seed = changes.seed; - } - - // 0 is a valid value for both of these, so a truthiness check wouldn't work - if (typeof changes.extraItStackFrames !== 'undefined') { - this.#values.extraItStackFrames = changes.extraItStackFrames; - } - - if (typeof changes.extraDescribeStackFrames !== 'undefined') { - this.#values.extraDescribeStackFrames = - changes.extraDescribeStackFrames; - } - - if (typeof changes.safariYieldStrategy !== 'undefined') { - const v = changes.safariYieldStrategy; - - if (v === 'count' || v === 'time') { - this.#values.safariYieldStrategy = v; - } else { - throw new Error( - "Invalid safariYieldStrategy value. Valid values are 'count' and 'time'." - ); - } - } - } - } - - return Configuration; -}; - -getJasmineRequireObj().CurrentRunableTracker = function() { - 'use strict'; - - class CurrentRunableTracker { - #currentSpec; - #currentlyExecutingSuites; - - constructor() { - this.#currentlyExecutingSuites = []; - } - - currentRunable() { - return this.currentSpec() || this.currentSuite(); - } - - currentSpec() { - return this.#currentSpec; - } - - setCurrentSpec(spec) { - this.#currentSpec = spec; - } - - currentSuite() { - return this.#currentlyExecutingSuites[ - this.#currentlyExecutingSuites.length - 1 - ]; - } - - pushSuite(suite) { - this.#currentlyExecutingSuites.push(suite); - } - - popSuite() { - this.#currentlyExecutingSuites.pop(); - } - } - - return CurrentRunableTracker; -}; - -getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { - 'use strict'; - - function DelayedFunctionScheduler() { - this.scheduledLookup_ = []; - this.scheduledFunctions_ = {}; - this.currentTime_ = 0; - this.delayedFnStartCount_ = 1e12; // arbitrarily large number to avoid collisions with native timer IDs; - this.deletedKeys_ = []; - - this.tick = function(millis, tickDate) { - millis = millis || 0; - const endTime = this.currentTime_ + millis; - - this.runScheduledFunctions_(endTime, tickDate); - }; - - this.scheduleFunction = function( - funcToCall, - millis, - params, - recurring, - timeoutKey, - runAtMillis - ) { - if (typeof funcToCall === 'string') { - throw new Error( - 'The mock clock does not support the eval form of setTimeout and setInterval. Pass a function instead of a string.' - ); - } - - millis = millis || 0; - timeoutKey = timeoutKey || ++this.delayedFnStartCount_; - runAtMillis = runAtMillis || this.currentTime_ + millis; - - const funcToSchedule = { - runAtMillis: runAtMillis, - funcToCall, - recurring: recurring, - params: params, - timeoutKey: timeoutKey, - millis: millis - }; - - if (runAtMillis in this.scheduledFunctions_) { - this.scheduledFunctions_[runAtMillis].push(funcToSchedule); - } else { - this.scheduledFunctions_[runAtMillis] = [funcToSchedule]; - this.scheduledLookup_.push(runAtMillis); - this.scheduledLookup_.sort(function(a, b) { - return a - b; - }); - } - - return timeoutKey; - }; - - this.removeFunctionWithId = function(timeoutKey) { - this.deletedKeys_.push(timeoutKey); - - for (const runAtMillis in this.scheduledFunctions_) { - const funcs = this.scheduledFunctions_[runAtMillis]; - const i = indexOfFirstToPass(funcs, function(func) { - return func.timeoutKey === timeoutKey; - }); - - if (i > -1) { - if (funcs.length === 1) { - delete this.scheduledFunctions_[runAtMillis]; - this.deleteFromLookup_(runAtMillis); - } else { - funcs.splice(i, 1); - } - - // intervals get rescheduled when executed, so there's never more - // than a single scheduled function with a given timeoutKey - break; - } - } - }; - - // Returns whether there are any scheduled functions. - // Returns true if there are any scheduled functions, otherwise false. - this.isEmpty = function() { - return this.scheduledFunctions_.length === 0; - }; - - // Runs the next timeout in the queue, advancing the clock. - this.runNextQueuedFunction = function(tickDate) { - if (this.scheduledLookup_.length === 0) { - return; - } - - const newCurrentTime = this.scheduledLookup_[0]; - if (newCurrentTime >= this.currentTime_) { - tickDate(newCurrentTime - this.currentTime_); - this.currentTime_ = newCurrentTime; - } - - const funcsAtTime = this.scheduledFunctions_[this.currentTime_]; - const fn = funcsAtTime.shift(); - if (funcsAtTime.length === 0) { - delete this.scheduledFunctions_[this.currentTime_]; - this.scheduledLookup_.splice(0, 1); - } - - if (fn.recurring) { - this.reschedule_(fn); - } - fn.funcToCall.apply(null, fn.params || []); - }; - - return this; - } - - DelayedFunctionScheduler.prototype.runScheduledFunctions_ = function( - endTime, - tickDate - ) { - tickDate = tickDate || function() {}; - if ( - this.scheduledLookup_.length === 0 || - this.scheduledLookup_[0] > endTime - ) { - if (endTime >= this.currentTime_) { - tickDate(endTime - this.currentTime_); - this.currentTime_ = endTime; - } - return; - } - - do { - this.deletedKeys_ = []; - const newCurrentTime = this.scheduledLookup_.shift(); - if (newCurrentTime >= this.currentTime_) { - tickDate(newCurrentTime - this.currentTime_); - this.currentTime_ = newCurrentTime; - } - - const funcsToRun = this.scheduledFunctions_[this.currentTime_]; - - delete this.scheduledFunctions_[this.currentTime_]; - - for (const fn of funcsToRun) { - if (fn.recurring) { - this.reschedule_(fn); - } - } - - for (const fn of funcsToRun) { - if (this.deletedKeys_.includes(fn.timeoutKey)) { - // skip a timeoutKey deleted whilst we were running - return; - } - fn.funcToCall.apply(null, fn.params || []); - } - this.deletedKeys_ = []; - } while ( - this.scheduledLookup_.length > 0 && - // checking first if we're out of time prevents setTimeout(0) - // scheduled in a funcToRun from forcing an extra iteration - this.currentTime_ !== endTime && - this.scheduledLookup_[0] <= endTime - ); - - // ran out of functions to call, but still time left on the clock - if (endTime >= this.currentTime_) { - tickDate(endTime - this.currentTime_); - this.currentTime_ = endTime; - } - }; - - DelayedFunctionScheduler.prototype.reschedule_ = function(scheduledFn) { - this.scheduleFunction( - scheduledFn.funcToCall, - scheduledFn.millis, - scheduledFn.params, - true, - scheduledFn.timeoutKey, - scheduledFn.runAtMillis + scheduledFn.millis - ); - }; - - DelayedFunctionScheduler.prototype.deleteFromLookup_ = function(key) { - const value = Number(key); - const i = indexOfFirstToPass(this.scheduledLookup_, function(millis) { - return millis === value; - }); - - if (i > -1) { - this.scheduledLookup_.splice(i, 1); - } - }; - - function indexOfFirstToPass(array, testFn) { - let index = -1; - - for (let i = 0; i < array.length; ++i) { - if (testFn(array[i])) { - index = i; - break; - } - } - - return index; - } - - return DelayedFunctionScheduler; -}; - -getJasmineRequireObj().deprecateMonkeyPatching = function(j$) { - return function deprecateMonkeyPatching(obj, keysToSkip) { - for (const key of Object.keys(obj)) { - if (!keysToSkip?.includes(key)) { - let value = obj[key]; - - Object.defineProperty(obj, key, { - enumerable: key in obj, - get() { - return value; - }, - set(newValue) { - j$.getEnv().deprecated( - 'Monkey patching detected. Code that overwrites parts of Jasmine, except globala and other properties that are documented as writeable, is not supported and will break in a future release.' - ); - value = newValue; - } - }); - } - } - }; -}; - -getJasmineRequireObj().Deprecator = function(j$) { - 'use strict'; - - function Deprecator(topSuite) { - this.topSuite_ = topSuite; - this.verbose_ = false; - this.toSuppress_ = []; - } - - const verboseNote = - 'Note: This message will be shown only once. Set the verboseDeprecations ' + - 'config property to true to see every occurrence.'; - - Deprecator.prototype.verboseDeprecations = function(enabled) { - this.verbose_ = enabled; - }; - - // runnable is a spec or a suite. - // deprecation is a string or an Error. - // See Env#deprecated for a description of the options argument. - Deprecator.prototype.addDeprecationWarning = function( - runnable, - deprecation, - options - ) { - options = options || {}; - - if (!this.verbose_ && !j$.private.isError(deprecation)) { - if (this.toSuppress_.indexOf(deprecation) !== -1) { - return; - } - this.toSuppress_.push(deprecation); - } - - this.log_(runnable, deprecation, options); - this.report_(runnable, deprecation, options); - }; - - Deprecator.prototype.log_ = function(runnable, deprecation, options) { - if (j$.private.isError(deprecation)) { - // eslint-disable-next-line no-console - console.error(deprecation); - return; - } - - let context; - - if (runnable === this.topSuite_ || options.ignoreRunnable) { - context = ''; - } else if (runnable.children) { - context = ' (in suite: ' + runnable.getFullName() + ')'; - } else { - context = ' (in spec: ' + runnable.getFullName() + ')'; - } - - if (!options.omitStackTrace) { - context += '\n' + this.stackTrace_(); - } - - if (!this.verbose_) { - context += '\n' + verboseNote; - } - - // eslint-disable-next-line no-console - console.error('DEPRECATION: ' + deprecation + context); - }; - - Deprecator.prototype.stackTrace_ = function() { - const formatter = new j$.private.ExceptionFormatter(); - return formatter.stack(new Error()).replace(/^Error\n/m, ''); - }; - - Deprecator.prototype.report_ = function(runnable, deprecation, options) { - if (options.ignoreRunnable) { - runnable = this.topSuite_; - } - - if (j$.private.isError(deprecation)) { - runnable.addDeprecationWarning(deprecation); - return; - } - - if (!this.verbose_) { - deprecation += '\n' + verboseNote; - } - - runnable.addDeprecationWarning({ - message: deprecation, - omitStackTrace: options.omitStackTrace || false - }); - }; - - return Deprecator; -}; - -getJasmineRequireObj().errors = function() { - 'use strict'; - - function ExpectationFailed() {} - - ExpectationFailed.prototype = new Error(); - ExpectationFailed.prototype.constructor = ExpectationFailed; - - return { - ExpectationFailed: ExpectationFailed - }; -}; - -getJasmineRequireObj().ExceptionFormatter = function(j$) { - 'use strict'; - - const ignoredProperties = [ - 'name', - 'message', - 'stack', - 'fileName', - 'sourceURL', - 'line', - 'lineNumber', - 'column', - 'description', - 'jasmineMessage' - ]; - - function ExceptionFormatter(options) { - const jasmineFile = - (options && options.jasmineFile) || j$.private.util.jasmineFile(); - this.message = function(error) { - let message = ''; - - if (error.jasmineMessage) { - message += error.jasmineMessage; - } else if (error.name && error.message) { - message += error.name + ': ' + error.message; - } else if (error.message) { - message += error.message; - } else { - message += error.toString() + ' thrown'; - } - - if (error.fileName || error.sourceURL) { - message += ' in ' + (error.fileName || error.sourceURL); - } - - if (error.line || error.lineNumber) { - message += ' (line ' + (error.line || error.lineNumber) + ')'; - } - - return message; - }; - - this.stack = function(error, { omitMessage } = {}) { - if (!error || !error.stack) { - return null; - } - - const lines = this.stack_(error, { - messageHandling: omitMessage ? 'omit' : undefined - }); - return lines.join('\n'); - }; - - // messageHandling can be falsy (unspecified), 'omit', or 'require' - this.stack_ = function(error, { messageHandling }) { - let lines = formatProperties(error).split('\n'); - - if (lines[lines.length - 1] === '') { - lines.pop(); - } - - const stackTrace = new j$.private.StackTrace(error); - lines = lines.concat(filterJasmine(stackTrace)); - - if (messageHandling === 'require') { - lines.unshift(stackTrace.message || 'Error: ' + error.message); - } else if (messageHandling !== 'omit' && stackTrace.message) { - lines.unshift(stackTrace.message); - } - - if (error.cause && error.cause instanceof Error) { - const substack = this.stack_(error.cause, { - messageHandling: 'require' - }); - substack[0] = 'Caused by: ' + substack[0]; - lines = lines.concat(substack); - } - - return lines; - }; - - function filterJasmine(stackTrace) { - const result = []; - const jasmineMarker = - stackTrace.style === 'webkit' ? '' : ' at '; - - stackTrace.frames.forEach(function(frame) { - if (frame.file !== jasmineFile) { - result.push(frame.raw); - } else if (result[result.length - 1] !== jasmineMarker) { - result.push(jasmineMarker); - } - }); - - return result; - } - - function formatProperties(error) { - if (!(error instanceof Object)) { - return; - } - - const result = {}; - let empty = true; - - for (const prop of Object.keys(error)) { - if (ignoredProperties.includes(prop)) { - continue; - } - result[prop] = error[prop]; - empty = false; - } - - if (!empty) { - return ( - 'error properties: ' + j$.private.basicPrettyPrinter(result) + '\n' - ); - } - - return ''; - } - } - - return ExceptionFormatter; -}; - -getJasmineRequireObj().Expectation = function(j$) { - 'use strict'; - - /** - * Matchers that come with Jasmine out of the box. - * @namespace matchers - */ - function Expectation(options) { - this.expector = new j$.private.Expector(options); - - const customMatchers = options.customMatchers || {}; - for (const matcherName in customMatchers) { - this[matcherName] = wrapSyncCompare( - matcherName, - customMatchers[matcherName] - ); - } - } - - /** - * Add some context to be included in matcher failures for an - * {@link expect|expectation}, so that it can be more easily distinguished - * from similar expectations. - * @function - * @name matchers#withContext - * @since 3.3.0 - * @param {String} message - Additional context to show when the matcher fails - * @return {matchers} - * @example - * expect(things[0]).withContext('thing 0').toEqual('a'); - * expect(things[1]).withContext('thing 1').toEqual('b'); - */ - Expectation.prototype.withContext = function withContext(message) { - return addFilter(this, new ContextAddingFilter(message)); - }; - - /** - * Invert the matcher following this {@link expect|expectation} - * @member - * @name matchers#not - * @since 1.3.0 - * @type {matchers} - * @example - * expect(something).not.toBe(true); - */ - Object.defineProperty(Expectation.prototype, 'not', { - get: function() { - return addFilter(this, syncNegatingFilter); - } - }); - - /** - * Asynchronous matchers that operate on an actual value which is a promise, - * and return a promise. - * - * Most async matchers will wait indefinitely for the promise to be resolved - * or rejected, resulting in a spec timeout if that never happens. If you - * expect that the promise will already be resolved or rejected at the time - * the matcher is called, you can use the {@link async-matchers#already} - * modifier to get a faster failure with a more helpful message. - * - * Note: Specs must await the result of each async matcher, return the - * promise returned by the matcher, or return a promise that's derived from - * the one returned by the matcher. Otherwise the matcher will not be - * evaluated before the spec completes. - * - * @example - * // Good - * await expectAsync(aPromise).toBeResolved(); - * @example - * // Good - * return expectAsync(aPromise).toBeResolved(); - * @example - * // Good - * return expectAsync(aPromise).toBeResolved() - * .then(function() { - * // more spec code - * }); - * @example - * // Bad - * expectAsync(aPromise).toBeResolved(); - * @namespace async-matchers - */ - function AsyncExpectation(options) { - this.expector = new j$.private.Expector(options); - - const customAsyncMatchers = options.customAsyncMatchers || {}; - for (const matcherName in customAsyncMatchers) { - this[matcherName] = wrapAsyncCompare( - matcherName, - customAsyncMatchers[matcherName] - ); - } - } - - /** - * Add some context for an {@link expectAsync} - * @function - * @name async-matchers#withContext - * @since 3.3.0 - * @param {String} message - Additional context to show when the async matcher fails - * @return {async-matchers} - */ - AsyncExpectation.prototype.withContext = function withContext(message) { - return addFilter(this, new ContextAddingFilter(message)); - }; - - /** - * Invert the matcher following this {@link expectAsync} - * @member - * @name async-matchers#not - * @type {async-matchers} - * @example - * await expectAsync(myPromise).not.toBeResolved(); - * @example - * return expectAsync(myPromise).not.toBeResolved(); - */ - Object.defineProperty(AsyncExpectation.prototype, 'not', { - get: function() { - return addFilter(this, asyncNegatingFilter); - } - }); - - /** - * Fail as soon as possible if the actual is pending. - * Otherwise evaluate the matcher. - * @member - * @name async-matchers#already - * @since 3.8.0 - * @type {async-matchers} - * @example - * await expectAsync(myPromise).already.toBeResolved(); - * @example - * return expectAsync(myPromise).already.toBeResolved(); - */ - Object.defineProperty(AsyncExpectation.prototype, 'already', { - get: function() { - return addFilter(this, expectSettledPromiseFilter); - } - }); - - function wrapSyncCompare(name, matcherFactory) { - return function() { - const result = this.expector.compare(name, matcherFactory, arguments); - this.expector.processResult(result); - }; - } - - function wrapAsyncCompare(name, matcherFactory) { - return function() { - // Capture the call stack here, before we go async, so that it will contain - // frames that are relevant to the user instead of just parts of Jasmine. - const errorForStack = new Error(); - - return this.expector - .compare(name, matcherFactory, arguments) - .then(result => { - this.expector.processResult(result, errorForStack); - }); - }; - } - - function addCoreMatchers(prototype, matchers, wrapper) { - for (const matcherName in matchers) { - const matcher = matchers[matcherName]; - prototype[matcherName] = wrapper(matcherName, matcher); - } - } - - function addFilter(source, filter) { - const result = Object.create(source); - result.expector = source.expector.addFilter(filter); - return result; - } - - function negatedFailureMessage(result, matcherName, args, matchersUtil) { - if (result.message) { - if (j$.private.isFunction(result.message)) { - return result.message(); - } else { - return result.message; - } - } - - args = args.slice(); - args.unshift(true); - args.unshift(matcherName); - return matchersUtil.buildFailureMessage.apply(matchersUtil, args); - } - - function negate(result) { - result.pass = !result.pass; - return result; - } - - const syncNegatingFilter = { - selectComparisonFunc: function(matcher) { - function defaultNegativeCompare() { - return negate(matcher.compare.apply(null, arguments)); - } - - return matcher.negativeCompare || defaultNegativeCompare; - }, - buildFailureMessage: negatedFailureMessage - }; - - const asyncNegatingFilter = { - selectComparisonFunc: function(matcher) { - function defaultNegativeCompare() { - return matcher.compare.apply(this, arguments).then(negate); - } - - return matcher.negativeCompare || defaultNegativeCompare; - }, - buildFailureMessage: negatedFailureMessage - }; - - const expectSettledPromiseFilter = { - selectComparisonFunc: function(matcher) { - return function(actual) { - const matcherArgs = arguments; - - return j$.private.isPending(actual).then(function(isPending) { - if (isPending) { - return { - pass: false, - message: - 'Expected a promise to be settled (via ' + - 'expectAsync(...).already) but it was pending.' - }; - } else { - return matcher.compare.apply(null, matcherArgs); - } - }); - }; - } - }; - - function ContextAddingFilter(message) { - this.message = message; - } - - ContextAddingFilter.prototype.modifyFailureMessage = function(msg) { - if (msg.indexOf('\n') === -1) { - return this.message + ': ' + msg; - } else { - return this.message + ':\n' + indent(msg); - } - }; - - function indent(s) { - return s.replace(/^/gm, ' '); - } - - return { - factory: function(options) { - return new Expectation(options || {}); - }, - addCoreMatchers: function(matchers) { - addCoreMatchers(Expectation.prototype, matchers, wrapSyncCompare); - }, - asyncFactory: function(options) { - return new AsyncExpectation(options || {}); - }, - addAsyncCoreMatchers: function(matchers) { - addCoreMatchers(AsyncExpectation.prototype, matchers, wrapAsyncCompare); - } - }; -}; - -getJasmineRequireObj().ExpectationFilterChain = function() { - 'use strict'; - - function ExpectationFilterChain(maybeFilter, prev) { - this.filter_ = maybeFilter; - this.prev_ = prev; - } - - ExpectationFilterChain.prototype.addFilter = function(filter) { - return new ExpectationFilterChain(filter, this); - }; - - ExpectationFilterChain.prototype.selectComparisonFunc = function(matcher) { - return this.callFirst_('selectComparisonFunc', arguments).result; - }; - - ExpectationFilterChain.prototype.buildFailureMessage = function( - result, - matcherName, - args, - matchersUtil - ) { - return this.callFirst_('buildFailureMessage', arguments).result; - }; - - ExpectationFilterChain.prototype.modifyFailureMessage = function(msg) { - const result = this.callFirst_('modifyFailureMessage', arguments).result; - return result || msg; - }; - - ExpectationFilterChain.prototype.callFirst_ = function(fname, args) { - if (this.prev_) { - const prevResult = this.prev_.callFirst_(fname, args); - - if (prevResult.found) { - return prevResult; - } - } - - if (this.filter_ && this.filter_[fname]) { - return { - found: true, - result: this.filter_[fname].apply(this.filter_, args) - }; - } - - return { found: false }; - }; - - return ExpectationFilterChain; -}; - -getJasmineRequireObj().Expector = function(j$) { - 'use strict'; - - function Expector(options) { - this.matchersUtil = options.matchersUtil || { - buildFailureMessage: function() {} - }; - this.actual = options.actual; - this.addExpectationResult = options.addExpectationResult || function() {}; - this.filters = new j$.private.ExpectationFilterChain(); - } - - Expector.prototype.instantiateMatcher = function( - matcherName, - matcherFactory, - args - ) { - this.matcherName = matcherName; - this.args = Array.prototype.slice.call(args, 0); - this.expected = this.args.slice(0); - - this.args.unshift(this.actual); - - const matcher = matcherFactory(this.matchersUtil); - - const comparisonFunc = this.filters.selectComparisonFunc(matcher); - return comparisonFunc || matcher.compare; - }; - - Expector.prototype.buildMessage = function(result) { - if (result.pass) { - return ''; - } - - const defaultMessage = () => { - if (!result.message) { - const args = this.args.slice(); - args.unshift(false); - args.unshift(this.matcherName); - return this.matchersUtil.buildFailureMessage.apply( - this.matchersUtil, - args - ); - } else if (j$.private.isFunction(result.message)) { - return result.message(); - } else { - return result.message; - } - }; - - const msg = this.filters.buildFailureMessage( - result, - this.matcherName, - this.args, - this.matchersUtil, - defaultMessage - ); - return this.filters.modifyFailureMessage(msg || defaultMessage()); - }; - - Expector.prototype.compare = function(matcherName, matcherFactory, args) { - const matcherCompare = this.instantiateMatcher( - matcherName, - matcherFactory, - args - ); - return matcherCompare.apply(null, this.args); - }; - - Expector.prototype.addFilter = function(filter) { - const result = Object.create(this); - result.filters = this.filters.addFilter(filter); - return result; - }; - - Expector.prototype.processResult = function(result, errorForStack) { - const message = this.buildMessage(result); - - if (this.expected.length === 1) { - this.expected = this.expected[0]; - } - - this.addExpectationResult(result.pass, { - matcherName: this.matcherName, - passed: result.pass, - message: message, - error: errorForStack ? undefined : result.error, - errorForStack: errorForStack || undefined - }); - }; - - return Expector; -}; - -getJasmineRequireObj().formatErrorMsg = function() { - 'use strict'; - - function generateErrorMsg(domain, usage) { - const usageDefinition = usage ? '\nUsage: ' + usage : ''; - - return function errorMsg(msg) { - return domain + ' : ' + msg + usageDefinition; - }; - } - - return generateErrorMsg; -}; - -getJasmineRequireObj().GlobalErrors = function(j$) { - 'use strict'; - - class GlobalErrors { - #getConfig; - #adapter; - #handlers; - #overrideHandler; - #onRemoveOverrideHandler; - #pendingUnhandledRejections; - - constructor(global, getConfig) { - global = global || j$.getGlobal(); - this.#getConfig = getConfig; - this.#pendingUnhandledRejections = new Map(); - this.#handlers = []; - this.#overrideHandler = null; - this.#onRemoveOverrideHandler = null; - - const dispatch = { - onUncaughtException: this.#onUncaughtException.bind(this), - onUnhandledRejection: this.#onUnhandledRejection.bind(this), - onRejectionHandled: this.#onRejectionHandled.bind(this) - }; - - if ( - global.process && - global.process.listeners && - j$.private.isFunction(global.process.on) - ) { - this.#adapter = new NodeAdapter(global, dispatch); - } else { - this.#adapter = new BrowserAdapter(global, dispatch); - } - } - - install() { - this.#adapter.install(); - } - - uninstall() { - this.#adapter.uninstall(); - } - - pushListener(listener) { - this.#handlers.push(listener); - } - - popListener(listener) { - if (!listener) { - throw new Error('popListener expects a listener'); - } - - this.#handlers.pop(); - } - - setOverrideListener(listener, onRemove) { - if (this.#overrideHandler) { - throw new Error("Can't set more than one override listener at a time"); - } - - this.#overrideHandler = listener; - this.#onRemoveOverrideHandler = onRemove; - } - - removeOverrideListener() { - if (this.#onRemoveOverrideHandler) { - this.#onRemoveOverrideHandler(); - } - - this.#overrideHandler = null; - this.#onRemoveOverrideHandler = null; - } - - reportUnhandledRejections() { - for (const { reason } of this.#pendingUnhandledRejections.values()) { - this.#dispatchError(reason); - } - - this.#pendingUnhandledRejections.clear(); - } - - #onUncaughtException(error) { - this.#dispatchError(error); - } - - // promise may be undefined - #onUnhandledRejection(reason, promise) { - if (this.#detectLateRejectionHandling() && promise) { - this.#pendingUnhandledRejections.set(promise, { reason }); - } else { - this.#dispatchError(reason); - } - } - - #detectLateRejectionHandling() { - return this.#getConfig().detectLateRejectionHandling; - } - - #onRejectionHandled(promise) { - this.#pendingUnhandledRejections.delete(promise); - } - - #dispatchError(error) { - if (this.#overrideHandler) { - // See discussion of spyOnGlobalErrorsAsync in base.js - this.#overrideHandler(error); - return; - } - - const handler = this.#handlers[this.#handlers.length - 1]; - - if (handler) { - handler(error); - } else { - throw error; - } - } - } - - class BrowserAdapter { - #global; - #dispatch; - #onError; - #onUnhandledRejection; - #onRejectionHandled; - - constructor(global, dispatch) { - this.#global = global; - this.#dispatch = dispatch; - this.#onError = this.#errorHandler.bind(this); - this.#onUnhandledRejection = this.#unhandledRejectionHandler.bind(this); - this.#onRejectionHandled = this.#rejectionHandledHandler.bind(this); - } - - install() { - this.#global.addEventListener('error', this.#onError); - this.#global.addEventListener( - 'unhandledrejection', - this.#onUnhandledRejection - ); - this.#global.addEventListener( - 'rejectionhandled', - this.#onRejectionHandled - ); - } - - uninstall() { - this.#global.removeEventListener('error', this.#onError); - this.#global.removeEventListener( - 'unhandledrejection', - this.#onUnhandledRejection - ); - this.#global.removeEventListener( - 'rejectionhandled', - this.#onRejectionHandled - ); - } - - #errorHandler(event) { - let error = event.error; - - // event.error isn't guaranteed to be present in all browser load-time - // error events. - if (!error) { - error = { - message: event.message, - stack: `@${event.filename}:${event.lineno}` - }; - } - - if (event.filename) { - // filename and lineno can be more convenient than stack when reporting - // things like syntax errors. Pass them along. - error.filename = event.filename; - error.lineno = event.lineno; - } - - this.#dispatch.onUncaughtException(error); - } - - #unhandledRejectionHandler(event) { - const jasmineMessage = 'Unhandled promise rejection: ' + event.reason; - let reason; - - if (j$.private.isError(event.reason)) { - reason = event.reason; - reason.jasmineMessage = jasmineMessage; - } else { - reason = jasmineMessage; - } - - this.#dispatch.onUnhandledRejection(reason, event.promise); - } - - #rejectionHandledHandler(event) { - this.#dispatch.onRejectionHandled(event.promise); - } - } - - class NodeAdapter { - #global; - #dispatch; - #originalHandlers; - #jasmineHandlers; - - constructor(global, dispatch) { - this.#global = global; - this.#dispatch = dispatch; - - this.#jasmineHandlers = {}; - this.#originalHandlers = {}; - - this.onError = this.onError.bind(this); - this.onUnhandledRejection = this.onUnhandledRejection.bind(this); - } - - install() { - this.#installHandler('uncaughtException', this.onError); - this.#installHandler('unhandledRejection', this.onUnhandledRejection); - this.#installHandler( - 'rejectionHandled', - this.#dispatch.onRejectionHandled - ); - } - - uninstall() { - const errorTypes = Object.keys(this.#originalHandlers); - for (const errorType of errorTypes) { - this.#global.process.removeListener( - errorType, - this.#jasmineHandlers[errorType] - ); - - for (let i = 0; i < this.#originalHandlers[errorType].length; i++) { - this.#global.process.on( - errorType, - this.#originalHandlers[errorType][i] - ); - } - delete this.#originalHandlers[errorType]; - delete this.#jasmineHandlers[errorType]; - } - } - - #installHandler(errorType, handler) { - this.#originalHandlers[errorType] = this.#global.process.listeners( - errorType - ); - this.#jasmineHandlers[errorType] = handler; - - this.#global.process.removeAllListeners(errorType); - this.#global.process.on(errorType, handler); - } - - #augmentError(error, isUnhandledRejection) { - let jasmineMessagePrefix; - - if (isUnhandledRejection) { - jasmineMessagePrefix = 'Unhandled promise rejection'; - } else { - jasmineMessagePrefix = 'Uncaught exception'; - } - - if (j$.private.isError(error)) { - error.jasmineMessage = jasmineMessagePrefix + ': ' + error; - return error; - } else { - let substituteMsg; - - if (error) { - substituteMsg = jasmineMessagePrefix + ': ' + error; - } else { - substituteMsg = jasmineMessagePrefix + ' with no error or message'; - } - - if (isUnhandledRejection) { - substituteMsg += - '\n' + - '(Tip: to get a useful stack trace, use ' + - 'Promise.reject(n' + - 'ew Error(...)) instead of Promise.reject(' + - (error ? '...' : '') + - ').)'; - } - - return new Error(substituteMsg); - } - } - - onError(error) { - error = this.#augmentError(error, false); - this.#dispatch.onUncaughtException(error); - } - - onUnhandledRejection(reason, promise) { - reason = this.#augmentError(reason, true); - this.#dispatch.onUnhandledRejection(reason, promise); - } - } - - return GlobalErrors; -}; - -getJasmineRequireObj().toBePending = function(j$) { - 'use strict'; - - /** - * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected. - * @function - * @async - * @name async-matchers#toBePending - * @since 3.6 - * @example - * await expectAsync(aPromise).toBePending(); - */ - return function toBePending() { - return { - compare: function(actual) { - if (!j$.private.isPromiseLike(actual)) { - throw new Error( - `Expected toBePending to be called on a promise but was on a ${typeof actual}.` - ); - } - const want = {}; - return Promise.race([actual, Promise.resolve(want)]).then( - function(got) { - return { pass: want === got }; - }, - function() { - return { pass: false }; - } - ); - } - }; - }; -}; - -getJasmineRequireObj().toBeRejected = function(j$) { - 'use strict'; - - /** - * Expect a promise to be rejected. - * @function - * @async - * @name async-matchers#toBeRejected - * @since 3.1.0 - * @example - * await expectAsync(aPromise).toBeRejected(); - * @example - * return expectAsync(aPromise).toBeRejected(); - */ - return function toBeRejected() { - return { - compare: function(actual) { - if (!j$.private.isPromiseLike(actual)) { - throw new Error( - `Expected toBeRejected to be called on a promise but was on a ${typeof actual}.` - ); - } - return actual.then( - function() { - return { pass: false }; - }, - function() { - return { pass: true }; - } - ); - } - }; - }; -}; - -getJasmineRequireObj().toBeRejectedWith = function(j$) { - 'use strict'; - - /** - * Expect a promise to be rejected with a value equal to the expected, using deep equality comparison. - * @function - * @async - * @name async-matchers#toBeRejectedWith - * @since 3.3.0 - * @param {Object} expected - Value that the promise is expected to be rejected with - * @example - * await expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); - * @example - * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); - */ - return function toBeRejectedWith(matchersUtil) { - return { - compare: function(actualPromise, expectedValue) { - if (!j$.private.isPromiseLike(actualPromise)) { - throw new Error( - `Expected toBeRejectedWith to be called on a promise but was on a ${typeof actualPromise}.` - ); - } - - function prefix(passed) { - return ( - 'Expected a promise ' + - (passed ? 'not ' : '') + - 'to be rejected with ' + - matchersUtil.pp(expectedValue) - ); - } - - return actualPromise.then( - function() { - return { - pass: false, - message: prefix(false) + ' but it was resolved.' - }; - }, - function(actualValue) { - if (matchersUtil.equals(actualValue, expectedValue)) { - return { - pass: true, - message: prefix(true) + '.' - }; - } else { - return { - pass: false, - message: - prefix(false) + - ' but it was rejected with ' + - matchersUtil.pp(actualValue) + - '.' - }; - } - } - ); - } - }; - }; -}; - -getJasmineRequireObj().toBeRejectedWithError = function(j$) { - 'use strict'; - - /** - * Expect a promise to be rejected with a value matched to the expected - * @function - * @async - * @name async-matchers#toBeRejectedWithError - * @since 3.5.0 - * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. - * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` - * @example - * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message'); - * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/); - * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError); - * await expectAsync(aPromise).toBeRejectedWithError('Error message'); - * return expectAsync(aPromise).toBeRejectedWithError(/Error message/); - */ - return function toBeRejectedWithError(matchersUtil) { - return { - compare: function(actualPromise, arg1, arg2) { - if (!j$.private.isPromiseLike(actualPromise)) { - throw new Error( - `Expected toBeRejectedWithError to be called on a promise but was on a ${typeof actualPromise}.` - ); - } - - const expected = getExpectedFromArgs(arg1, arg2, matchersUtil); - - return actualPromise.then( - function() { - return { - pass: false, - message: 'Expected a promise to be rejected but it was resolved.' - }; - }, - function(actualValue) { - return matchError(actualValue, expected, matchersUtil); - } - ); - } - }; - }; - - function matchError(actual, expected, matchersUtil) { - if (!j$.private.isError(actual)) { - return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); - } - - if (!(actual instanceof expected.error)) { - return fail( - expected, - 'rejected with type ' + j$.private.fnNameFor(actual.constructor) - ); - } - - const actualMessage = actual.message; - - if ( - actualMessage === expected.message || - typeof expected.message === 'undefined' - ) { - return pass(expected); - } - - if ( - expected.message instanceof RegExp && - expected.message.test(actualMessage) - ) { - return pass(expected); - } - - return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); - } - - function pass(expected) { - return { - pass: true, - message: - 'Expected a promise not to be rejected with ' + - expected.printValue + - ', but it was.' - }; - } - - function fail(expected, message) { - return { - pass: false, - message: - 'Expected a promise to be rejected with ' + - expected.printValue + - ' but it was ' + - message + - '.' - }; - } - - function getExpectedFromArgs(arg1, arg2, matchersUtil) { - let error, message; - - if (isErrorConstructor(arg1)) { - error = arg1; - message = arg2; - } else { - error = Error; - message = arg1; - } - - return { - error: error, - message: message, - printValue: - j$.private.fnNameFor(error) + - (typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message)) - }; - } - - function isErrorConstructor(value) { - return ( - typeof value === 'function' && - (value === Error || j$.private.isError(value.prototype)) - ); - } -}; - -getJasmineRequireObj().toBeResolved = function(j$) { - 'use strict'; - - /** - * Expect a promise to be resolved. - * @function - * @async - * @name async-matchers#toBeResolved - * @since 3.1.0 - * @example - * await expectAsync(aPromise).toBeResolved(); - * @example - * return expectAsync(aPromise).toBeResolved(); - */ - return function toBeResolved(matchersUtil) { - return { - compare: function(actual) { - if (!j$.private.isPromiseLike(actual)) { - throw new Error( - `Expected toBeResolved to be called on a promise but was on a ${typeof actual}.` - ); - } - - return actual.then( - function() { - return { pass: true }; - }, - function(e) { - return { - pass: false, - message: - 'Expected a promise to be resolved but it was ' + - 'rejected with ' + - matchersUtil.pp(e) + - '.' - }; - } - ); - } - }; - }; -}; - -getJasmineRequireObj().toBeResolvedTo = function(j$) { - 'use strict'; - - /** - * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison. - * @function - * @async - * @name async-matchers#toBeResolvedTo - * @since 3.1.0 - * @param {Object} expected - Value that the promise is expected to resolve to - * @example - * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); - * @example - * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); - */ - return function toBeResolvedTo(matchersUtil) { - return { - compare: function(actualPromise, expectedValue) { - if (!j$.private.isPromiseLike(actualPromise)) { - throw new Error( - `Expected toBeResolvedTo to be called on a promise but was on a ${typeof actualPromise}.` - ); - } - - function prefix(passed) { - return ( - 'Expected a promise ' + - (passed ? 'not ' : '') + - 'to be resolved to ' + - matchersUtil.pp(expectedValue) - ); - } - - return actualPromise.then( - function(actualValue) { - if (matchersUtil.equals(actualValue, expectedValue)) { - return { - pass: true, - message: prefix(true) + '.' - }; - } else { - return { - pass: false, - message: - prefix(false) + - ' but it was resolved to ' + - matchersUtil.pp(actualValue) + - '.' - }; - } - }, - function(e) { - return { - pass: false, - message: - prefix(false) + - ' but it was rejected with ' + - matchersUtil.pp(e) + - '.' - }; - } - ); - } - }; - }; -}; - -getJasmineRequireObj().DiffBuilder = function(j$) { - 'use strict'; - - class DiffBuilder { - constructor(config) { - this.prettyPrinter_ = - (config || {}).prettyPrinter || j$.private.makePrettyPrinter(); - this.mismatches_ = new j$.private.MismatchTree(); - this.path_ = new j$.private.ObjectPath(); - this.actualRoot_ = undefined; - this.expectedRoot_ = undefined; - } - - setRoots(actual, expected) { - this.actualRoot_ = actual; - this.expectedRoot_ = expected; - } - - recordMismatch(formatter) { - this.mismatches_.add(this.path_, formatter); - } - - getMessage() { - const messages = []; - - this.mismatches_.traverse((path, isLeaf, formatter) => { - const { actual, expected } = this.dereferencePath_(path); - - if (formatter) { - messages.push(formatter(actual, expected, path, this.prettyPrinter_)); - return true; - } - - const actualCustom = this.prettyPrinter_.customFormat_(actual); - const expectedCustom = this.prettyPrinter_.customFormat_(expected); - const useCustom = - actualCustom !== undefined || expectedCustom !== undefined; - - if (useCustom) { - const prettyActual = actualCustom || this.prettyPrinter_(actual); - const prettyExpected = - expectedCustom || this.prettyPrinter_(expected); - messages.push(wrapPrettyPrinted(prettyActual, prettyExpected, path)); - return false; // don't recurse further - } - - if (isLeaf) { - messages.push(this.defaultFormatter_(actual, expected, path)); - } - - return true; - }); - - return messages.join('\n'); - } - - withPath(pathComponent, block) { - const oldPath = this.path_; - this.path_ = this.path_.add(pathComponent); - block(); - this.path_ = oldPath; - } - - dereferencePath_(objectPath) { - let actual = this.actualRoot_; - let expected = this.expectedRoot_; - - const handleAsymmetricExpected = () => { - if ( - j$.private.isAsymmetricEqualityTester(expected) && - j$.private.isFunction(expected.valuesForDiff_) - ) { - const asymmetricResult = expected.valuesForDiff_( - actual, - this.prettyPrinter_ - ); - expected = asymmetricResult.self; - actual = asymmetricResult.other; - } - }; - - handleAsymmetricExpected(); - - for (const pc of objectPath.components) { - actual = actual[pc]; - expected = expected[pc]; - handleAsymmetricExpected(); - } - - return { actual: actual, expected: expected }; - } - - defaultFormatter_(actual, expected, path) { - return wrapPrettyPrinted( - this.prettyPrinter_(actual), - this.prettyPrinter_(expected), - path - ); - } - } - - function wrapPrettyPrinted(actual, expected, path) { - return ( - 'Expected ' + - path + - (path.depth() ? ' = ' : '') + - actual + - ' to equal ' + - expected + - '.' - ); - } - - return DiffBuilder; -}; - -getJasmineRequireObj().MatchersUtil = function(j$) { - 'use strict'; - - /** - * @class MatchersUtil - * @classdesc Utilities for use in implementing matchers.
- * _Note:_ Do not construct this directly. Jasmine will construct one and - * pass it to matchers and asymmetric equality testers. - * @hideconstructor - */ - function MatchersUtil(options) { - options = options || {}; - this.customTesters_ = options.customTesters || []; - /** - * Formats a value for use in matcher failure messages and similar contexts, - * taking into account the current set of custom object formatters. - * @function - * @name MatchersUtil#pp - * @since 3.6.0 - * @param {*} value The value to pretty-print - * @return {string} The pretty-printed value - */ - this.pp = options.pp || function() {}; - } - - /** - * Determines whether `haystack` contains `needle`, using the same comparison - * logic as {@link MatchersUtil#equals}. - * @function - * @name MatchersUtil#contains - * @since 2.0.0 - * @param {*} haystack The collection to search - * @param {*} needle The value to search for - * @returns {boolean} True if `needle` was found in `haystack` - */ - MatchersUtil.prototype.contains = function(haystack, needle) { - if (!haystack) { - return false; - } - - if (j$.private.isSet(haystack)) { - // Try .has() first. It should be faster in cases where - // needle === something in haystack. Fall back to .equals() comparison - // if that fails. - if (haystack.has(needle)) { - return true; - } - } - - if (j$.private.isIterable(haystack) && !j$.private.isString(haystack)) { - // Arrays, Sets, etc. - for (const candidate of haystack) { - if (this.equals(candidate, needle)) { - return true; - } - } - - return false; - } - - if (haystack.indexOf) { - // Mainly strings - return haystack.indexOf(needle) >= 0; - } - - if (j$.private.isNumber(haystack.length)) { - // Objects that are shaped like arrays but aren't iterable - for (let i = 0; i < haystack.length; i++) { - if (this.equals(haystack[i], needle)) { - return true; - } - } - } - - return false; - }; - - MatchersUtil.prototype.buildFailureMessage = function() { - const args = Array.prototype.slice.call(arguments, 0), - matcherName = args[0], - isNot = args[1], - actual = args[2], - expected = args.slice(3), - englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { - return ' ' + s.toLowerCase(); - }); - - let message = - 'Expected ' + - this.pp(actual) + - (isNot ? ' not ' : ' ') + - englishyPredicate; - - if (expected.length > 0) { - for (let i = 0; i < expected.length; i++) { - if (i > 0) { - message += ','; - } - message += ' ' + this.pp(expected[i]); - } - } - - return message + '.'; - }; - - MatchersUtil.prototype.asymmetricDiff_ = function( - a, - b, - aStack, - bStack, - diffBuilder - ) { - if (j$.private.isFunction(b.valuesForDiff_)) { - const values = b.valuesForDiff_(a, this.pp); - this.eq_(values.other, values.self, aStack, bStack, diffBuilder); - } else { - diffBuilder.recordMismatch(); - } - }; - - MatchersUtil.prototype.asymmetricMatch_ = function( - a, - b, - aStack, - bStack, - diffBuilder - ) { - const asymmetricA = j$.private.isAsymmetricEqualityTester(a); - const asymmetricB = j$.private.isAsymmetricEqualityTester(b); - - if (asymmetricA === asymmetricB) { - return undefined; - } - - let result; - - if (asymmetricA) { - result = a.asymmetricMatch(b, this); - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - } - - if (asymmetricB) { - result = b.asymmetricMatch(a, this); - if (!result) { - this.asymmetricDiff_(a, b, aStack, bStack, diffBuilder); - } - return result; - } - }; - - /** - * Determines whether two values are deeply equal to each other. - * @function - * @name MatchersUtil#equals - * @since 2.0.0 - * @param {*} a The first value to compare - * @param {*} b The second value to compare - * @returns {boolean} True if the values are equal - */ - MatchersUtil.prototype.equals = function(a, b, diffBuilder) { - diffBuilder = diffBuilder || j$.private.NullDiffBuilder(); - diffBuilder.setRoots(a, b); - - return this.eq_(a, b, [], [], diffBuilder); - }; - - // Equality function lovingly adapted from isEqual in - // [Underscore](http://underscorejs.org) - MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, diffBuilder) { - let result = true; - - const asymmetricResult = this.asymmetricMatch_( - a, - b, - aStack, - bStack, - diffBuilder - ); - if (asymmetricResult !== undefined) { - return asymmetricResult; - } - - for (const tester of this.customTesters_) { - const customTesterResult = tester(a, b); - if (customTesterResult !== undefined) { - if (!customTesterResult) { - diffBuilder.recordMismatch(); - } - return customTesterResult; - } - } - - if (a instanceof Error && b instanceof Error) { - result = a.message == b.message; - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - } - - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) { - result = a !== 0 || 1 / a == 1 / b; - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - } - // A strict comparison is necessary because `null == undefined`. - if (a === null || b === null) { - result = a === b; - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - } - const className = Object.prototype.toString.call(a); - if (className != Object.prototype.toString.call(b)) { - diffBuilder.recordMismatch(); - return false; - } - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - result = a == String(b); - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - result = - a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b; - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - result = +a == +b; - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - case '[object ArrayBuffer]': - // If we have an instance of ArrayBuffer the Uint8Array ctor - // will be defined as well - return this.eq_( - new Uint8Array(a), - new Uint8Array(b), - aStack, - bStack, - diffBuilder - ); - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return ( - a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase - ); - } - if (typeof a != 'object' || typeof b != 'object') { - diffBuilder.recordMismatch(); - return false; - } - - const aIsDomNode = j$.private.isDomNode(a); - const bIsDomNode = j$.private.isDomNode(b); - if (aIsDomNode && bIsDomNode) { - // At first try to use DOM3 method isEqualNode - result = a.isEqualNode(b); - if (!result) { - diffBuilder.recordMismatch(); - } - return result; - } - if (aIsDomNode || bIsDomNode) { - diffBuilder.recordMismatch(); - return false; - } - - const aIsPromise = j$.private.isPromise(a); - const bIsPromise = j$.private.isPromise(b); - if (aIsPromise && bIsPromise) { - return a === b; - } - - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - let length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) { - return bStack[length] == b; - } - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - let size = 0; - // Recursively compare objects and arrays. - // Compare array lengths to determine if a deep comparison is necessary. - if (className == '[object Array]') { - const aLength = a.length; - const bLength = b.length; - - diffBuilder.withPath('length', function() { - if (aLength !== bLength) { - diffBuilder.recordMismatch(); - result = false; - } - }); - - for (let i = 0; i < aLength || i < bLength; i++) { - diffBuilder.withPath(i, () => { - if (i >= bLength) { - diffBuilder.recordMismatch( - actualArrayIsLongerFormatter.bind(null, this.pp) - ); - result = false; - } else { - result = - this.eq_( - i < aLength ? a[i] : void 0, - i < bLength ? b[i] : void 0, - aStack, - bStack, - diffBuilder - ) && result; - } - }); - } - if (!result) { - return false; - } - } else if (j$.private.isMap(a) && j$.private.isMap(b)) { - if (a.size != b.size) { - diffBuilder.recordMismatch(); - return false; - } - - const keysA = []; - const keysB = []; - a.forEach(function(valueA, keyA) { - keysA.push(keyA); - }); - b.forEach(function(valueB, keyB) { - keysB.push(keyB); - }); - - // For both sets of keys, check they map to equal values in both maps. - // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys. - const mapKeys = [keysA, keysB]; - const cmpKeys = [keysB, keysA]; - for (let i = 0; result && i < mapKeys.length; i++) { - const mapIter = mapKeys[i]; - const cmpIter = cmpKeys[i]; - - for (let j = 0; result && j < mapIter.length; j++) { - const mapKey = mapIter[j]; - const cmpKey = cmpIter[j]; - const mapValueA = a.get(mapKey); - let mapValueB; - - // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches, - // otherwise explicitly look up the mapKey in the other Map since we want keys with unique - // obj identity (that are otherwise equal) to not match. - if ( - j$.private.isAsymmetricEqualityTester(mapKey) || - (j$.private.isAsymmetricEqualityTester(cmpKey) && - this.eq_( - mapKey, - cmpKey, - aStack, - bStack, - j$.private.NullDiffBuilder() - )) - ) { - mapValueB = b.get(cmpKey); - } else { - mapValueB = b.get(mapKey); - } - result = this.eq_( - mapValueA, - mapValueB, - aStack, - bStack, - j$.private.NullDiffBuilder() - ); - } - } - - if (!result) { - diffBuilder.recordMismatch(); - return false; - } - } else if (j$.private.isSet(a) && j$.private.isSet(b)) { - if (a.size != b.size) { - diffBuilder.recordMismatch(); - return false; - } - - const valuesA = []; - a.forEach(function(valueA) { - valuesA.push(valueA); - }); - const valuesB = []; - b.forEach(function(valueB) { - valuesB.push(valueB); - }); - - // For both sets, check they are all contained in the other set - const setPairs = [[valuesA, valuesB], [valuesB, valuesA]]; - const stackPairs = [[aStack, bStack], [bStack, aStack]]; - for (let i = 0; result && i < setPairs.length; i++) { - const baseValues = setPairs[i][0]; - const otherValues = setPairs[i][1]; - const baseStack = stackPairs[i][0]; - const otherStack = stackPairs[i][1]; - // For each value in the base set... - for (const baseValue of baseValues) { - let found = false; - // ... test that it is present in the other set - for (let j = 0; !found && j < otherValues.length; j++) { - const otherValue = otherValues[j]; - const prevStackSize = baseStack.length; - // compare by value equality - found = this.eq_( - baseValue, - otherValue, - baseStack, - otherStack, - j$.private.NullDiffBuilder() - ); - if (!found && prevStackSize !== baseStack.length) { - baseStack.splice(prevStackSize); - otherStack.splice(prevStackSize); - } - } - result = result && found; - } - } - - if (!result) { - diffBuilder.recordMismatch(); - return false; - } - } else if (j$.private.isURL(a) && j$.private.isURL(b)) { - // URLs have no enumrable properties, so the default object comparison - // would consider any two URLs to be equal. - return a.toString() === b.toString(); - } else { - // Objects with different constructors are not equivalent, but `Object`s - // or `Array`s from different frames are. - const aCtor = a.constructor, - bCtor = b.constructor; - if ( - aCtor !== bCtor && - isFunction(aCtor) && - isFunction(bCtor) && - a instanceof aCtor && - b instanceof bCtor && - !(aCtor instanceof aCtor && bCtor instanceof bCtor) - ) { - diffBuilder.recordMismatch( - constructorsAreDifferentFormatter.bind(null, this.pp) - ); - return false; - } - } - - // Deep compare objects. - const aKeys = MatchersUtil.keys(a, className == '[object Array]'); - size = aKeys.length; - - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (MatchersUtil.keys(b, className == '[object Array]').length !== size) { - diffBuilder.recordMismatch( - objectKeysAreDifferentFormatter.bind(null, this.pp) - ); - result = false; - } - - for (const key of aKeys) { - // Deep compare each member - if (!j$.private.util.has(b, key)) { - diffBuilder.recordMismatch( - objectKeysAreDifferentFormatter.bind(null, this.pp) - ); - result = false; - continue; - } - - diffBuilder.withPath(key, () => { - if (!this.eq_(a[key], b[key], aStack, bStack, diffBuilder)) { - result = false; - } - }); - } - - if (!result) { - return false; - } - - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - - return result; - }; - - MatchersUtil.keys = function(obj, isArray) { - const allKeys = (function(o) { - const keys = []; - for (const key in o) { - if (j$.private.util.has(o, key)) { - keys.push(key); - } - } - - const symbols = Object.getOwnPropertySymbols(o); - for (const sym of symbols) { - if (o.propertyIsEnumerable(sym)) { - keys.push(sym); - } - } - - return keys; - })(obj); - - if (!isArray) { - return allKeys; - } - - if (allKeys.length === 0) { - return allKeys; - } - - const extraKeys = []; - for (const k of allKeys) { - if (typeof k === 'symbol' || !/^[0-9]+$/.test(k)) { - extraKeys.push(k); - } - } - - return extraKeys; - }; - - function isFunction(obj) { - return typeof obj === 'function'; - } - - // Returns an array of [k, v] pairs for eacch property that's in objA - // and not in objB. - function extraKeysAndValues(objA, objB) { - return MatchersUtil.keys(objA) - .filter(key => !j$.private.util.has(objB, key)) - .map(key => [key, objA[key]]); - } - - function objectKeysAreDifferentFormatter(pp, actual, expected, path) { - const missingProperties = extraKeysAndValues(expected, actual), - extraProperties = extraKeysAndValues(actual, expected), - missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), - extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), - messages = []; - - if (!path.depth()) { - path = 'object'; - } - - if (missingPropertiesMessage.length) { - messages.push( - 'Expected ' + path + ' to have properties' + missingPropertiesMessage - ); - } - - if (extraPropertiesMessage.length) { - messages.push( - 'Expected ' + path + ' not to have properties' + extraPropertiesMessage - ); - } - - return messages.join('\n'); - } - - function constructorsAreDifferentFormatter(pp, actual, expected, path) { - if (!path.depth()) { - path = 'object'; - } - - return ( - 'Expected ' + - path + - ' to be a kind of ' + - j$.private.fnNameFor(expected.constructor) + - ', but was ' + - pp(actual) + - '.' - ); - } - - function actualArrayIsLongerFormatter(pp, actual, expected, path) { - return ( - 'Unexpected ' + - path + - (path.depth() ? ' = ' : '') + - pp(actual) + - ' in array.' - ); - } - - function formatKeyValuePairs(pp, keyValuePairs) { - let formatted = ''; - - for (const [key, value] of keyValuePairs) { - formatted += '\n ' + key.toString() + ': ' + pp(value); - } - - return formatted; - } - - return MatchersUtil; -}; - -/** - * @interface AsymmetricEqualityTester - * @classdesc An asymmetric equality tester is an object that can match multiple - * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine - * includes a number of built-in asymmetric equality testers, such as - * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are - * also supported. - * - * Asymmetric equality testers work with any matcher, including user-defined - * custom matchers, that uses {@link MatchersUtil#equals} or - * {@link MatchersUtil#contains}. - * - * @example - * function numberDivisibleBy(divisor) { - * return { - * asymmetricMatch: function(n) { - * return typeof n === 'number' && n % divisor === 0; - * }, - * jasmineToString: function() { - * return ``; - * } - * }; - * } - * - * const actual = { - * n: 2, - * otherFields: "don't care" - * }; - * - * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)})); - * @see custom_asymmetric_equality_testers - * @since 2.0.0 - */ -/** - * Determines whether a value matches this tester - * @function - * @name AsymmetricEqualityTester#asymmetricMatch - * @param value {any} The value to test - * @param matchersUtil {MatchersUtil} utilities for testing equality, etc - * @return {Boolean} - */ -/** - * Returns a string representation of this tester to use in matcher failure messages - * @function - * @name AsymmetricEqualityTester#jasmineToString - * @param pp {function} Function that takes a value and returns a pretty-printed representation - * @return {String} - */ - -getJasmineRequireObj().MismatchTree = function(j$) { - 'use strict'; - - /* - To be able to apply custom object formatters at all possible levels of an - object graph, DiffBuilder needs to be able to know not just where the - mismatch occurred but also all ancestors of the mismatched value in both - the expected and actual object graphs. MismatchTree maintains that context - and provides it via the traverse method. - */ - class MismatchTree { - constructor(path) { - this.path = path || new j$.private.ObjectPath([]); - this.formatter = undefined; - this.children = []; - this.isMismatch = false; - } - - add(path, formatter) { - if (path.depth() === 0) { - this.formatter = formatter; - this.isMismatch = true; - } else { - const key = path.components[0]; - path = path.shift(); - let child = this.child(key); - - if (!child) { - child = new MismatchTree(this.path.add(key)); - this.children.push(child); - } - - child.add(path, formatter); - } - } - - traverse(visit) { - const hasChildren = this.children.length > 0; - - if (this.isMismatch || hasChildren) { - if (visit(this.path, !hasChildren, this.formatter)) { - for (const child of this.children) { - child.traverse(visit); - } - } - } - } - - child(key) { - return this.children.find(child => { - const pathEls = child.path.components; - return pathEls[pathEls.length - 1] === key; - }); - } - } - - return MismatchTree; -}; - -getJasmineRequireObj().nothing = function() { - 'use strict'; - - /** - * {@link expect} nothing explicitly. - * @function - * @name matchers#nothing - * @since 2.8.0 - * @example - * expect().nothing(); - */ - function nothing() { - return { - compare: function() { - return { - pass: true - }; - } - }; - } - - return nothing; -}; - -getJasmineRequireObj().NullDiffBuilder = function(j$) { - 'use strict'; - - return function() { - return { - withPath: function(_, block) { - block(); - }, - setRoots: function() {}, - recordMismatch: function() {} - }; - }; -}; - -getJasmineRequireObj().ObjectPath = function(j$) { - 'use strict'; - - class ObjectPath { - constructor(components) { - this.components = components || []; - } - - toString() { - if (this.components.length) { - return '$' + this.components.map(formatPropertyAccess).join(''); - } else { - return ''; - } - } - - add(component) { - return new ObjectPath(this.components.concat([component])); - } - - shift() { - return new ObjectPath(this.components.slice(1)); - } - - depth() { - return this.components.length; - } - } - - function formatPropertyAccess(prop) { - if (typeof prop === 'number' || typeof prop === 'symbol') { - return '[' + prop.toString() + ']'; - } - - if (isValidIdentifier(prop)) { - return '.' + prop; - } - - return `['${prop}']`; - } - - function isValidIdentifier(string) { - return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string); - } - - return ObjectPath; -}; - -getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) { - 'use strict'; - - const availableMatchers = [ - 'toBePending', - 'toBeResolved', - 'toBeRejected', - 'toBeResolvedTo', - 'toBeRejectedWith', - 'toBeRejectedWithError' - ], - matchers = {}; - - for (const name of availableMatchers) { - matchers[name] = jRequire[name](j$); - } - - return matchers; -}; - -getJasmineRequireObj().toBe = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be `===` to the expected value. - * @function - * @name matchers#toBe - * @since 1.3.0 - * @param {Object} expected - The expected value to compare against. - * @example - * expect(thing).toBe(realThing); - */ - function toBe(matchersUtil) { - const tip = - ' Tip: To check for deep equality, use .toEqual() instead of .toBe().'; - - return { - compare: function(actual, expected) { - const result = { - pass: actual === expected - }; - - if (typeof expected === 'object') { - result.message = - matchersUtil.buildFailureMessage( - 'toBe', - result.pass, - actual, - expected - ) + tip; - } - - return result; - } - }; - } - - return toBe; -}; - -getJasmineRequireObj().toBeCloseTo = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be within a specified precision of the expected value. - * @function - * @name matchers#toBeCloseTo - * @since 1.3.0 - * @param {Object} expected - The expected value to compare against. - * @param {Number} [precision=2] - The number of decimal points to check. - * @example - * expect(number).toBeCloseTo(42.2, 3); - */ - function toBeCloseTo() { - return { - compare: function(actual, expected, precision) { - if (precision !== 0) { - precision = precision || 2; - } - - if (expected === null || actual === null) { - throw new Error( - 'Cannot use toBeCloseTo with null. Arguments evaluated to: ' + - 'expect(' + - actual + - ').toBeCloseTo(' + - expected + - ').' - ); - } - - // Infinity is close to Infinity and -Infinity is close to -Infinity, - // regardless of the precision. - if (expected === Infinity || expected === -Infinity) { - return { - pass: actual === expected - }; - } - - const pow = Math.pow(10, precision + 1); - const delta = Math.abs(expected - actual); - const maxDelta = Math.pow(10, -precision) / 2; - - return { - pass: Math.round(delta * pow) <= maxDelta * pow - }; - } - }; - } - - return toBeCloseTo; -}; - -getJasmineRequireObj().toBeDefined = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be defined. (Not `undefined`) - * @function - * @name matchers#toBeDefined - * @since 1.3.0 - * @example - * expect(result).toBeDefined(); - */ - function toBeDefined() { - return { - compare: function(actual) { - return { - pass: void 0 !== actual - }; - } - }; - } - - return toBeDefined; -}; - -getJasmineRequireObj().toBeFalse = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be `false`. - * @function - * @name matchers#toBeFalse - * @since 3.5.0 - * @example - * expect(result).toBeFalse(); - */ - function toBeFalse() { - return { - compare: function(actual) { - return { - pass: actual === false - }; - } - }; - } - - return toBeFalse; -}; - -getJasmineRequireObj().toBeFalsy = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be falsy - * @function - * @name matchers#toBeFalsy - * @since 2.0.0 - * @example - * expect(result).toBeFalsy(); - */ - function toBeFalsy() { - return { - compare: function(actual) { - return { - pass: !actual - }; - } - }; - } - - return toBeFalsy; -}; - -getJasmineRequireObj().toBeGreaterThan = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be greater than the expected value. - * @function - * @name matchers#toBeGreaterThan - * @since 2.0.0 - * @param {Number} expected - The value to compare against. - * @example - * expect(result).toBeGreaterThan(3); - */ - function toBeGreaterThan() { - return { - compare: function(actual, expected) { - return { - pass: actual > expected - }; - } - }; - } - - return toBeGreaterThan; -}; - -getJasmineRequireObj().toBeGreaterThanOrEqual = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be greater than or equal to the expected value. - * @function - * @name matchers#toBeGreaterThanOrEqual - * @since 2.0.0 - * @param {Number} expected - The expected value to compare against. - * @example - * expect(result).toBeGreaterThanOrEqual(25); - */ - function toBeGreaterThanOrEqual() { - return { - compare: function(actual, expected) { - return { - pass: actual >= expected - }; - } - }; - } - - return toBeGreaterThanOrEqual; -}; - -getJasmineRequireObj().toBeInstanceOf = function(j$) { - 'use strict'; - - const usageError = j$.private.formatErrorMsg( - '', - 'expect(value).toBeInstanceOf()' - ); - - /** - * {@link expect} the actual to be an instance of the expected class - * @function - * @name matchers#toBeInstanceOf - * @since 3.5.0 - * @param {Object} expected - The class or constructor function to check for - * @example - * expect('foo').toBeInstanceOf(String); - * expect(3).toBeInstanceOf(Number); - * expect(new Error()).toBeInstanceOf(Error); - */ - function toBeInstanceOf(matchersUtil) { - return { - compare: function(actual, expected) { - const actualType = - actual && actual.constructor - ? j$.private.fnNameFor(actual.constructor) - : matchersUtil.pp(actual); - const expectedType = expected - ? j$.private.fnNameFor(expected) - : matchersUtil.pp(expected); - let expectedMatcher; - let pass; - - try { - expectedMatcher = new j$.private.Any(expected); - pass = expectedMatcher.asymmetricMatch(actual); - // eslint-disable-next-line no-unused-vars - } catch (error) { - throw new Error( - usageError('Expected value is not a constructor function') - ); - } - - if (pass) { - return { - pass: true, - message: - 'Expected instance of ' + - actualType + - ' not to be an instance of ' + - expectedType - }; - } else { - return { - pass: false, - message: - 'Expected instance of ' + - actualType + - ' to be an instance of ' + - expectedType - }; - } - } - }; - } - - return toBeInstanceOf; -}; - -getJasmineRequireObj().toBeLessThan = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be less than the expected value. - * @function - * @name matchers#toBeLessThan - * @since 2.0.0 - * @param {Number} expected - The expected value to compare against. - * @example - * expect(result).toBeLessThan(0); - */ - function toBeLessThan() { - return { - compare: function(actual, expected) { - return { - pass: actual < expected - }; - } - }; - } - - return toBeLessThan; -}; - -getJasmineRequireObj().toBeLessThanOrEqual = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be less than or equal to the expected value. - * @function - * @name matchers#toBeLessThanOrEqual - * @since 2.0.0 - * @param {Number} expected - The expected value to compare against. - * @example - * expect(result).toBeLessThanOrEqual(123); - */ - function toBeLessThanOrEqual() { - return { - compare: function(actual, expected) { - return { - pass: actual <= expected - }; - } - }; - } - - return toBeLessThanOrEqual; -}; - -getJasmineRequireObj().toBeNaN = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be `NaN` (Not a Number). - * @function - * @name matchers#toBeNaN - * @since 1.3.0 - * @example - * expect(thing).toBeNaN(); - */ - function toBeNaN(matchersUtil) { - return { - compare: function(actual) { - const result = { - pass: actual !== actual - }; - - if (result.pass) { - result.message = 'Expected actual not to be NaN.'; - } else { - result.message = function() { - return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.'; - }; - } - - return result; - } - }; - } - - return toBeNaN; -}; - -getJasmineRequireObj().toBeNegativeInfinity = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be `-Infinity` (-infinity). - * @function - * @name matchers#toBeNegativeInfinity - * @since 2.6.0 - * @example - * expect(thing).toBeNegativeInfinity(); - */ - function toBeNegativeInfinity(matchersUtil) { - return { - compare: function(actual) { - const result = { - pass: actual === Number.NEGATIVE_INFINITY - }; - - if (result.pass) { - result.message = 'Expected actual not to be -Infinity.'; - } else { - result.message = function() { - return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.'; - }; - } - - return result; - } - }; - } - - return toBeNegativeInfinity; -}; - -getJasmineRequireObj().toBeNull = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be `null`. - * @function - * @name matchers#toBeNull - * @since 1.3.0 - * @example - * expect(result).toBeNull(); - */ - function toBeNull() { - return { - compare: function(actual) { - return { - pass: actual === null - }; - } - }; - } - - return toBeNull; -}; - -getJasmineRequireObj().toBeNullish = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be `null` or `undefined`. - * @function - * @name matchers#toBeNullish - * @since 5.6.0 - * @example - * expect(result).toBeNullish(): - */ - function toBeNullish() { - return { - compare: function(actual) { - return { - pass: null === actual || void 0 === actual - }; - } - }; - } - - return toBeNullish; -}; - -getJasmineRequireObj().toBePositiveInfinity = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be `Infinity` (infinity). - * @function - * @name matchers#toBePositiveInfinity - * @since 2.6.0 - * @example - * expect(thing).toBePositiveInfinity(); - */ - function toBePositiveInfinity(matchersUtil) { - return { - compare: function(actual) { - const result = { - pass: actual === Number.POSITIVE_INFINITY - }; - - if (result.pass) { - result.message = 'Expected actual not to be Infinity.'; - } else { - result.message = function() { - return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.'; - }; - } - - return result; - } - }; - } - - return toBePositiveInfinity; -}; - -getJasmineRequireObj().toBeTrue = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be `true`. - * @function - * @name matchers#toBeTrue - * @since 3.5.0 - * @example - * expect(result).toBeTrue(); - */ - function toBeTrue() { - return { - compare: function(actual) { - return { - pass: actual === true - }; - } - }; - } - - return toBeTrue; -}; - -getJasmineRequireObj().toBeTruthy = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be truthy. - * @function - * @name matchers#toBeTruthy - * @since 2.0.0 - * @example - * expect(thing).toBeTruthy(); - */ - function toBeTruthy() { - return { - compare: function(actual) { - return { - pass: !!actual - }; - } - }; - } - - return toBeTruthy; -}; - -getJasmineRequireObj().toBeUndefined = function() { - 'use strict'; - - /** - * {@link expect} the actual value to be `undefined`. - * @function - * @name matchers#toBeUndefined - * @since 1.3.0 - * @example - * expect(result).toBeUndefined(): - */ - function toBeUndefined() { - return { - compare: function(actual) { - return { - pass: void 0 === actual - }; - } - }; - } - - return toBeUndefined; -}; - -getJasmineRequireObj().toContain = function() { - 'use strict'; - - /** - * {@link expect} the actual value to contain a specific value. - * @function - * @name matchers#toContain - * @since 2.0.0 - * @param {Object} expected - The value to look for. - * @example - * expect(array).toContain(anElement); - * expect(string).toContain(substring); - */ - function toContain(matchersUtil) { - return { - compare: function(actual, expected) { - return { - pass: matchersUtil.contains(actual, expected) - }; - } - }; - } - - return toContain; -}; - -getJasmineRequireObj().toEqual = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be equal to the expected, using deep equality comparison. - * @function - * @name matchers#toEqual - * @since 1.3.0 - * @param {Object} expected - Expected value - * @example - * expect(bigObject).toEqual({"foo": ['bar', 'baz']}); - */ - function toEqual(matchersUtil) { - return { - compare: function(actual, expected) { - const result = { - pass: false - }, - diffBuilder = new j$.private.DiffBuilder({ - prettyPrinter: matchersUtil.pp - }); - - result.pass = matchersUtil.equals(actual, expected, diffBuilder); - - // TODO: only set error message if test fails - result.message = diffBuilder.getMessage(); - - return result; - } - }; - } - - return toEqual; -}; - -getJasmineRequireObj().toHaveBeenCalled = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveBeenCalled()' - ); - - /** - * {@link expect} the actual (a {@link Spy}) to have been called. - * @function - * @name matchers#toHaveBeenCalled - * @since 1.3.0 - * @example - * expect(mySpy).toHaveBeenCalled(); - * expect(mySpy).not.toHaveBeenCalled(); - */ - function toHaveBeenCalled(matchersUtil) { - return { - compare: function(actual) { - const result = {}; - - if (!j$.isSpy(actual)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' - ) - ); - } - - if (arguments.length > 1) { - throw new Error( - getErrorMsg('Does not take arguments, use toHaveBeenCalledWith') - ); - } - - result.pass = actual.calls.any(); - - actual.calls.all().forEach(call => (call.verified = true)); - - result.message = result.pass - ? 'Expected spy ' + actual.and.identity + ' not to have been called.' - : 'Expected spy ' + actual.and.identity + ' to have been called.'; - - return result; - } - }; - } - - return toHaveBeenCalled; -}; - -getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveBeenCalledBefore()' - ); - - /** - * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}. - * @function - * @name matchers#toHaveBeenCalledBefore - * @since 2.6.0 - * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}. - * @example - * expect(mySpy).toHaveBeenCalledBefore(otherSpy); - */ - function toHaveBeenCalledBefore(matchersUtil) { - return { - compare: function(firstSpy, latterSpy) { - if (!j$.isSpy(firstSpy)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.' - ) - ); - } - if (!j$.isSpy(latterSpy)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.' - ) - ); - } - - const result = { pass: false }; - - if (!firstSpy.calls.count()) { - result.message = - 'Expected spy ' + firstSpy.and.identity + ' to have been called.'; - return result; - } - if (!latterSpy.calls.count()) { - result.message = - 'Expected spy ' + latterSpy.and.identity + ' to have been called.'; - return result; - } - - const latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder; - const first2ndSpyCall = latterSpy.calls.first().invocationOrder; - - result.pass = latest1stSpyCall < first2ndSpyCall; - - if (result.pass) { - firstSpy.calls.mostRecent().verified = true; - latterSpy.calls.first().verified = true; - - result.message = - 'Expected spy ' + - firstSpy.and.identity + - ' to not have been called before spy ' + - latterSpy.and.identity + - ', but it was'; - } else { - const first1stSpyCall = firstSpy.calls.first().invocationOrder; - const latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder; - - if (first1stSpyCall < first2ndSpyCall) { - result.message = - 'Expected latest call to spy ' + - firstSpy.and.identity + - ' to have been called before first call to spy ' + - latterSpy.and.identity + - ' (no interleaved calls)'; - } else if (latest2ndSpyCall > latest1stSpyCall) { - result.message = - 'Expected first call to spy ' + - latterSpy.and.identity + - ' to have been called after latest call to spy ' + - firstSpy.and.identity + - ' (no interleaved calls)'; - } else { - result.message = - 'Expected spy ' + - firstSpy.and.identity + - ' to have been called before spy ' + - latterSpy.and.identity; - } - } - - return result; - } - }; - } - - return toHaveBeenCalledBefore; -}; - -getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveBeenCalledOnceWith(...arguments)' - ); - - /** - * {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments. - * @function - * @name matchers#toHaveBeenCalledOnceWith - * @since 3.6.0 - * @param {...Object} - The arguments to look for - * @example - * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2); - */ - function toHaveBeenCalledOnceWith(matchersUtil) { - return { - compare: function() { - const args = Array.prototype.slice.call(arguments, 0), - actual = args[0], - expectedArgs = args.slice(1); - - if (!j$.isSpy(actual)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' - ) - ); - } - - const prettyPrintedCalls = actual.calls - .allArgs() - .map(function(argsForCall) { - return ' ' + matchersUtil.pp(argsForCall); - }); - - if ( - actual.calls.count() === 1 && - matchersUtil.contains(actual.calls.allArgs(), expectedArgs) - ) { - const firstIndex = actual.calls - .all() - .findIndex(call => matchersUtil.equals(call.args, expectedArgs)); - if (firstIndex > -1) { - actual.calls.all()[firstIndex].verified = true; - } - - return { - pass: true, - message: - 'Expected spy ' + - actual.and.identity + - ' to have been called 0 times, multiple times, or once, but with arguments different from:\n' + - ' ' + - matchersUtil.pp(expectedArgs) + - '\n' + - 'But the actual call was:\n' + - prettyPrintedCalls.join(',\n') + - '.\n\n' - }; - } - - function getDiffs() { - return actual.calls.allArgs().map(function(argsForCall, callIx) { - const diffBuilder = new j$.private.DiffBuilder(); - matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); - return diffBuilder.getMessage(); - }); - } - - function butString() { - switch (actual.calls.count()) { - case 0: - return 'But it was never called.\n\n'; - case 1: - return ( - 'But the actual call was:\n' + - prettyPrintedCalls.join(',\n') + - '.\n' + - getDiffs().join('\n') + - '\n\n' - ); - default: - return ( - 'But the actual calls were:\n' + - prettyPrintedCalls.join(',\n') + - '.\n\n' - ); - } - } - - return { - pass: false, - message: - 'Expected spy ' + - actual.and.identity + - ' to have been called only once, and with given args:\n' + - ' ' + - matchersUtil.pp(expectedArgs) + - '\n' + - butString() - }; - } - }; - } - - return toHaveBeenCalledOnceWith; -}; - -getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveBeenCalledTimes()' - ); - - /** - * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times. - * @function - * @name matchers#toHaveBeenCalledTimes - * @since 2.4.0 - * @param {Number} expected - The number of invocations to look for. - * @example - * expect(mySpy).toHaveBeenCalledTimes(3); - */ - function toHaveBeenCalledTimes(matchersUtil) { - return { - compare: function(actual, expected) { - if (!j$.isSpy(actual)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' - ) - ); - } - - const args = Array.prototype.slice.call(arguments, 0), - result = { pass: false }; - - if (!j$.private.isNumber(expected)) { - throw new Error( - getErrorMsg( - 'The expected times failed is a required argument and must be a number.' - ) - ); - } - - actual = args[0]; - - const callsCount = actual.calls.count(); - const timesMessage = expected === 1 ? 'once' : expected + ' times'; - - result.pass = callsCount === expected; - - if (result.pass) { - const allCalls = actual.calls.all(); - const max = Math.min(expected, callsCount); - - for (let i = 0; i < max; i++) { - allCalls[i].verified = true; - } - } - - result.message = result.pass - ? 'Expected spy ' + - actual.and.identity + - ' not to have been called ' + - timesMessage + - '. It was called ' + - callsCount + - ' times.' - : 'Expected spy ' + - actual.and.identity + - ' to have been called ' + - timesMessage + - '. It was called ' + - callsCount + - ' times.'; - return result; - } - }; - } - - return toHaveBeenCalledTimes; -}; - -getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveBeenCalledWith(...arguments)' - ); - - /** - * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once. - * @function - * @name matchers#toHaveBeenCalledWith - * @since 1.3.0 - * @param {...Object} - The arguments to look for - * @example - * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2); - */ - function toHaveBeenCalledWith(matchersUtil) { - return { - compare: function() { - const args = Array.prototype.slice.call(arguments, 0), - actual = args[0], - expectedArgs = args.slice(1), - result = { pass: false }; - - if (!j$.isSpy(actual)) { - throw new Error( - getErrorMsg( - 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' - ) - ); - } - - if (!actual.calls.any()) { - result.message = function() { - return ( - 'Expected spy ' + - actual.and.identity + - ' to have been called with:\n' + - ' ' + - matchersUtil.pp(expectedArgs) + - '\nbut it was never called.' - ); - }; - return result; - } - - if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) { - actual.calls - .all() - .filter(call => matchersUtil.equals(call.args, expectedArgs)) - .forEach(call => (call.verified = true)); - - result.pass = true; - result.message = function() { - return ( - 'Expected spy ' + - actual.and.identity + - ' not to have been called with:\n' + - ' ' + - matchersUtil.pp(expectedArgs) + - '\nbut it was.' - ); - }; - } else { - result.message = function() { - const prettyPrintedCalls = actual.calls - .allArgs() - .map(function(argsForCall) { - return ' ' + matchersUtil.pp(argsForCall); - }); - - const diffs = actual.calls - .allArgs() - .map(function(argsForCall, callIx) { - const diffBuilder = new j$.private.DiffBuilder(); - matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); - return ( - 'Call ' + - callIx + - ':\n' + - diffBuilder.getMessage().replace(/^/gm, ' ') - ); - }); - - return ( - 'Expected spy ' + - actual.and.identity + - ' to have been called with:\n' + - ' ' + - matchersUtil.pp(expectedArgs) + - '\n' + - '' + - 'but actual calls were:\n' + - prettyPrintedCalls.join(',\n') + - '.\n\n' + - diffs.join('\n') - ); - }; - } - - return result; - } - }; - } - - return toHaveBeenCalledWith; -}; - -getJasmineRequireObj().toHaveClass = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be a DOM element that has the expected class - * @function - * @name matchers#toHaveClass - * @since 3.0.0 - * @param {Object} expected - The class name to test for - * @example - * const el = document.createElement('div'); - * el.className = 'foo bar baz'; - * expect(el).toHaveClass('bar'); - */ - function toHaveClass(matchersUtil) { - return { - compare: function(actual, expected) { - if (!isElement(actual)) { - throw new Error(matchersUtil.pp(actual) + ' is not a DOM element'); - } - - return { - pass: actual.classList.contains(expected) - }; - } - }; - } - - function isElement(maybeEl) { - return ( - maybeEl && - maybeEl.classList && - j$.private.isFunction(maybeEl.classList.contains) - ); - } - - return toHaveClass; -}; - -getJasmineRequireObj().toHaveClasses = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual value to be a DOM element that has the expected classes - * @function - * @name matchers#toHaveClasses - * @since 5.6.0 - * @param {Object} expected - The class names to test for - * @example - * const el = document.createElement('div'); - * el.className = 'foo bar baz'; - * expect(el).toHaveClasses(['bar', 'baz']); - */ - function toHaveClasses(matchersUtil) { - return { - compare: function(actual, expected) { - if (!isElement(actual)) { - throw new Error(matchersUtil.pp(actual) + ' is not a DOM element'); - } - - return { - pass: expected.every(e => actual.classList.contains(e)) - }; - } - }; - } - - function isElement(maybeEl) { - return ( - maybeEl && - maybeEl.classList && - j$.private.isFunction(maybeEl.classList.contains) - ); - } - - return toHaveClasses; -}; - -getJasmineRequireObj().toHaveNoOtherSpyInteractions = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveNoOtherSpyInteractions()' - ); - - /** - * {@link expect} the actual (a {@link SpyObj}) spies to have not been called except interactions which was already tracked with `toHaveBeenCalled`. - * @function - * @name matchers#toHaveNoOtherSpyInteractions - * @example - * expect(mySpyObj).toHaveNoOtherSpyInteractions(); - * expect(mySpyObj).not.toHaveNoOtherSpyInteractions(); - */ - function toHaveNoOtherSpyInteractions(matchersUtil) { - return { - compare: function(actual) { - const result = {}; - - if (!j$.private.isObject(actual)) { - throw new Error( - getErrorMsg('Expected an object, but got ' + typeof actual + '.') - ); - } - - if (arguments.length > 1) { - throw new Error(getErrorMsg('Does not take arguments')); - } - - result.pass = true; - let hasSpy = false; - const unexpectedCalls = []; - - for (const spy of Object.values(actual)) { - if (!j$.isSpy(spy)) { - continue; - } - - hasSpy = true; - - const unverifiedCalls = spy.calls - .all() - .filter(call => !call.verified); - - if (unverifiedCalls.length > 0) { - result.pass = false; - } - - unverifiedCalls.forEach(unverifiedCall => { - unexpectedCalls.push([ - spy.and.identity, - matchersUtil.pp(unverifiedCall.args) - ]); - }); - } - - if (!hasSpy) { - throw new Error( - getErrorMsg( - 'Expected an object with spies, but object has no spies.' - ) - ); - } - - if (result.pass) { - result.message = - "Expected a spy object to have other spy interactions but it didn't."; - } else { - const ppUnexpectedCalls = unexpectedCalls - .map(([spyName, args]) => ` ${spyName} called with ${args}`) - .join(',\n'); - - result.message = - 'Expected a spy object to have no other spy interactions, but it had the following calls:\n' + - ppUnexpectedCalls + - '.'; - } - - return result; - } - }; - } - - return toHaveNoOtherSpyInteractions; -}; - -getJasmineRequireObj().toHaveSize = function(j$) { - 'use strict'; - - /** - * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size. - * @function - * @name matchers#toHaveSize - * @since 3.6.0 - * @param {Object} expected - Expected size - * @example - * array = [1,2]; - * expect(array).toHaveSize(2); - */ - function toHaveSize(matchersUtil) { - return { - compare: function(actual, expected) { - const result = { - pass: false - }; - - if ( - j$.private.isA('WeakSet', actual) || - j$.private.isWeakMap(actual) || - j$.private.isDataView(actual) - ) { - throw new Error('Cannot get size of ' + actual + '.'); - } - - let actualSize; - if (j$.private.isSet(actual) || j$.private.isMap(actual)) { - actualSize = actual.size; - } else if (isLength(actual.length)) { - actualSize = actual.length; - } else { - actualSize = Object.keys(actual).length; - } - - result.pass = actualSize === expected; - - if (!result.pass) { - result.message = function() { - return ( - 'Expected ' + - matchersUtil.pp(actual) + - ' with size ' + - actualSize + - ' to have size ' + - expected + - '.' - ); - }; - } - - return result; - } - }; - } - - const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; - function isLength(value) { - return ( - typeof value == 'number' && - value > -1 && - value % 1 === 0 && - value <= MAX_SAFE_INTEGER - ); - } - - return toHaveSize; -}; - -getJasmineRequireObj().toHaveSpyInteractions = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toHaveSpyInteractions()' - ); - - /** - * {@link expect} the actual (a {@link SpyObj}) spies to have been called. - * @function - * @name matchers#toHaveSpyInteractions - * @since 4.1.0 - * @example - * expect(mySpyObj).toHaveSpyInteractions(); - * expect(mySpyObj).not.toHaveSpyInteractions(); - */ - function toHaveSpyInteractions(matchersUtil) { - return { - compare: function(actual) { - const result = {}; - - if (!j$.private.isObject(actual)) { - throw new Error( - getErrorMsg('Expected a spy object, but got ' + typeof actual + '.') - ); - } - - if (arguments.length > 1) { - throw new Error(getErrorMsg('Does not take arguments')); - } - - result.pass = false; - let hasSpy = false; - const calledSpies = []; - for (const spy of Object.values(actual)) { - if (!j$.isSpy(spy)) { - continue; - } - - hasSpy = true; - - if (spy.calls.any()) { - result.pass = true; - calledSpies.push([spy.and.identity, spy.calls.count()]); - } - } - - if (!hasSpy) { - throw new Error( - getErrorMsg( - 'Expected a spy object with spies, but object has no spies.' - ) - ); - } - - let resultMessage; - if (result.pass) { - resultMessage = - 'Expected spy object spies not to have been called, ' + - 'but the following spies were called: '; - resultMessage += calledSpies - .map(([spyName, spyCount]) => { - return `${spyName} called ${spyCount} time(s)`; - }) - .join(', '); - } else { - resultMessage = - 'Expected spy object spies to have been called, ' + - 'but no spies were called.'; - } - result.message = resultMessage; - - return result; - } - }; - } - - return toHaveSpyInteractions; -}; - -getJasmineRequireObj().toMatch = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect().toMatch( || )' - ); - - /** - * {@link expect} the actual value to match a regular expression - * @function - * @name matchers#toMatch - * @since 1.3.0 - * @param {RegExp|String} expected - Value to look for in the string. - * @example - * expect("my string").toMatch(/string$/); - * expect("other string").toMatch("her"); - */ - function toMatch() { - return { - compare: function(actual, expected) { - if ( - !j$.private.isString(expected) && - !j$.private.isA('RegExp', expected) - ) { - throw new Error(getErrorMsg('Expected is not a String or a RegExp')); - } - - const regexp = new RegExp(expected); - - return { - pass: regexp.test(actual) - }; - } - }; - } - - return toMatch; -}; - -getJasmineRequireObj().toThrow = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect(function() {}).toThrow()' - ); - - /** - * {@link expect} a function to `throw` something. - * @function - * @name matchers#toThrow - * @since 2.0.0 - * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked. - * @example - * expect(function() { return 'things'; }).toThrow('foo'); - * expect(function() { return 'stuff'; }).toThrow(); - */ - function toThrow(matchersUtil) { - return { - compare: function(actual, expected) { - const result = { pass: false }; - let threw = false; - let thrown; - - if (typeof actual != 'function') { - throw new Error(getErrorMsg('Actual is not a Function')); - } - - try { - actual(); - } catch (e) { - threw = true; - thrown = e; - } - - if (!threw) { - result.message = 'Expected function to throw an exception.'; - return result; - } - - if (arguments.length == 1) { - result.pass = true; - result.message = function() { - return ( - 'Expected function not to throw, but it threw ' + - matchersUtil.pp(thrown) + - '.' - ); - }; - - return result; - } - - if (matchersUtil.equals(thrown, expected)) { - result.pass = true; - result.message = function() { - return ( - 'Expected function not to throw ' + - matchersUtil.pp(expected) + - '.' - ); - }; - } else { - result.message = function() { - return ( - 'Expected function to throw ' + - matchersUtil.pp(expected) + - ', but it threw ' + - matchersUtil.pp(thrown) + - '.' - ); - }; - } - - return result; - } - }; - } - - return toThrow; -}; - -getJasmineRequireObj().toThrowError = function(j$) { - 'use strict'; - - const getErrorMsg = j$.private.formatErrorMsg( - '', - 'expect(function() {}).toThrowError(, )' - ); - - /** - * {@link expect} a function to `throw` an `Error`. - * @function - * @name matchers#toThrowError - * @since 2.0.0 - * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. - * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` - * @example - * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message'); - * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/); - * expect(function() { return 'stuff'; }).toThrowError(MyCustomError); - * expect(function() { return 'other'; }).toThrowError(/foo/); - * expect(function() { return 'other'; }).toThrowError(); - */ - function toThrowError(matchersUtil) { - return { - compare: function(actual) { - const errorMatcher = getMatcher.apply(null, arguments); - - if (typeof actual != 'function') { - throw new Error(getErrorMsg('Actual is not a Function')); - } - - let thrown; - - try { - actual(); - return fail('Expected function to throw an Error.'); - } catch (e) { - thrown = e; - } - - if (!j$.private.isError(thrown)) { - return fail(function() { - return ( - 'Expected function to throw an Error, but it threw ' + - matchersUtil.pp(thrown) + - '.' - ); - }); - } - - return errorMatcher.match(thrown); - } - }; - - function getMatcher() { - let expected, errorType; - - if (arguments[2]) { - errorType = arguments[1]; - expected = arguments[2]; - if (!isAnErrorType(errorType)) { - throw new Error(getErrorMsg('Expected error type is not an Error.')); - } - - return exactMatcher(expected, errorType); - } else if (arguments[1]) { - expected = arguments[1]; - - if (isAnErrorType(arguments[1])) { - return exactMatcher(null, arguments[1]); - } else { - return exactMatcher(arguments[1], null); - } - } else { - return anyMatcher(); - } - } - - function anyMatcher() { - return { - match: function(error) { - return pass( - 'Expected function not to throw an Error, but it threw ' + - j$.private.fnNameFor(error) + - '.' - ); - } - }; - } - - function exactMatcher(expected, errorType) { - if (expected && !isStringOrRegExp(expected)) { - if (errorType) { - throw new Error( - getErrorMsg('Expected error message is not a string or RegExp.') - ); - } else { - throw new Error( - getErrorMsg('Expected is not an Error, string, or RegExp.') - ); - } - } - - function messageMatch(message) { - if (typeof expected == 'string') { - return expected == message; - } else { - return expected.test(message); - } - } - - const errorTypeDescription = errorType - ? j$.private.fnNameFor(errorType) - : 'an exception'; - - function thrownDescription(thrown) { - const thrownName = errorType - ? j$.private.fnNameFor(thrown.constructor) - : 'an exception'; - let thrownMessage = ''; - - if (expected) { - thrownMessage = ' with message ' + matchersUtil.pp(thrown.message); - } - - return thrownName + thrownMessage; - } - - function messageDescription() { - if (expected === null) { - return ''; - } else if (expected instanceof RegExp) { - return ' with a message matching ' + matchersUtil.pp(expected); - } else { - return ' with message ' + matchersUtil.pp(expected); - } - } - - function matches(error) { - return ( - (errorType === null || error instanceof errorType) && - (expected === null || messageMatch(error.message)) - ); - } - - return { - match: function(thrown) { - if (matches(thrown)) { - return pass(function() { - return ( - 'Expected function not to throw ' + - errorTypeDescription + - messageDescription() + - '.' - ); - }); - } else { - return fail(function() { - return ( - 'Expected function to throw ' + - errorTypeDescription + - messageDescription() + - ', but it threw ' + - thrownDescription(thrown) + - '.' - ); - }); - } - } - }; - } - - function isStringOrRegExp(potential) { - return potential instanceof RegExp || typeof potential == 'string'; - } - - function isAnErrorType(type) { - if (typeof type !== 'function') { - return false; - } - - const Surrogate = function() {}; - Surrogate.prototype = type.prototype; - return j$.private.isError(new Surrogate()); - } - } - - function pass(message) { - return { - pass: true, - message: message - }; - } - - function fail(message) { - return { - pass: false, - message: message - }; - } - - return toThrowError; -}; - -getJasmineRequireObj().toThrowMatching = function(j$) { - 'use strict'; - - const usageError = j$.private.formatErrorMsg( - '', - 'expect(function() {}).toThrowMatching()' - ); - - /** - * {@link expect} a function to `throw` something matching a predicate. - * @function - * @name matchers#toThrowMatching - * @since 3.0.0 - * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches. - * @example - * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; }); - */ - function toThrowMatching(matchersUtil) { - return { - compare: function(actual, predicate) { - if (typeof actual !== 'function') { - throw new Error(usageError('Actual is not a Function')); - } - - if (typeof predicate !== 'function') { - throw new Error(usageError('Predicate is not a Function')); - } - - let thrown; - - try { - actual(); - return fail('Expected function to throw an exception.'); - } catch (e) { - thrown = e; - } - - if (predicate(thrown)) { - return pass( - 'Expected function not to throw an exception matching a predicate.' - ); - } else { - return fail(function() { - return ( - 'Expected function to throw an exception matching a predicate, ' + - 'but it threw ' + - thrownDescription(thrown) + - '.' - ); - }); - } - } - }; - - function thrownDescription(thrown) { - if (thrown && thrown.constructor) { - return ( - j$.private.fnNameFor(thrown.constructor) + - ' with message ' + - matchersUtil.pp(thrown.message) - ); - } else { - return matchersUtil.pp(thrown); - } - } - } - - function pass(message) { - return { - pass: true, - message: message - }; - } - - function fail(message) { - return { - pass: false, - message: message - }; - } - - return toThrowMatching; -}; - -getJasmineRequireObj().MockDate = function(j$) { - 'use strict'; - - function MockDate(global) { - let currentTime = 0; - - if (!global || !global.Date) { - this.install = function() {}; - this.tick = function() {}; - this.uninstall = function() {}; - return this; - } - - const GlobalDate = global.Date; - - this.install = function(mockDate) { - if (mockDate instanceof GlobalDate) { - currentTime = mockDate.getTime(); - } else { - if (mockDate !== undefined) { - throw new Error( - 'The argument to jasmine.clock().mockDate(), if specified, ' + - 'should be a Date instance.' - ); - } - - currentTime = new GlobalDate().getTime(); - } - - global.Date = FakeDate; - }; - - this.tick = function(millis) { - millis = millis || 0; - currentTime = currentTime + millis; - }; - - this.uninstall = function() { - currentTime = 0; - global.Date = GlobalDate; - }; - - createDateProperties(); - - return this; - - function FakeDate() { - switch (arguments.length) { - case 0: - return new GlobalDate(currentTime); - case 1: - return new GlobalDate(arguments[0]); - case 2: - return new GlobalDate(arguments[0], arguments[1]); - case 3: - return new GlobalDate(arguments[0], arguments[1], arguments[2]); - case 4: - return new GlobalDate( - arguments[0], - arguments[1], - arguments[2], - arguments[3] - ); - case 5: - return new GlobalDate( - arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4] - ); - case 6: - return new GlobalDate( - arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4], - arguments[5] - ); - default: - return new GlobalDate( - arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4], - arguments[5], - arguments[6] - ); - } - } - - function createDateProperties() { - FakeDate.prototype = GlobalDate.prototype; - - FakeDate.now = function() { - return currentTime; - }; - - FakeDate.toSource = GlobalDate.toSource; - FakeDate.toString = GlobalDate.toString; - FakeDate.parse = GlobalDate.parse; - FakeDate.UTC = GlobalDate.UTC; - } - } - - return MockDate; -}; - -getJasmineRequireObj().NeverSkipPolicy = function(j$) { - 'use strict'; - - function NeverSkipPolicy(queueableFns) {} - - NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { - return lastRanFnIx + 1; - }; - - NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; - - return NeverSkipPolicy; -}; - -getJasmineRequireObj().ParallelReportDispatcher = function(j$) { - 'use strict'; - - /** - * @class ParallelReportDispatcher - * @implements Reporter - * @classdesc A report dispatcher packaged for convenient use from outside jasmine-core. - * - * This is intended to help packages like `jasmine` (the Jasmine runner for - * Node.js) do their own report dispatching in order to support parallel - * execution. If you aren't implementing a runner package that supports - * parallel execution, this class probably isn't what you're looking for. - * - * Warning: Do not use ParallelReportDispatcher in the same process that - * Jasmine specs run in. Doing so will break Jasmine's error handling. - * @param onError {function} Function called when an unhandled exception, unhandled promise rejection, or explicit reporter failure occurs - */ - function ParallelReportDispatcher(onError, deps = {}) { - const ReportDispatcher = - deps.ReportDispatcher || j$.private.ReportDispatcher; - const QueueRunner = deps.QueueRunner || j$.private.QueueRunner; - const globalErrors = deps.globalErrors || new j$.private.GlobalErrors(); - const dispatcher = new ReportDispatcher( - j$.private.reporterEvents, - function(queueRunnerOptions) { - queueRunnerOptions = { - ...queueRunnerOptions, - globalErrors, - timeout: { setTimeout, clearTimeout }, - fail: function(error) { - // A callback-style async reporter called either done.fail() - // or done(anError). - if (!error) { - error = new Error('A reporter called done.fail()'); - } - - onError(error); - }, - onException: function(error) { - // A reporter method threw an exception or returned a rejected - // promise, or there was an unhandled exception or unhandled promise - // rejection while an asynchronous reporter method was running. - onError(error); - } - }; - new QueueRunner(queueRunnerOptions).execute(); - }, - function(error) { - // A reporter called done() more than once. - onError(error); - } - ); - - const self = { - /** - * Adds a reporter to the list of reporters that events will be dispatched to. - * @function - * @name ParallelReportDispatcher#addReporter - * @param {Reporter} reporterToAdd The reporter to be added. - * @see custom_reporter - */ - addReporter: dispatcher.addReporter.bind(dispatcher), - /** - * Clears all registered reporters. - * @function - * @name ParallelReportDispatcher#clearReporters - */ - clearReporters: dispatcher.clearReporters.bind(dispatcher), - /** - * Installs a global error handler. After this method is called, any - * unhandled exceptions or unhandled promise rejections will be passed to - * the onError callback that was passed to the constructor. - * @function - * @name ParallelReportDispatcher#installGlobalErrors - */ - installGlobalErrors: globalErrors.install.bind(globalErrors), - /** - * Uninstalls the global error handler. - * @function - * @name ParallelReportDispatcher#uninstallGlobalErrors - */ - uninstallGlobalErrors: function() { - // late-bind uninstall because it doesn't exist until install is called - globalErrors.uninstall(globalErrors); - } - }; - - for (const eventName of j$.private.reporterEvents) { - self[eventName] = dispatcher[eventName].bind(dispatcher); - } - - return self; - } - - return ParallelReportDispatcher; -}; - -getJasmineRequireObj().makePrettyPrinter = function(j$) { - 'use strict'; - - class SinglePrettyPrintRun { - constructor(customObjectFormatters, pp) { - this.customObjectFormatters_ = customObjectFormatters; - this.ppNestLevel_ = 0; - this.seen = []; - this.length = 0; - this.stringParts = []; - this.pp_ = pp; - } - - format(value) { - this.ppNestLevel_++; - try { - const customFormatResult = this.applyCustomFormatters_(value); - - if (customFormatResult) { - this.emitScalar(customFormatResult); - } else if (value === undefined) { - this.emitScalar('undefined'); - } else if (value === null) { - this.emitScalar('null'); - } else if (value === 0 && 1 / value === -Infinity) { - this.emitScalar('-0'); - } else if (value === j$.getGlobal()) { - this.emitScalar(''); - } else if (value.jasmineToString) { - this.emitScalar(value.jasmineToString(this.pp_)); - } else if (j$.private.isString(value)) { - this.emitString(value); - } else if (j$.isSpy(value)) { - this.emitScalar('spy on ' + value.and.identity); - } else if (j$.isSpy(value.toString)) { - this.emitScalar('spy on ' + value.toString.and.identity); - } else if (value instanceof RegExp) { - this.emitScalar(value.toString()); - } else if (typeof value === 'function') { - if (value.name) { - this.emitScalar(`Function '${value.name}'`); - } else { - this.emitScalar('Function'); - } - } else if (j$.private.isDomNode(value)) { - if (value.tagName) { - this.emitDomElement(value); - } else { - this.emitScalar('HTMLNode'); - } - } else if (value instanceof Date) { - this.emitScalar('Date(' + value + ')'); - } else if (j$.private.isSet(value)) { - this.emitSet(value); - } else if (j$.private.isMap(value)) { - this.emitMap(value); - } else if (j$.private.isTypedArray(value)) { - this.emitTypedArray(value); - } else if ( - value.toString && - typeof value === 'object' && - !Array.isArray(value) && - hasCustomToString(value) - ) { - try { - this.emitScalar(value.toString()); - // eslint-disable-next-line no-unused-vars - } catch (e) { - this.emitScalar('has-invalid-toString-method'); - } - } else if (this.seen.includes(value)) { - this.emitScalar( - '' - ); - } else if (Array.isArray(value) || j$.private.isA('Object', value)) { - this.seen.push(value); - if (Array.isArray(value)) { - this.emitArray(value); - } else { - this.emitObject(value); - } - this.seen.pop(); - } else { - this.emitScalar(value.toString()); - } - } catch (e) { - if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) { - throw e; - } - } finally { - this.ppNestLevel_--; - } - } - - applyCustomFormatters_(value) { - return customFormat(value, this.customObjectFormatters_); - } - - iterateObject(obj, fn) { - const objKeys = j$.private.MatchersUtil.keys(obj, Array.isArray(obj)); - const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); - - for (let i = 0; i < length; i++) { - fn(objKeys[i]); - } - - return objKeys.length > length; - } - - emitScalar(value) { - this.append(value); - } - - emitString(value) { - this.append("'" + value + "'"); - } - - emitArray(array) { - if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { - this.append('Array'); - return; - } - - const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); - this.append('[ '); - - for (let i = 0; i < length; i++) { - if (i > 0) { - this.append(', '); - } - this.format(array[i]); - } - if (array.length > length) { - this.append(', ...'); - } - - let first = array.length === 0; - const wasTruncated = this.iterateObject(array, property => { - if (first) { - first = false; - } else { - this.append(', '); - } - - this.formatProperty(array, property); - }); - - if (wasTruncated) { - this.append(', ...'); - } - - this.append(' ]'); - } - - emitSet(set) { - if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { - this.append('Set'); - return; - } - this.append('Set( '); - const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); - let i = 0; - set.forEach(function(value, key) { - if (i >= size) { - return; - } - if (i > 0) { - this.append(', '); - } - this.format(value); - - i++; - }, this); - if (set.size > size) { - this.append(', ...'); - } - this.append(' )'); - } - - emitMap(map) { - if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { - this.append('Map'); - return; - } - this.append('Map( '); - const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); - let i = 0; - map.forEach(function(value, key) { - if (i >= size) { - return; - } - if (i > 0) { - this.append(', '); - } - this.format([key, value]); - - i++; - }, this); - if (map.size > size) { - this.append(', ...'); - } - this.append(' )'); - } - - emitObject(obj) { - const ctor = obj.constructor; - const constructorName = - typeof ctor === 'function' && obj instanceof ctor - ? j$.private.fnNameFor(obj.constructor) - : 'null'; - - this.append(constructorName); - - if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { - return; - } - - this.append('({ '); - let first = true; - - const wasTruncated = this.iterateObject(obj, property => { - if (first) { - first = false; - } else { - this.append(', '); - } - - this.formatProperty(obj, property); - }); - - if (wasTruncated) { - this.append(', ...'); - } - - this.append(' })'); - } - - emitTypedArray(arr) { - const constructorName = j$.private.fnNameFor(arr.constructor); - const limitedArray = Array.prototype.slice.call( - arr, - 0, - j$.MAX_PRETTY_PRINT_ARRAY_LENGTH - ); - let itemsString = Array.prototype.join.call(limitedArray, ', '); - - if (limitedArray.length !== arr.length) { - itemsString += ', ...'; - } - - this.append(constructorName + ' [ ' + itemsString + ' ]'); - } - - emitDomElement(el) { - const tagName = el.tagName.toLowerCase(); - let out = '<' + tagName; - - for (const attr of el.attributes) { - out += ' ' + attr.name; - - if (attr.value !== '') { - out += '="' + attr.value + '"'; - } - } - - out += '>'; - - if (el.childElementCount !== 0 || el.textContent !== '') { - out += '...'; - } - - this.append(out); - } - - formatProperty(obj, property) { - if (typeof property === 'symbol') { - this.append(property.toString()); - } else { - this.append(property); - } - - this.append(': '); - this.format(obj[property]); - } - - append(value) { - // This check protects us from the rare case where an object has overriden - // `toString()` with an invalid implementation (returning a non-string). - if (typeof value !== 'string') { - value = Object.prototype.toString.call(value); - } - - const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length); - this.length += result.value.length; - this.stringParts.push(result.value); - - if (result.truncated) { - throw new MaxCharsReachedError(); - } - } - } - - function hasCustomToString(value) { - // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g. - // iframe, web worker) - try { - return ( - j$.private.isFunction(value.toString) && - value.toString !== Object.prototype.toString && - value.toString() !== Object.prototype.toString.call(value) - ); - // eslint-disable-next-line no-unused-vars - } catch (e) { - // The custom toString() threw. - return true; - } - } - - function truncate(s, maxlen) { - if (s.length <= maxlen) { - return { value: s, truncated: false }; - } - - s = s.substring(0, maxlen - 4) + ' ...'; - return { value: s, truncated: true }; - } - - function MaxCharsReachedError() { - this.message = - 'Exceeded ' + - j$.MAX_PRETTY_PRINT_CHARS + - ' characters while pretty-printing a value'; - } - - MaxCharsReachedError.prototype = new Error(); - - function customFormat(value, customObjectFormatters) { - for (const formatter of customObjectFormatters) { - const result = formatter(value); - - if (result !== undefined) { - return result; - } - } - } - - return function(customObjectFormatters) { - customObjectFormatters = customObjectFormatters || []; - - const pp = function(value) { - const prettyPrinter = new SinglePrettyPrintRun( - customObjectFormatters, - pp - ); - prettyPrinter.format(value); - return prettyPrinter.stringParts.join(''); - }; - - pp.customFormat_ = function(value) { - return customFormat(value, customObjectFormatters); - }; - - return pp; - }; -}; - -getJasmineRequireObj().QueueRunner = function(j$) { - 'use strict'; - - let nextid = 1; - - function StopExecutionError() {} - StopExecutionError.prototype = new Error(); - j$.private.StopExecutionError = StopExecutionError; - - function once(fn, onTwice) { - let called = false; - return function(arg) { - if (called) { - if (onTwice) { - onTwice(); - } - } else { - called = true; - // Direct call using single parameter, because cleanup/next does not need more - fn(arg); - } - return null; - }; - } - - function fallbackOnMultipleDone() { - // eslint-disable-next-line no-console - console.error( - new Error( - "An asynchronous function called its 'done' " + - 'callback more than once, in a QueueRunner without a onMultipleDone ' + - 'handler.' - ) - ); - } - - function emptyFn() {} - - function QueueRunner(attrs) { - this.id_ = nextid++; - this.queueableFns = attrs.queueableFns || []; - - for (const f of this.queueableFns) { - if (!f) { - throw new Error('Received a falsy queueableFn'); - } - - if (!f.fn) { - throw new Error('Received a queueableFn with no fn'); - } - } - - this.onComplete = attrs.onComplete || emptyFn; - this.clearStack = attrs.clearStack || { - clearStack(fn) { - fn(); - } - }; - this.onException = attrs.onException || emptyFn; - this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone; - this.userContext = attrs.userContext || new j$.private.UserContext(); - this.timeout = attrs.timeout || { - setTimeout: setTimeout, - clearTimeout: clearTimeout - }; - this.fail = attrs.fail || emptyFn; - this.globalErrors = attrs.globalErrors || { - pushListener: emptyFn, - popListener: emptyFn - }; - - const SkipPolicy = attrs.SkipPolicy || j$.private.NeverSkipPolicy; - this.skipPolicy_ = new SkipPolicy(this.queueableFns); - this.errored_ = false; - - if (typeof this.onComplete !== 'function') { - throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); - } - } - - QueueRunner.prototype.execute = function() { - this.handleFinalError = error => { - this.onException(error); - }; - this.globalErrors.pushListener(this.handleFinalError); - this.run(0); - }; - - QueueRunner.prototype.clearTimeout = function(timeoutId) { - Function.prototype.apply.apply(this.timeout.clearTimeout, [ - j$.getGlobal(), - [timeoutId] - ]); - }; - - QueueRunner.prototype.setTimeout = function(fn, timeout) { - return Function.prototype.apply.apply(this.timeout.setTimeout, [ - j$.getGlobal(), - [fn, timeout] - ]); - }; - - QueueRunner.prototype.attempt = function attempt(iterativeIndex) { - let timeoutId; - let timedOut; - let completedSynchronously = true; - - const onException = e => { - this.onException(e); - this.recordError_(iterativeIndex); - }; - - function handleError(error) { - onException(error); - } - const cleanup = once(() => { - if (timeoutId !== void 0) { - this.clearTimeout(timeoutId); - } - this.globalErrors.popListener(handleError); - }); - const next = once( - err => { - cleanup(); - - if (typeof err !== 'undefined') { - if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { - this.fail(err); - } - this.recordError_(iterativeIndex); - } - - const runNext = () => { - this.run(this.nextFnIx_(iterativeIndex)); - }; - - if (completedSynchronously) { - this.setTimeout(runNext); - } else { - runNext(); - } - }, - () => { - try { - if (!timedOut) { - this.onMultipleDone(); - } - } catch (error) { - // Any error we catch here is probably due to a bug in Jasmine, - // and it's not likely to end up anywhere useful if we let it - // propagate. Log it so it can at least show up when debugging. - // eslint-disable-next-line no-console - console.error(error); - } - } - ); - timedOut = false; - const queueableFn = this.queueableFns[iterativeIndex]; - - next.fail = function nextFail() { - this.fail.apply(null, arguments); - this.recordError_(iterativeIndex); - next(); - }.bind(this); - - this.globalErrors.pushListener(handleError); - - if (queueableFn.timeout !== undefined) { - const timeoutInterval = - queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL; - timeoutId = this.setTimeout(function() { - timedOut = true; - const error = new Error( - 'Timeout - Async function did not complete within ' + - timeoutInterval + - 'ms ' + - (queueableFn.timeout - ? '(custom timeout)' - : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') - ); - // TODO Need to decide what to do about a successful completion after a - // timeout. That should probably not be a deprecation, and maybe not - // an error in 4.0. (But a diagnostic of some sort might be helpful.) - onException(error); - next(); - }, timeoutInterval); - } - - try { - let maybeThenable; - - if (queueableFn.fn.length === 0) { - maybeThenable = queueableFn.fn.call(this.userContext); - - if (maybeThenable && j$.private.isFunction(maybeThenable.then)) { - maybeThenable.then( - wrapInPromiseResolutionHandler(next), - onPromiseRejection - ); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } else { - maybeThenable = queueableFn.fn.call(this.userContext, next); - this.diagnoseConflictingAsync_(queueableFn.fn, maybeThenable); - completedSynchronously = false; - return { completedSynchronously: false }; - } - } catch (e) { - onException(e); - this.recordError_(iterativeIndex); - } - - cleanup(); - return { completedSynchronously: true }; - - function onPromiseRejection(e) { - onException(e); - next(); - } - }; - - QueueRunner.prototype.run = function(recursiveIndex) { - const length = this.queueableFns.length; - - for ( - let iterativeIndex = recursiveIndex; - iterativeIndex < length; - iterativeIndex = this.nextFnIx_(iterativeIndex) - ) { - const result = this.attempt(iterativeIndex); - - if (!result.completedSynchronously) { - return; - } - } - - this.clearStack.clearStack(() => { - this.globalErrors.popListener(this.handleFinalError); - - if (this.errored_) { - this.onComplete(new StopExecutionError()); - } else { - this.onComplete(); - } - }); - }; - - QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { - const result = this.skipPolicy_.skipTo(currentFnIx); - - if (result === currentFnIx) { - throw new Error("Can't skip to the same queueable fn that just finished"); - } - - return result; - }; - - QueueRunner.prototype.recordError_ = function(currentFnIx) { - this.errored_ = true; - this.skipPolicy_.fnErrored(currentFnIx); - }; - - QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { - if (retval && j$.private.isFunction(retval.then)) { - // Issue a warning that matches the user's code. - // Omit the stack trace because there's almost certainly no user code - // on the stack at this point. - if (j$.private.isAsyncFunction(fn)) { - this.onException( - new Error( - 'An asynchronous before/it/after ' + - 'function was defined with the async keyword but also took a ' + - 'done callback. Either remove the done callback (recommended) or ' + - 'remove the async keyword.' - ) - ); - } else { - this.onException( - new Error( - 'An asynchronous before/it/after ' + - 'function took a done callback but also returned a promise. ' + - 'Either remove the done callback (recommended) or change the ' + - 'function to not return a promise.' - ) - ); - } - } - }; - - function wrapInPromiseResolutionHandler(fn) { - return function(maybeArg) { - if (j$.private.isError(maybeArg)) { - fn(maybeArg); - } else { - fn(); - } - }; - } - - return QueueRunner; -}; - -getJasmineRequireObj().ReportDispatcher = function(j$) { - 'use strict'; - - function ReportDispatcher(methods, runQueue, onLateError) { - const dispatchedMethods = methods || []; - - for (const method of dispatchedMethods) { - this[method] = (function(m) { - return function(event) { - return dispatch(m, event); - }; - })(method); - } - - let reporters = []; - let fallbackReporter = null; - - this.addReporter = function(reporter) { - reporters.push(reporter); - }; - - this.provideFallbackReporter = function(reporter) { - fallbackReporter = reporter; - }; - - this.clearReporters = function() { - reporters = []; - }; - - return this; - - function dispatch(method, event) { - if (reporters.length === 0 && fallbackReporter !== null) { - reporters.push(fallbackReporter); - } - const fns = []; - for (const reporter of reporters) { - addFn(fns, reporter, method, event); - } - - return new Promise(function(resolve) { - runQueue({ - queueableFns: fns, - onComplete: resolve, - isReporter: true, - onMultipleDone: function() { - onLateError( - new Error( - "An asynchronous reporter callback called its 'done' callback " + - 'more than once.' - ) - ); - } - }); - }); - } - - function addFn(fns, reporter, method, event) { - const fn = reporter[method]; - if (!fn) { - return; - } - - const thisEvent = structuredClone(event); - if (fn.length <= 1) { - fns.push({ - fn: function() { - return fn.call(reporter, thisEvent); - } - }); - } else { - fns.push({ - fn: function(done) { - return fn.call(reporter, thisEvent, done); - } - }); - } - } - } - - return ReportDispatcher; -}; - -getJasmineRequireObj().reporterEvents = function(j$) { - 'use strict'; - - /** - * Used to tell Jasmine what optional or uncommonly implemented features - * the reporter supports. If not specified, the defaults described in - * {@link ReporterCapabilities} will apply. - * @name Reporter#reporterCapabilities - * @type ReporterCapabilities | undefined - * @since 5.0 - */ - /** - * Used to tell Jasmine what optional or uncommonly implemented features - * the reporter supports. - * @interface ReporterCapabilities - * @see Reporter#reporterCapabilities - * @since 5.0 - */ - /** - * Indicates whether the reporter supports parallel execution. Jasmine will - * not allow parallel execution unless all reporters that are in use set this - * capability to true. - * @name ReporterCapabilities#parallel - * @type boolean | undefined - * @default false - * @see running_specs_in_parallel - * @since 5.0 - */ - - const events = [ - /** - * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts. - * @function - * @name Reporter#jasmineStarted - * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'jasmineStarted', - /** - * When the entire suite has finished execution `jasmineDone` is called - * @function - * @name Reporter#jasmineDone - * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running. - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'jasmineDone', - /** - * `suiteStarted` is invoked when a `describe` starts to run - * @function - * @name Reporter#suiteStarted - * @param {SuiteStartedEvent} result Information about the individual {@link describe} being run - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'suiteStarted', - /** - * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run - * - * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`. - * @function - * @name Reporter#suiteDone - * @param {SuiteDoneEvent} result - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'suiteDone', - /** - * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions) - * @function - * @name Reporter#specStarted - * @param {SpecStartedEvent} result Information about the individual {@link it} being run - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'specStarted', - /** - * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run. - * - * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed. - * @function - * @name Reporter#specDone - * @param {SpecDoneEvent} result - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - * @see async - */ - 'specDone' - ]; - Object.freeze(events); - return events; -}; - -getJasmineRequireObj().interface = function(jasmine, env) { - 'use strict'; - - const jasmineInterface = { - /** - * Callback passed to parts of the Jasmine base interface. - * - * By default Jasmine assumes this function completes synchronously. - * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment. - * @callback implementationCallback - * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. - * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. - */ - - /** - * Create a group of specs (often called a suite). - * - * Calls to `describe` can be nested within other calls to compose your suite as a tree. - * @name describe - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of the group - * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs - */ - describe: function(description, specDefinitions) { - return env.describe(description, specDefinitions); - }, - - /** - * A temporarily disabled [`describe`]{@link describe} - * - * Specs within an `xdescribe` will be marked pending and not executed - * @name xdescribe - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of the group - * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs - */ - xdescribe: function(description, specDefinitions) { - return env.xdescribe(description, specDefinitions); - }, - - /** - * A focused [`describe`]{@link describe} - * - * If suites or specs are focused, only those that are focused will be executed - * @see fit - * @name fdescribe - * @since 2.1.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of the group - * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs - */ - fdescribe: function(description, specDefinitions) { - return env.fdescribe(description, specDefinitions); - }, - - /** - * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code. - * - * A spec whose expectations all succeed will be passing and a spec with any failures will fail. - * The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the - * spec more readable by connecting the function name `it` and the argument `description` as a - * complete sentence. - * @name it - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of what this spec is checking - * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. - * @see async - */ - it: function() { - return env.it.apply(env, arguments); - }, - - /** - * A temporarily disabled [`it`]{@link it} - * - * The spec will report as `pending` and will not be executed. - * @name xit - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of what this spec is checking. - * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed. - */ - xit: function() { - return env.xit.apply(env, arguments); - }, - - /** - * A focused [`it`]{@link it} - * - * If suites or specs are focused, only those that are focused will be executed. - * @name fit - * @since 2.1.0 - * @function - * @global - * @overwritable - * @param {String} description Textual description of what this spec is checking. - * @param {implementationCallback} testFunction Function that contains the code of your test. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. - * @see async - */ - fit: function() { - return env.fit.apply(env, arguments); - }, - - /** - * Run some shared setup before each of the specs in the {@link describe} in which it is called. - * @name beforeEach - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {implementationCallback} [function] Function that contains the code to setup your specs. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. - * @see async - */ - beforeEach: function() { - return env.beforeEach.apply(env, arguments); - }, - - /** - * Run some shared teardown after each of the specs in the {@link describe} in which it is called. - * @name afterEach - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {implementationCallback} [function] Function that contains the code to teardown your specs. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. - * @see async - */ - afterEach: function() { - return env.afterEach.apply(env, arguments); - }, - - /** - * Run some shared setup once before all of the specs in the {@link describe} are run. - * - * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. - * @name beforeAll - * @since 2.1.0 - * @function - * @global - * @overwritable - * @param {implementationCallback} [function] Function that contains the code to setup your specs. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. - * @see async - */ - beforeAll: function() { - return env.beforeAll.apply(env, arguments); - }, - - /** - * Run some shared teardown once after all of the specs in the {@link describe} are run. - * - * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. - * @name afterAll - * @since 2.1.0 - * @function - * @global - * @overwritable - * @param {implementationCallback} [function] Function that contains the code to teardown your specs. - * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. - * @see async - */ - afterAll: function() { - return env.afterAll.apply(env, arguments); - }, - - /** - * Get a user-defined property as part of the properties field of {@link SpecResult} - * @name getSpecProperty - * @since 5.10.0 - * @function - * @global - * @overwritable - * @param {String} key The name of the property - * @returns {*} The value of the property - */ - getSpecProperty: function(key) { - return env.getSpecProperty(key); - }, - - /** - * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} - * @name setSpecProperty - * @since 3.6.0 - * @function - * @global - * @overwritable - * @param {String} key The name of the property - * @param {*} value The value of the property - */ - setSpecProperty: function(key, value) { - return env.setSpecProperty(key, value); - }, - - /** - * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} - * @name setSuiteProperty - * @since 3.6.0 - * @function - * @global - * @overwritable - * @param {String} key The name of the property - * @param {*} value The value of the property - */ - setSuiteProperty: function(key, value) { - return env.setSuiteProperty(key, value); - }, - - /** - * Create an expectation for a spec. - * @name expect - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {Object} actual - Actual computed value to test expectations against. - * @return {matchers} - */ - expect: function(actual) { - return env.expect(actual); - }, - - /** - * Create an asynchronous expectation for a spec. Note that the matchers - * that are provided by an asynchronous expectation all return promises - * which must be either returned from the spec or waited for using `await` - * in order for Jasmine to associate them with the correct spec. - * @name expectAsync - * @since 3.3.0 - * @function - * @global - * @overwritable - * @param {Object} actual - Actual computed value to test expectations against. - * @return {async-matchers} - * @example - * await expectAsync(somePromise).toBeResolved(); - * @example - * return expectAsync(somePromise).toBeResolved(); - */ - expectAsync: function(actual) { - return env.expectAsync(actual); - }, - - /** - * Create an asynchronous expectation for a spec and throw an error if it fails. - * - * This is intended to allow Jasmine matchers to be used with tools like - * testing-library's `waitFor`, which expect matcher failures to throw - * exceptions and not trigger a spec failure if the exception is caught. - * It can also be used to integration-test custom matchers. - * - * If the resulting expectation fails, a {@link ThrowUnlessFailure} will be - * thrown. A failed expectation will not result in a spec failure unless the - * exception propagates back to Jasmine, either via the call stack or via - * the global unhandled exception/unhandled promise rejection events. - * @name throwUnlessAsync - * @since 5.1.0 - * @function - * @global - * @overwritable - * @param {Object} actual - Actual computed value to test expectations against. - * @return {matchers} - */ - throwUnlessAsync: function(actual) { - return env.throwUnlessAsync(actual); - }, - - /** - * Create an expectation for a spec and throw an error if it fails. - * - * This is intended to allow Jasmine matchers to be used with tools like - * testing-library's `waitFor`, which expect matcher failures to throw - * exceptions and not trigger a spec failure if the exception is caught. - * It can also be used to integration-test custom matchers. - * - * If the resulting expectation fails, a {@link ThrowUnlessFailure} will be - * thrown. A failed expectation will not result in a spec failure unless the - * exception propagates back to Jasmine, either via the call stack or via - * the global unhandled exception/unhandled promise rejection events. - * @name throwUnless - * @since 5.1.0 - * @function - * @global - * @overwritable - * @param {Object} actual - Actual computed value to test expectations against. - * @return {matchers} - */ - throwUnless: function(actual) { - return env.throwUnless(actual); - }, - - /** - * Mark a spec as pending, expectation results will be ignored. - * @name pending - * @since 2.0.0 - * @function - * @global - * @overwritable - * @param {String} [message] - Reason the spec is pending. - */ - pending: function() { - return env.pending.apply(env, arguments); - }, - - /** - * Explicitly mark a spec as failed. - * @name fail - * @since 2.1.0 - * @function - * @global - * @overwritable - * @param {String|Error} [error] - Reason for the failure. - */ - fail: function() { - return env.fail.apply(env, arguments); - }, - - /** - * Install a spy onto an existing object. - * @name spyOn - * @since 1.3.0 - * @function - * @global - * @overwritable - * @param {Object} obj - The object upon which to install the {@link Spy}. - * @param {String} methodName - The name of the method to replace with a {@link Spy}. - * @returns {Spy} - */ - spyOn: function(obj, methodName) { - return env.spyOn(obj, methodName); - }, - - /** - * Install a spy on a property installed with `Object.defineProperty` onto an existing object. - * @name spyOnProperty - * @since 2.6.0 - * @function - * @global - * @overwritable - * @param {Object} obj - The object upon which to install the {@link Spy} - * @param {String} propertyName - The name of the property to replace with a {@link Spy}. - * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on. - * @returns {Spy} - */ - spyOnProperty: function(obj, methodName, accessType) { - return env.spyOnProperty(obj, methodName, accessType); - }, - - /** - * Installs spies on all writable and configurable properties of an object. - * @name spyOnAllFunctions - * @since 3.2.1 - * @function - * @global - * @overwritable - * @param {Object} obj - The object upon which to install the {@link Spy}s - * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties - * @returns {Object} the spied object - */ - spyOnAllFunctions: function(obj, includeNonEnumerable) { - return env.spyOnAllFunctions(obj, includeNonEnumerable); - }, - - jsApiReporter: new jasmine.private.JsApiReporter({ - timer: new jasmine.Timer() - }), - - /** - *

Members of the jasmine global.

- *

Note: The members of the - * {@link asymmetricEqualityTesters|asymmetricEqualityTesters namespace} - * are also accessed via the jasmine global, but due to jsdoc limitations - * they are not listed here.

- * - * @namespace jasmine - */ - jasmine: jasmine - }; - const existingKeys = Object.keys(jasmine); - - /** - * Add a custom equality tester for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.addCustomEqualityTester - * @since 2.0.0 - * @function - * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise. - * @see custom_equality - */ - jasmine.addCustomEqualityTester = function(tester) { - env.addCustomEqualityTester(tester); - }; - - /** - * Add custom matchers for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.addMatchers - * @since 2.0.0 - * @function - * @param {Object} matchers - Keys from this object will be the new matcher names. - * @see custom_matcher - */ - jasmine.addMatchers = function(matchers) { - return env.addMatchers(matchers); - }; - - /** - * Add custom async matchers for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.addAsyncMatchers - * @since 3.5.0 - * @function - * @param {Object} matchers - Keys from this object will be the new async matcher names. - * @see custom_matcher - */ - jasmine.addAsyncMatchers = function(matchers) { - return env.addAsyncMatchers(matchers); - }; - - /** - * Add a custom object formatter for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.addCustomObjectFormatter - * @since 3.6.0 - * @function - * @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise. - * @see custom_object_formatters - */ - jasmine.addCustomObjectFormatter = function(formatter) { - return env.addCustomObjectFormatter(formatter); - }; - - /** - * Get the currently booted mock {Clock} for this Jasmine environment. - * @name jasmine.clock - * @since 2.0.0 - * @function - * @returns {Clock} - */ - jasmine.clock = function() { - return env.clock; - }; - - /** - * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it. - * @name jasmine.createSpy - * @since 1.3.0 - * @function - * @param {String} [name] - Name to give the spy. This will be displayed in failure messages. - * @param {Function} [originalFn] - The "real" function. This will - * be used for subsequent calls to the spy after you call - * `mySpy.and.callThrough()`. In most cases you should omit this parameter. - * The usual way to supply an original function is to call {@link spyOn} - * instead of createSpy. - * @return {Spy} - */ - jasmine.createSpy = function(name, originalFn) { - return env.createSpy(name, originalFn); - }; - - /** - * Create an object with multiple {@link Spy}s as its members. - * @name jasmine.createSpyObj - * @since 1.3.0 - * @function - * @param {String} [baseName] - Base name for the spies in the object. - * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}. - * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}. - * @return {Object} - */ - jasmine.createSpyObj = function(baseName, methodNames, propertyNames) { - return env.createSpyObj(baseName, methodNames, propertyNames); - }; - - /** - * Add a custom spy strategy for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.addSpyStrategy - * @since 3.5.0 - * @function - * @param {String} name - The name of the strategy (i.e. what you call from `and`) - * @param {Function} factory - Factory function that returns the plan to be executed. - */ - jasmine.addSpyStrategy = function(name, factory) { - return env.addSpyStrategy(name, factory); - }; - - /** - * Set the default spy strategy for the current scope of specs. - * - * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. - * @name jasmine.setDefaultSpyStrategy - * @function - * @param {Function} defaultStrategyFn - a function that assigns a strategy - * @example - * beforeEach(function() { - * jasmine.setDefaultSpyStrategy(and => and.returnValue(true)); - * }); - */ - jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) { - return env.setDefaultSpyStrategy(defaultStrategyFn); - }; - - /** - * Formats a value for display, taking into account the current set of - * custom object formatters. - * - * @name jasmine.pp - * @function - * @since 6.0.0 - * @param {*} value The value to pretty-print - * @return {string} The pretty-printed value - * @see {MatchersUtil#pp} - */ - jasmine.pp = function(value) { - return env.pp(value); - }; - - /** - * {@link AsymmetricEqualityTester|Asymmetric equality testers} allow for - * non-exact matching in matchers that use Jasmine's deep value equality - * semantics, such as {@link matchers#toEqual|toEqual}, - * {@link matchers#toContain|toContain}, and - * {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}. - * - * @example - * const someComplexObject = { - * foo: 'bar', - * baz: 'a string that contains "something"', - * qux: 'whatever' - * }; - * // Passes. - * expect(someComplexObject).toEqual(jasmine.objectContaining({ - * foo: 'bar', - * baz: jasmine.stringContaining('something') - * }); - * - * @namespace asymmetricEqualityTesters - */ - - jasmine.private.deprecateMonkeyPatching(jasmine, existingKeys); - - return jasmineInterface; -}; - -getJasmineRequireObj().RunableResources = function(j$) { - 'use strict'; - - class RunableResources { - constructor(options) { - this.byRunableId_ = {}; - this.getCurrentRunableId_ = options.getCurrentRunableId; - this.globalErrors_ = options.globalErrors; - - this.spyFactory = new j$.private.SpyFactory( - () => { - if (this.getCurrentRunableId_()) { - return this.customSpyStrategies(); - } else { - return {}; - } - }, - () => this.defaultSpyStrategy(), - () => this.makeMatchersUtil() - ); - - this.spyRegistry = new j$.private.SpyRegistry({ - currentSpies: () => this.spies(), - createSpy: (name, originalFn) => - this.spyFactory.createSpy(name, originalFn) - }); - } - - initForRunable(runableId, parentId) { - const newRes = (this.byRunableId_[runableId] = { - customEqualityTesters: [], - customMatchers: {}, - customAsyncMatchers: {}, - customSpyStrategies: {}, - customObjectFormatters: [], - defaultSpyStrategy: undefined, - spies: [] - }); - - const parentRes = this.byRunableId_[parentId]; - - if (parentRes) { - newRes.defaultSpyStrategy = parentRes.defaultSpyStrategy; - const toClone = [ - 'customEqualityTesters', - 'customMatchers', - 'customAsyncMatchers', - 'customObjectFormatters', - 'customSpyStrategies' - ]; - - for (const k of toClone) { - newRes[k] = j$.private.util.clone(parentRes[k]); - } - } - } - - clearForRunable(runableId) { - this.globalErrors_.removeOverrideListener(); - this.spyRegistry.clearSpies(); - delete this.byRunableId_[runableId]; - } - - spies() { - return this.forCurrentRunable_( - 'Spies must be created in a before function or a spec' - ).spies; - } - - defaultSpyStrategy() { - if (!this.getCurrentRunableId_()) { - return undefined; - } - - return this.byRunableId_[this.getCurrentRunableId_()].defaultSpyStrategy; - } - - setDefaultSpyStrategy(fn) { - this.forCurrentRunable_( - 'Default spy strategy must be set in a before function or a spec' - ).defaultSpyStrategy = fn; - } - - customSpyStrategies() { - return this.forCurrentRunable_( - 'Custom spy strategies must be added in a before function or a spec' - ).customSpyStrategies; - } - - customEqualityTesters() { - return this.forCurrentRunable_( - 'Custom Equalities must be added in a before function or a spec' - ).customEqualityTesters; - } - - customMatchers() { - return this.forCurrentRunable_( - 'Matchers must be added in a before function or a spec' - ).customMatchers; - } - - addCustomMatchers(matchersToAdd) { - const matchers = this.customMatchers(); - - for (const name in matchersToAdd) { - matchers[name] = matchersToAdd[name]; - } - } - - customAsyncMatchers() { - return this.forCurrentRunable_( - 'Async Matchers must be added in a before function or a spec' - ).customAsyncMatchers; - } - - addCustomAsyncMatchers(matchersToAdd) { - const matchers = this.customAsyncMatchers(); - - for (const name in matchersToAdd) { - matchers[name] = matchersToAdd[name]; - } - } - - customObjectFormatters() { - return this.forCurrentRunable_( - 'Custom object formatters must be added in a before function or a spec' - ).customObjectFormatters; - } - - makePrettyPrinter() { - return j$.private.makePrettyPrinter(this.customObjectFormatters()); - } - - makeMatchersUtil() { - if (this.getCurrentRunableId_()) { - return new j$.private.MatchersUtil({ - customTesters: this.customEqualityTesters(), - pp: this.makePrettyPrinter() - }); - } else { - return new j$.private.MatchersUtil({ - pp: j$.private.basicPrettyPrinter - }); - } - } - - forCurrentRunable_(errorMsg) { - const resources = this.byRunableId_[this.getCurrentRunableId_()]; - - if (!resources && errorMsg) { - throw new Error(errorMsg); - } - - return resources; - } - } - - return RunableResources; -}; - -getJasmineRequireObj().Runner = function(j$) { - 'use strict'; - - class Runner { - #topSuite; - #getTotalSpecsDefined; - #getFocusedRunables; - #runableResources; - #runQueue; - #TreeProcessor; - #executionTree; - #globalErrors; - #reportDispatcher; - #getConfig; - #executedBefore; - #currentRunableTracker; - - constructor(options) { - this.#topSuite = options.topSuite; - this.#getTotalSpecsDefined = options.totalSpecsDefined; - this.#getFocusedRunables = options.focusedRunables; - this.#runableResources = options.runableResources; - this.#runQueue = options.runQueue; - this.#TreeProcessor = options.TreeProcessor; - this.#globalErrors = options.globalErrors; - this.#reportDispatcher = options.reportDispatcher; - this.#getConfig = options.getConfig; - this.#executedBefore = false; - this.#currentRunableTracker = new j$.private.CurrentRunableTracker(); - } - - currentSpec() { - return this.#currentRunableTracker.currentSpec(); - } - - setCurrentSpec(spec) { - this.#currentRunableTracker.setCurrentSpec(spec); - } - - currentRunable() { - return this.#currentRunableTracker.currentRunable(); - } - - currentSuite() { - return this.#currentRunableTracker.currentSuite(); - } - - parallelReset() { - this.#executedBefore = false; - } - - async execute(runablesToRun) { - if (this.#executedBefore) { - this.#topSuite.reset(); - } - this.#executedBefore = true; - - const focusedRunables = this.#getFocusedRunables(); - const config = this.#getConfig(); - - if (!runablesToRun) { - if (focusedRunables.length) { - runablesToRun = focusedRunables; - } else { - runablesToRun = [this.#topSuite.id]; - } - } - - const order = new j$.private.Order({ - random: config.random, - seed: j$.private.isNumber(config.seed) ? config.seed + '' : config.seed - }); - - const treeProcessor = new this.#TreeProcessor({ - tree: this.#topSuite, - runnableIds: runablesToRun, - orderChildren: function(node) { - return order.sort(node.children); - }, - excludeNode: function(spec) { - return !config.specFilter(spec.metadata); - } - }); - this.#executionTree = treeProcessor.processTree(); - - return this.#execute2(runablesToRun, order); - } - - async #execute2(runablesToRun, order) { - const totalSpecsDefined = this.#getTotalSpecsDefined(); - - this.#runableResources.initForRunable(this.#topSuite.id); - const jasmineTimer = new j$.Timer(); - jasmineTimer.start(); - - /** - * Information passed to the {@link Reporter#jasmineStarted} event. - * @typedef JasmineStartedInfo - * @property {int} totalSpecsDefined - The total number of specs defined in this suite. Note that this property is not present when Jasmine is run in parallel mode. - * @property {int} numExcludedSpecs - The number of specs that will be excluded from execution. Note that this property is not present when Jasmine is run in parallel mode. - * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode. - * @property {Boolean} parallel - Whether Jasmine is being run in parallel mode. - * @since 2.0.0 - */ - await this.#reportDispatcher.jasmineStarted({ - // In parallel mode, the jasmineStarted event is separately dispatched - // by jasmine-npm. This event only reaches reporters in non-parallel. - totalSpecsDefined, - numExcludedSpecs: this.#executionTree.numExcludedSpecs(), - order: orderForReporting(order), - parallel: false - }); - - this.#currentRunableTracker.pushSuite(this.#topSuite); - const treeRunner = new j$.private.TreeRunner({ - executionTree: this.#executionTree, - globalErrors: this.#globalErrors, - runableResources: this.#runableResources, - reportDispatcher: this.#reportDispatcher, - runQueue: this.#runQueue, - getConfig: this.#getConfig, - currentRunableTracker: this.#currentRunableTracker - }); - const { hasFailures } = await treeRunner.execute(); - - this.#runableResources.clearForRunable(this.#topSuite.id); - this.#currentRunableTracker.popSuite(); - let overallStatus, incompleteReason, incompleteCode; - - if (hasFailures || this.#topSuite.hasOwnFailedExpectations()) { - overallStatus = 'failed'; - } else if (this.#getFocusedRunables().length > 0) { - overallStatus = 'incomplete'; - incompleteReason = 'fit() or fdescribe() was found'; - incompleteCode = 'focused'; - } else if (totalSpecsDefined === 0) { - overallStatus = 'incomplete'; - incompleteReason = 'No specs found'; - incompleteCode = 'noSpecsFound'; - } else { - overallStatus = 'passed'; - } - - const topSuiteResult = this.#topSuite.doneEvent(); - /** - * Information passed to the {@link Reporter#jasmineDone} event. - * @typedef JasmineDoneInfo - * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. - * @property {Int} totalTime - The total time (in ms) that it took to execute the suite - * @property {String} incompleteReason - Human-readable explanation of why the suite was incomplete. - * @property {String} incompleteCode - Machine-readable explanation of why the suite was incomplete: 'focused', 'noSpecsFound', or undefined. - * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode. - * @property {Int} numWorkers - Number of parallel workers. Note that this property is only present when Jasmine is run in parallel mode. - * @property {ExpectationResult[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. - * @property {ExpectationResult[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. - * @since 2.4.0 - */ - const jasmineDoneInfo = { - overallStatus: overallStatus, - totalTime: jasmineTimer.elapsed(), - incompleteReason: incompleteReason, - incompleteCode: incompleteCode, - order: orderForReporting(order), - failedExpectations: topSuiteResult.failedExpectations, - deprecationWarnings: topSuiteResult.deprecationWarnings - }; - this.#topSuite.reportedDone = true; - await this.#reportDispatcher.jasmineDone(jasmineDoneInfo); - return jasmineDoneInfo; - } - } - - /** - * Information about the ordering (random or not) of this execution of the suite. - * @typedef Order - * @property {boolean} random - Whether the suite is running in random order - * @property {string} seed - The random seed - */ - function orderForReporting(order) { - // Don't expose the actual Order object to reporters. That class is private - // and instances are not cloneable. - if (order.random) { - return { random: true, seed: order.seed }; - } else { - return { random: false }; - } - } - - return Runner; -}; - -getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { - 'use strict'; - - function SkipAfterBeforeAllErrorPolicy(queueableFns) { - this.queueableFns_ = queueableFns; - this.skipping_ = false; - } - - SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { - if (this.skipping_) { - return this.nextAfterAllAfter_(lastRanFnIx); - } else { - return lastRanFnIx + 1; - } - }; - - SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { - for ( - i++; - i < this.queueableFns_.length && - this.queueableFns_[i].type !== 'afterAll'; - i++ - ) {} - return i; - }; - - SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { - if (this.queueableFns_[fnIx].type === 'beforeAll') { - this.skipping_ = true; - // Failures need to be reported for each contained spec. But we can't do - // that from here because reporting is async. This function isn't async - // (and can't be without greatly complicating QueueRunner). Mark the - // failure so that the code that reports the suite result (which is - // already async) can detect the failure and report the specs. - this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true; - } - }; - - return SkipAfterBeforeAllErrorPolicy; -}; - -getJasmineRequireObj().Spy = function(j$) { - 'use strict'; - - const nextOrder = (function() { - let order = 0; - - return function() { - return order++; - }; - })(); - - /** - * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn}, - * {@link spyOnProperty}, {@link jasmine.createSpy}, or - * {@link jasmine.createSpyObj} instead. - * @class Spy - * @hideconstructor - */ - function Spy(name, matchersUtil, optionals) { - const spy = function(context, args, invokeNew) { - /** - * @name Spy.callData - * @property {object} object - `this` context for the invocation. - * @property {number} invocationOrder - Order of the invocation. - * @property {Array} args - The arguments passed for this invocation. - * @property returnValue - The value that was returned from this invocation. - */ - const callData = { - object: context, - invocationOrder: nextOrder(), - args: Array.prototype.slice.apply(args), - verified: false - }; - - callTracker.track(callData); - const returnValue = strategyDispatcher.exec(context, args, invokeNew); - callData.returnValue = returnValue; - - return returnValue; - }; - const { originalFn, customStrategies, defaultStrategyFn } = optionals || {}; - - const numArgs = typeof originalFn === 'function' ? originalFn.length : 0, - wrapper = makeFunc(numArgs, function(context, args, invokeNew) { - return spy(context, args, invokeNew); - }), - strategyDispatcher = new SpyStrategyDispatcher( - { - name: name, - fn: originalFn, - getSpy: function() { - return wrapper; - }, - customStrategies: customStrategies - }, - matchersUtil - ), - callTracker = new j$.private.CallTracker(); - - function makeFunc(length, fn) { - switch (length) { - case 1: - return function wrap1(a) { - return fn(this, arguments, this instanceof wrap1); - }; - case 2: - return function wrap2(a, b) { - return fn(this, arguments, this instanceof wrap2); - }; - case 3: - return function wrap3(a, b, c) { - return fn(this, arguments, this instanceof wrap3); - }; - case 4: - return function wrap4(a, b, c, d) { - return fn(this, arguments, this instanceof wrap4); - }; - case 5: - return function wrap5(a, b, c, d, e) { - return fn(this, arguments, this instanceof wrap5); - }; - case 6: - return function wrap6(a, b, c, d, e, f) { - return fn(this, arguments, this instanceof wrap6); - }; - case 7: - return function wrap7(a, b, c, d, e, f, g) { - return fn(this, arguments, this instanceof wrap7); - }; - case 8: - return function wrap8(a, b, c, d, e, f, g, h) { - return fn(this, arguments, this instanceof wrap8); - }; - case 9: - return function wrap9(a, b, c, d, e, f, g, h, i) { - return fn(this, arguments, this instanceof wrap9); - }; - default: - return function wrap() { - return fn(this, arguments, this instanceof wrap); - }; - } - } - - for (const prop in originalFn) { - if (prop === 'and' || prop === 'calls') { - throw new Error( - "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon" - ); - } - - wrapper[prop] = originalFn[prop]; - } - - /** - * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used - * whenever the spy is called with arguments that don't match any strategy - * created with {@link Spy#withArgs}. - * @name Spy#and - * @since 2.0.0 - * @example - * spyOn(someObj, 'func').and.returnValue(42); - */ - wrapper.and = strategyDispatcher.and; - /** - * Specifies a strategy to be used for calls to the spy that have the - * specified arguments. - * @name Spy#withArgs - * @since 3.0.0 - * @function - * @param {...*} args - The arguments to match - * @type {SpyStrategy} - * @example - * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42); - * someObj.func(1, 2, 3); // returns 42 - */ - wrapper.withArgs = function() { - return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments); - }; - wrapper.calls = callTracker; - - if (defaultStrategyFn) { - defaultStrategyFn(wrapper.and); - } - - return wrapper; - } - - function SpyStrategyDispatcher(strategyArgs, matchersUtil) { - const baseStrategy = new j$.private.SpyStrategy(strategyArgs); - const argsStrategies = new StrategyDict(function() { - return new j$.private.SpyStrategy(strategyArgs); - }, matchersUtil); - - this.and = baseStrategy; - - this.exec = function(spy, args, invokeNew) { - let strategy = argsStrategies.get(args); - - if (!strategy) { - if (argsStrategies.any() && !baseStrategy.isConfigured()) { - throw new Error( - "Spy '" + - strategyArgs.name + - "' received a call with arguments " + - matchersUtil.pp(Array.prototype.slice.call(args)) + - ' but all configured strategies specify other arguments.' - ); - } else { - strategy = baseStrategy; - } - } - - return strategy.exec(spy, args, invokeNew); - }; - - this.withArgs = function() { - return { and: argsStrategies.getOrCreate(arguments) }; - }; - } - - function StrategyDict(strategyFactory, matchersUtil) { - this.strategies = []; - this.strategyFactory = strategyFactory; - this.matchersUtil = matchersUtil; - } - - StrategyDict.prototype.any = function() { - return this.strategies.length > 0; - }; - - StrategyDict.prototype.getOrCreate = function(args) { - let strategy = this.get(args); - - if (!strategy) { - strategy = this.strategyFactory(); - this.strategies.push({ - args: args, - strategy: strategy - }); - } - - return strategy; - }; - - StrategyDict.prototype.get = function(args) { - for (let i = 0; i < this.strategies.length; i++) { - if (this.matchersUtil.equals(args, this.strategies[i].args)) { - return this.strategies[i].strategy; - } - } - }; - - return Spy; -}; - -getJasmineRequireObj().SpyFactory = function(j$) { - 'use strict'; - - function SpyFactory( - getCustomStrategies, - getDefaultStrategyFn, - getMatchersUtil - ) { - this.createSpy = function(name, originalFn) { - if (j$.private.isFunction(name) && originalFn === undefined) { - originalFn = name; - name = originalFn.name; - } - - return j$.private.Spy(name, getMatchersUtil(), { - originalFn, - customStrategies: getCustomStrategies(), - defaultStrategyFn: getDefaultStrategyFn() - }); - }; - - this.createSpyObj = function(baseName, methodNames, propertyNames) { - const baseNameIsCollection = - j$.private.isObject(baseName) || Array.isArray(baseName); - - if (baseNameIsCollection) { - propertyNames = methodNames; - methodNames = baseName; - baseName = 'unknown'; - } - - const obj = {}; - - const methods = normalizeKeyValues(methodNames); - for (let i = 0; i < methods.length; i++) { - const spy = (obj[methods[i][0]] = this.createSpy( - baseName + '.' + methods[i][0] - )); - if (methods[i].length > 1) { - spy.and.returnValue(methods[i][1]); - } - } - - const properties = normalizeKeyValues(propertyNames); - for (let i = 0; i < properties.length; i++) { - const descriptor = { - enumerable: true, - get: this.createSpy(baseName + '.' + properties[i][0] + '.get'), - set: this.createSpy(baseName + '.' + properties[i][0] + '.set') - }; - if (properties[i].length > 1) { - descriptor.get.and.returnValue(properties[i][1]); - descriptor.set.and.returnValue(properties[i][1]); - } - Object.defineProperty(obj, properties[i][0], descriptor); - } - - if (methods.length === 0 && properties.length === 0) { - throw new Error( - 'createSpyObj requires a non-empty array or object of method names to create spies for' - ); - } - - return obj; - }; - } - - function normalizeKeyValues(object) { - const result = []; - if (Array.isArray(object)) { - for (let i = 0; i < object.length; i++) { - result.push([object[i]]); - } - } else if (j$.private.isObject(object)) { - for (const key in object) { - if (object.hasOwnProperty(key)) { - result.push([key, object[key]]); - } - } - } - return result; - } - - return SpyFactory; -}; - -getJasmineRequireObj().SpyRegistry = function(j$) { - 'use strict'; - - const spyOnMsg = j$.private.formatErrorMsg( - '', - 'spyOn(, )' - ); - const spyOnPropertyMsg = j$.private.formatErrorMsg( - '', - 'spyOnProperty(, , [accessType])' - ); - - function SpyRegistry(options) { - options = options || {}; - const global = options.global || j$.getGlobal(); - const createSpy = options.createSpy; - const currentSpies = - options.currentSpies || - function() { - return []; - }; - - this.allowRespy = function(allow) { - this.respy = allow; - }; - - this.spyOn = function(obj, methodName) { - const getErrorMsg = spyOnMsg; - - if (obj === undefined || obj === null) { - throw new Error( - getErrorMsg( - 'could not find an object to spy upon for ' + methodName + '()' - ) - ); - } - - if (methodName === undefined || methodName === null) { - throw new Error(getErrorMsg('No method name supplied')); - } - - if (obj[methodName] === undefined) { - throw new Error(getErrorMsg(methodName + '() method does not exist')); - } - - // Spying on mock clock timing fns would prevent the real ones from being - // restored. - if ( - obj[methodName] && - obj[methodName][j$.private.Clock.IsMockClockTimingFn] - ) { - throw new Error("Mock clock timing functions can't be spied on"); - } - - if (obj[methodName] && j$.isSpy(obj[methodName])) { - if (this.respy) { - return obj[methodName]; - } else { - throw new Error( - getErrorMsg(methodName + ' has already been spied upon') - ); - } - } - - const descriptor = Object.getOwnPropertyDescriptor(obj, methodName); - - if (descriptor && !(descriptor.writable || descriptor.set)) { - throw new Error( - getErrorMsg(methodName + ' is not declared writable or has no setter') - ); - } - - const originalMethod = obj[methodName]; - const spiedMethod = createSpy(methodName, originalMethod); - let restoreStrategy; - - if ( - Object.prototype.hasOwnProperty.call(obj, methodName) || - (obj === global && methodName === 'onerror') - ) { - restoreStrategy = function() { - obj[methodName] = originalMethod; - }; - } else { - restoreStrategy = function() { - try { - delete obj[methodName]; - // eslint-disable-next-line no-unused-vars - } catch (e) { - obj[methodName] = originalMethod; - } - }; - } - - currentSpies().push({ - restoreObjectToOriginalState: restoreStrategy - }); - - obj[methodName] = spiedMethod; - - // Check if setting the property actually worked. Some objects, such as - // localStorage in Firefox and later Safari versions, have no-op setters. - if (obj[methodName] !== spiedMethod) { - throw new Error( - j$.private.formatErrorMsg('')( - `Can't spy on ${methodName} because assigning to it had no effect` - ) - ); - } - - return spiedMethod; - }; - - this.spyOnProperty = function(obj, propertyName, accessType) { - const getErrorMsg = spyOnPropertyMsg; - - accessType = accessType || 'get'; - - if (!obj) { - throw new Error( - getErrorMsg( - 'spyOn could not find an object to spy upon for ' + - propertyName + - '' - ) - ); - } - - if (propertyName === undefined) { - throw new Error(getErrorMsg('No property name supplied')); - } - - const descriptor = j$.private.util.getPropertyDescriptor( - obj, - propertyName - ); - - if (!descriptor) { - throw new Error(getErrorMsg(propertyName + ' property does not exist')); - } - - if (!descriptor.configurable) { - throw new Error( - getErrorMsg(propertyName + ' is not declared configurable') - ); - } - - if (!descriptor[accessType]) { - throw new Error( - getErrorMsg( - 'Property ' + - propertyName + - ' does not have access type ' + - accessType - ) - ); - } - - if (j$.isSpy(descriptor[accessType])) { - if (this.respy) { - return descriptor[accessType]; - } else { - throw new Error( - getErrorMsg( - propertyName + '#' + accessType + ' has already been spied upon' - ) - ); - } - } - - const originalDescriptor = j$.private.util.clone(descriptor); - const spy = createSpy(propertyName, descriptor[accessType]); - let restoreStrategy; - - if (Object.prototype.hasOwnProperty.call(obj, propertyName)) { - restoreStrategy = function() { - Object.defineProperty(obj, propertyName, originalDescriptor); - }; - } else { - restoreStrategy = function() { - delete obj[propertyName]; - }; - } - - currentSpies().push({ - restoreObjectToOriginalState: restoreStrategy - }); - - descriptor[accessType] = spy; - - Object.defineProperty(obj, propertyName, descriptor); - - return spy; - }; - - this.spyOnAllFunctions = function(obj, includeNonEnumerable) { - if (!obj) { - throw new Error( - 'spyOnAllFunctions could not find an object to spy upon' - ); - } - - let pointer = obj, - propsToSpyOn = [], - properties, - propertiesToSkip = []; - - while ( - pointer && - (!includeNonEnumerable || pointer !== Object.prototype) - ) { - properties = getProps(pointer, includeNonEnumerable); - properties = properties.filter(function(prop) { - return propertiesToSkip.indexOf(prop) === -1; - }); - propertiesToSkip = propertiesToSkip.concat(properties); - propsToSpyOn = propsToSpyOn.concat( - getSpyableFunctionProps(pointer, properties) - ); - pointer = Object.getPrototypeOf(pointer); - } - - for (const prop of propsToSpyOn) { - this.spyOn(obj, prop); - } - - return obj; - }; - - this.clearSpies = function() { - const spies = currentSpies(); - for (let i = spies.length - 1; i >= 0; i--) { - const spyEntry = spies[i]; - spyEntry.restoreObjectToOriginalState(); - } - }; - } - - function getProps(obj, includeNonEnumerable) { - const enumerableProperties = Object.keys(obj); - - if (!includeNonEnumerable) { - return enumerableProperties; - } - - return Object.getOwnPropertyNames(obj).filter(function(prop) { - return ( - prop !== 'constructor' || - enumerableProperties.indexOf('constructor') > -1 - ); - }); - } - - function getSpyableFunctionProps(obj, propertiesToCheck) { - const props = []; - - for (const prop of propertiesToCheck) { - if ( - Object.prototype.hasOwnProperty.call(obj, prop) && - isSpyableProp(obj, prop) - ) { - props.push(prop); - } - } - return props; - } - - function isSpyableProp(obj, prop) { - let value; - try { - value = obj[prop]; - // eslint-disable-next-line no-unused-vars - } catch (e) { - return false; - } - - if (value instanceof Function) { - const descriptor = Object.getOwnPropertyDescriptor(obj, prop); - return (descriptor.writable || descriptor.set) && descriptor.configurable; - } - return false; - } - - return SpyRegistry; -}; - -getJasmineRequireObj().SpyStrategy = function(j$) { - 'use strict'; - - /** - * @interface SpyStrategy - */ - function SpyStrategy(options) { - options = options || {}; - - /** - * Get the identifying information for the spy. - * @name SpyStrategy#identity - * @since 3.0.0 - * @member - * @type {String} - */ - this.identity = options.name || 'unknown'; - this.originalFn = options.fn || function() {}; - this.getSpy = options.getSpy || function() {}; - this.plan = this._defaultPlan = function() {}; - - const cs = options.customStrategies || {}; - for (const k in cs) { - if (j$.private.util.has(cs, k) && !this[k]) { - this[k] = createCustomPlan(cs[k]); - } - } - - /** - * Tell the spy to return a promise resolving to the specified value when invoked. - * @name SpyStrategy#resolveTo - * @since 3.5.0 - * @function - * @param {*} value The value to return. - */ - this.resolveTo = function(value) { - this.plan = function() { - return Promise.resolve(value); - }; - return this.getSpy(); - }; - - /** - * Tell the spy to return a promise rejecting with the specified value when invoked. - * @name SpyStrategy#rejectWith - * @since 3.5.0 - * @function - * @param {*} value The value to return. - */ - this.rejectWith = function(value) { - this.plan = function() { - return Promise.reject(value); - }; - return this.getSpy(); - }; - } - - function createCustomPlan(factory) { - return function() { - const plan = factory.apply(null, arguments); - - if (!j$.private.isFunction(plan)) { - throw new Error('Spy strategy must return a function'); - } - - this.plan = plan; - return this.getSpy(); - }; - } - - /** - * Execute the current spy strategy. - * @name SpyStrategy#exec - * @since 2.0.0 - * @function - */ - SpyStrategy.prototype.exec = function(context, args, invokeNew) { - const contextArgs = [context].concat( - args ? Array.prototype.slice.call(args) : [] - ); - const target = this.plan.bind.apply(this.plan, contextArgs); - - return invokeNew ? new target() : target(); - }; - - /** - * Tell the spy to call through to the real implementation when invoked. - * @name SpyStrategy#callThrough - * @since 2.0.0 - * @function - */ - SpyStrategy.prototype.callThrough = function() { - this.plan = this.originalFn; - return this.getSpy(); - }; - - /** - * Tell the spy to return the value when invoked. - * @name SpyStrategy#returnValue - * @since 2.0.0 - * @function - * @param {*} value The value to return. - */ - SpyStrategy.prototype.returnValue = function(value) { - this.plan = function() { - return value; - }; - return this.getSpy(); - }; - - /** - * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked. - * @name SpyStrategy#returnValues - * @since 2.1.0 - * @function - * @param {...*} values - Values to be returned on subsequent calls to the spy. - */ - SpyStrategy.prototype.returnValues = function() { - const values = Array.prototype.slice.call(arguments); - this.plan = function() { - return values.shift(); - }; - return this.getSpy(); - }; - - /** - * Tell the spy to throw an error when invoked. - * @name SpyStrategy#throwError - * @since 2.0.0 - * @function - * @param {Error|Object|String} something Thing to throw - */ - SpyStrategy.prototype.throwError = function(something) { - const error = j$.private.isString(something) - ? new Error(something) - : something; - this.plan = function() { - throw error; - }; - return this.getSpy(); - }; - - /** - * Tell the spy to call a fake implementation when invoked. - * @name SpyStrategy#callFake - * @since 2.0.0 - * @function - * @param {Function} fn The function to invoke with the passed parameters. - */ - SpyStrategy.prototype.callFake = function(fn) { - if ( - !( - j$.private.isFunction(fn) || - j$.private.isAsyncFunction(fn) || - j$.private.isGeneratorFunction(fn) - ) - ) { - throw new Error( - 'Argument passed to callFake should be a function, got ' + fn - ); - } - this.plan = fn; - return this.getSpy(); - }; - - /** - * Tell the spy to do nothing when invoked. This is the default. - * @name SpyStrategy#stub - * @since 2.0.0 - * @function - */ - SpyStrategy.prototype.stub = function(fn) { - this.plan = function() {}; - return this.getSpy(); - }; - - SpyStrategy.prototype.isConfigured = function() { - return this.plan !== this._defaultPlan; - }; - - return SpyStrategy; -}; - -getJasmineRequireObj().StackClearer = function(j$) { - 'use strict'; - - const maxInlineCallCount = 10; - // 25ms gives a good balance of speed and UI responsiveness when running - // jasmine-core's own tests in Safari 18. The exact value isn't critical. - const safariYieldIntervalMs = 25; - - function browserQueueMicrotaskImpl(global) { - const unclampedSetTimeout = getUnclampedSetTimeout(global); - const { queueMicrotask } = global; - let yieldStrategy = 'count'; - let currentCallCount = 0; // for count strategy - let nextSetTimeoutTime; // for time strategy - - return { - clearStack(fn) { - currentCallCount++; - let shouldSetTimeout; - - if (yieldStrategy === 'time') { - const now = new Date().getTime(); - shouldSetTimeout = now >= nextSetTimeoutTime; - if (shouldSetTimeout) { - nextSetTimeoutTime = now + safariYieldIntervalMs; - } - } else { - shouldSetTimeout = currentCallCount >= maxInlineCallCount; - if (shouldSetTimeout) { - currentCallCount = 0; - } - } - - if (shouldSetTimeout) { - unclampedSetTimeout(fn); - } else { - queueMicrotask(fn); - } - }, - setSafariYieldStrategy(strategy) { - yieldStrategy = strategy; - - if (yieldStrategy === 'time') { - nextSetTimeoutTime = new Date().getTime() + safariYieldIntervalMs; - } - } - }; - } - - function nodeQueueMicrotaskImpl(global) { - const { queueMicrotask } = global; - - return { - clearStack(fn) { - queueMicrotask(fn); - }, - setSafariYieldStrategy() {} - }; - } - - function messageChannelImpl(global) { - const { setTimeout } = global; - const postMessage = getPostMessage(global); - - let currentCallCount = 0; - - return { - clearStack(fn) { - currentCallCount++; - - if (currentCallCount < maxInlineCallCount) { - postMessage(fn); - } else { - currentCallCount = 0; - setTimeout(fn); - } - }, - setSafariYieldStrategy() {} - }; - } - - function getUnclampedSetTimeout(global) { - const { setTimeout } = global; - if (!global.MessageChannel) { - return setTimeout; - } - - const postMessage = getPostMessage(global); - return function unclampedSetTimeout(fn) { - postMessage(function() { - setTimeout(fn); - }); - }; - } - - function getPostMessage(global) { - const { MessageChannel, setTimeout } = global; - const channel = new MessageChannel(); - let head = {}; - let tail = head; - - let taskRunning = false; - channel.port1.onmessage = function() { - head = head.next; - const task = head.task; - delete head.task; - - if (taskRunning) { - setTimeout(task, 0); - } else { - try { - taskRunning = true; - task(); - } finally { - taskRunning = false; - } - } - }; - - return function postMessage(fn) { - tail = tail.next = { task: fn }; - channel.port2.postMessage(0); - }; - } - - function getStackClearer(global) { - const NODE_JS = - global.process && - global.process.versions && - typeof global.process.versions.node === 'string'; - - // Windows builds of WebKit have a fairly generic user agent string when no application name is provided: - // e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)" - const SAFARI_OR_WIN_WEBKIT = - global.navigator && - /(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test( - global.navigator.userAgent - ); - - if (NODE_JS) { - // Unlike browsers, Node doesn't require us to do a periodic setTimeout - // so we avoid the overhead. - return nodeQueueMicrotaskImpl(global); - } else if (SAFARI_OR_WIN_WEBKIT) { - // queueMicrotask is dramatically faster than MessageChannel in Safari - // and other WebKit-based browsers, such as the one distributed by Playwright - // to test Safari-like behavior on Windows. - return browserQueueMicrotaskImpl(global); - } else { - // MessageChannel is faster than queueMicrotask in supported browsers - // other than Safari. - return messageChannelImpl(global); - } - } - - return getStackClearer; -}; - -getJasmineRequireObj().StackTrace = function(j$) { - 'use strict'; - - function StackTrace(error) { - let lines = error.stack.split('\n'); - - const extractResult = extractMessage(error.message, lines); - - if (extractResult) { - this.message = extractResult.message; - lines = extractResult.remainder; - } - - lines = lines.filter(function(line) { - return line !== ''; - }); - - const parseResult = tryParseFrames(lines); - this.frames = parseResult.frames; - this.style = parseResult.style; - } - - const framePatterns = [ - // Node, Chrome, Edge - // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)" - // Note that the "function name" can include a surprisingly large set of - // characters, including angle brackets and square brackets. - { - re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, - fnIx: 1, - fileLineColIx: 2, - style: 'v8' - }, - - // NodeJS alternate form, often mixed in with the Chrome style - // e.g. " at /some/path:4320:20 - { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' }, - - // Safari, most Firefox stack frames - // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27" - // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27" - { - re: /^(?:(([^@\s]+)@)|@)?([^\s]+)$/, - fnIx: 2, - fileLineColIx: 3, - style: 'webkit' - }, - - // Some Firefox stack frames when the developer tools are open - // e.g. "promise callback*specStarted@http://localhost:8888/__jasmine__/jasmine.js:1880:41" - { - re: /^^(?:((?:promise callback|[^\s]+ handler)\*([^@\s]+)@)|@)?([^\s]+)$/, - fnIx: 2, - fileLineColIx: 3, - style: 'webkit' - } - ]; - - // regexes should capture the function name (if any) as group 1 - // and the file, line, and column as group 2. - function tryParseFrames(lines) { - let style = null; - const frames = lines.map(function(line) { - const convertedLine = first(framePatterns, function(pattern) { - const overallMatch = line.match(pattern.re); - if (!overallMatch) { - return null; - } - - const fileLineColMatch = overallMatch[pattern.fileLineColIx].match( - /^(.*):(\d+):\d+$/ - ); - if (!fileLineColMatch) { - return null; - } - - style = style || pattern.style; - return { - raw: line, - file: fileLineColMatch[1], - line: parseInt(fileLineColMatch[2], 10), - func: overallMatch[pattern.fnIx] - }; - }); - - return convertedLine || { raw: line }; - }); - - return { - style: style, - frames: frames - }; - } - - function first(items, fn) { - for (const item of items) { - const result = fn(item); - - if (result) { - return result; - } - } - } - - function extractMessage(message, stackLines) { - const len = messagePrefixLength(message, stackLines); - - if (len > 0) { - return { - message: stackLines.slice(0, len).join('\n'), - remainder: stackLines.slice(len) - }; - } - } - - function messagePrefixLength(message, stackLines) { - if (!stackLines[0].match(/^\w*Error/)) { - return 0; - } - - const messageLines = message.split('\n'); - - for (let i = 1; i < messageLines.length; i++) { - if (messageLines[i] !== stackLines[i]) { - return 0; - } - } - - return messageLines.length; - } - - return StackTrace; -}; - -getJasmineRequireObj().Suite = function(j$) { - 'use strict'; - - class Suite { - #reportedParentSuiteId; - #throwOnExpectationFailure; - #autoCleanClosures; - #timer; - #result; - - constructor(attrs) { - this.id = attrs.id; - this.parentSuite = attrs.parentSuite; - this.description = attrs.description; - this.filename = attrs.filename; - this.expectationFactory = attrs.expectationFactory; - this.asyncExpectationFactory = attrs.asyncExpectationFactory; - this.onLateError = attrs.onLateError || function() {}; - this.#reportedParentSuiteId = attrs.reportedParentSuiteId; - this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - this.#autoCleanClosures = - attrs.autoCleanClosures === undefined - ? true - : !!attrs.autoCleanClosures; - this.#timer = attrs.timer || new j$.Timer(); - - this.beforeFns = []; - this.afterFns = []; - this.beforeAllFns = []; - this.afterAllFns = []; - this.children = []; - - this.reset(); - } - - setSuiteProperty(key, value) { - // Key and value will eventually be cloned during reporting. The error - // thrown at that point if they aren't cloneable isn't very helpful. - // Throw a better one now. - if (!j$.private.isString(key)) { - throw new Error('Key must be a string'); - } - j$.private.util.assertReporterCloneable(value, 'Value'); - - this.#result.properties = this.#result.properties || {}; - this.#result.properties[key] = value; - } - - getFullName() { - const fullName = []; - for ( - let parentSuite = this; - parentSuite; - parentSuite = parentSuite.parentSuite - ) { - if (parentSuite.parentSuite) { - fullName.unshift(parentSuite.description); - } - } - return fullName.join(' '); - } - - // Mark the suite with "pending" status - pend() { - this.markedPending = true; - } - - // Like pend(), but pending state will survive reset(). - // Useful for fdescribe, xdescribe, where pending state should remain. - exclude() { - this.pend(); - this.markedExcluding = true; - } - - beforeEach(fn) { - this.beforeFns.unshift({ ...fn, suite: this }); - } - - beforeAll(fn) { - this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); - } - - afterEach(fn) { - this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); - } - - afterAll(fn) { - this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); - } - - startTimer() { - this.#timer.start(); - } - - endTimer() { - this.#result.duration = this.#timer.elapsed(); - } - - cleanupBeforeAfter() { - if (this.#autoCleanClosures) { - removeFns(this.beforeAllFns); - removeFns(this.afterAllFns); - removeFns(this.beforeFns); - removeFns(this.afterFns); - } - } - - reset() { - this.#result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - parentSuiteId: this.#reportedParentSuiteId, - filename: this.filename, - failedExpectations: [], - deprecationWarnings: [], - duration: null, - properties: null - }; - this.markedPending = this.markedExcluding; - this.children.forEach(function(child) { - child.reset(); - }); - this.reportedDone = false; - } - - startedEvent() { - /** - * @typedef SuiteStartedEvent - * @property {String} id - The unique id of this suite. - * @property {String} description - The description text passed to the {@link describe} that made this suite. - * @property {String} fullName - The full description including all ancestors of this suite. - * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). - * @property {String} filename - Deprecated. The name of the file the suite was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that - * don't maintain the same call stack height as the originals. This property - * may be removed in a future version unless there is enough user interest - * in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}. - * @since 6.0.0 - */ - return this.#commonEventFields(); - } - - doneEvent() { - /** - * @typedef SuiteDoneEvent - * @property {String} id - The unique id of this suite. - * @property {String} description - The description text passed to the {@link describe} that made this suite. - * @property {String} fullName - The full description including all ancestors of this suite. - * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). - * @property {String} filename - The name of the file the suite was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that - * don't maintain the same call stack height as the originals. You can fix - * that by setting {@link Configuration#extraDescribeStackFrames}. - * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. - * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. - * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. - * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} - * @since 2.0.0 - */ - const event = { - ...this.#commonEventFields(), - status: this.#status() - }; - const toCopy = [ - 'failedExpectations', - 'deprecationWarnings', - 'duration', - 'properties' - ]; - - for (const k of toCopy) { - event[k] = this.#result[k]; - } - - return event; - } - - #commonEventFields() { - return { - id: this.id, - description: this.description, - fullName: this.getFullName(), - parentSuiteId: this.#reportedParentSuiteId, - filename: this.filename - }; - } - - removeChildren() { - this.children = []; - } - - addChild(child) { - this.children.push(child); - } - - #status() { - if (this.markedPending) { - return 'pending'; - } - - if (this.#result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'passed'; - } - } - - hasOwnFailedExpectations() { - return this.#result.failedExpectations.length > 0; - } - - sharedUserContext() { - if (!this.sharedContext) { - this.sharedContext = this.parentSuite - ? this.parentSuite.clonedSharedUserContext() - : new j$.private.UserContext(); - } - - return this.sharedContext; - } - - clonedSharedUserContext() { - return j$.private.UserContext.fromExisting(this.sharedUserContext()); - } - - handleException() { - if (arguments[0] instanceof j$.private.errors.ExpectationFailed) { - return; - } - - const data = { - matcherName: '', - passed: false, - error: arguments[0] - }; - const failedExpectation = j$.private.buildExpectationResult(data); - - if (!this.parentSuite) { - failedExpectation.globalErrorType = 'afterAll'; - } - - if (this.reportedDone) { - this.onLateError(failedExpectation); - } else { - this.#result.failedExpectations.push(failedExpectation); - } - } - - onMultipleDone() { - let msg; - - // Issue an error. Include the context ourselves and pass - // ignoreRunnable: true, since getting here always means that we've already - // moved on and the current runnable isn't the one that caused the problem. - if (this.parentSuite) { - msg = - "An asynchronous beforeAll or afterAll function called its 'done' " + - 'callback more than once.\n' + - '(in suite: ' + - this.getFullName() + - ')'; - } else { - msg = - 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once."; - } - - this.onLateError(new Error(msg)); - } - - addExpectationResult(passed, data) { - if (passed) { - // Passed expectations are accepted for compatibility with - // Spec#addExpectationResult, but aren't recorded. - return; - } - - const expectationResult = j$.private.buildExpectationResult(data); - - if (this.reportedDone) { - this.onLateError(expectationResult); - } else { - this.#result.failedExpectations.push(expectationResult); - } - - if (this.#throwOnExpectationFailure) { - throw new j$.private.errors.ExpectationFailed(); - } - } - - addDeprecationWarning(deprecation) { - if (typeof deprecation === 'string') { - deprecation = { message: deprecation }; - } - this.#result.deprecationWarnings.push( - j$.private.buildExpectationResult(deprecation) - ); - } - - hasChildWithDescription(description) { - for (const child of this.children) { - if (child.description === description) { - return true; - } - } - - return false; - } - - get metadata() { - if (!this.metadata_) { - this.metadata_ = new SuiteMetadata(this); - } - - return this.metadata_; - } - } - - function removeFns(queueableFns) { - for (const qf of queueableFns) { - qf.fn = null; - } - } - - /** - * @interface Suite - * @see Env#topSuite - * @since 2.0.0 - */ - class SuiteMetadata { - #suite; - - constructor(suite) { - this.#suite = suite; - /** - * The unique ID of this suite. - * @name Suite#id - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.id = suite.id; - - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ - this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; - - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.description = suite.description; - - /** - * The name of the file the suite was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `describe`/`fdescribe`/`xdescribe` have been replaced with versions - * that don't maintain the same call stack height as the originals. You - * can fix that by setting {@link Configuration#extraItStackFrames}. - * @name Suite#filename - * @readonly - * @type {string} - * @since 5.13.0 - */ - this.filename = suite.filename; - } - - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - * @since 2.0.0 - */ - getFullName() { - return this.#suite.getFullName(); - } - - /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} - * @since 2.0.0 - */ - get children() { - return this.#suite.children.map(child => child.metadata); - } - } - - return Suite; -}; - -getJasmineRequireObj().SuiteBuilder = function(j$) { - 'use strict'; - - class SuiteBuilder { - constructor(options) { - this.env_ = options.env; - this.expectationFactory_ = options.expectationFactory; - this.suiteAsyncExpectationFactory_ = function(actual, suite) { - return options.asyncExpectationFactory(actual, suite, 'Suite'); - }; - this.specAsyncExpectationFactory_ = function(actual, suite) { - return options.asyncExpectationFactory(actual, suite, 'Spec'); - }; - this.onLateError_ = options.onLateError; - - this.nextSuiteId_ = 0; - this.nextSpecId_ = 0; - - this.topSuite = this.suiteFactory_('Jasmine__TopLevel__Suite'); - this.currentDeclarationSuite_ = this.topSuite; - this.totalSpecsDefined = 0; - this.focusedRunables = []; - } - - inDescribe() { - return this.currentDeclarationSuite_ !== this.topSuite; - } - - parallelReset() { - this.topSuite.removeChildren(); - this.topSuite.reset(); - this.totalSpecsDefined = 0; - this.focusedRunables = []; - } - - describe(description, definitionFn, filename) { - ensureIsFunction(definitionFn, 'describe'); - const suite = this.suiteFactory_(description, filename); - if (definitionFn.length > 0) { - throw new Error('describe does not expect any arguments'); - } - if (this.currentDeclarationSuite_.markedExcluding) { - suite.exclude(); - } - this.addSpecsToSuite_(suite, definitionFn); - return suite; - } - - fdescribe(description, definitionFn, filename) { - ensureIsFunction(definitionFn, 'fdescribe'); - const suite = this.suiteFactory_(description, filename); - suite.isFocused = true; - - this.focusedRunables.push(suite.id); - this.unfocusAncestor_(); - this.addSpecsToSuite_(suite, definitionFn); - - return suite; - } - - xdescribe(description, definitionFn, filename) { - ensureIsFunction(definitionFn, 'xdescribe'); - const suite = this.suiteFactory_(description, filename); - suite.exclude(); - this.addSpecsToSuite_(suite, definitionFn); - - return suite; - } - - it(description, fn, timeout, filename) { - // it() sometimes doesn't have a fn argument, so only check the type if - // it's given. - if (arguments.length > 1 && typeof fn !== 'undefined') { - ensureIsFunctionOrAsync(fn, 'it'); - } - - return this.it_(description, fn, timeout, filename); - } - - xit(description, fn, timeout, filename) { - // xit(), like it(), doesn't always have a fn argument, so only check the - // type when needed. - if (arguments.length > 1 && typeof fn !== 'undefined') { - ensureIsFunctionOrAsync(fn, 'xit'); - } - const spec = this.it_(description, fn, timeout, filename); - spec.exclude('Temporarily disabled with xit'); - return spec; - } - - fit(description, fn, timeout, filename) { - // Unlike it and xit, the function is required because it doesn't make - // sense to focus on nothing. - ensureIsFunctionOrAsync(fn, 'fit'); - - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - const spec = this.specFactory_(description, fn, timeout, filename); - this.currentDeclarationSuite_.addChild(spec); - this.focusedRunables.push(spec.id); - this.unfocusAncestor_(); - return spec; - } - - beforeEach(beforeEachFunction, timeout) { - ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); - - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - - this.currentDeclarationSuite_.beforeEach({ - fn: beforeEachFunction, - timeout: timeout || 0 - }); - } - - beforeAll(beforeAllFunction, timeout) { - ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); - - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - - this.currentDeclarationSuite_.beforeAll({ - fn: beforeAllFunction, - timeout: timeout || 0 - }); - } - - afterEach(afterEachFunction, timeout) { - ensureIsFunctionOrAsync(afterEachFunction, 'afterEach'); - - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - - afterEachFunction.isCleanup = true; - this.currentDeclarationSuite_.afterEach({ - fn: afterEachFunction, - timeout: timeout || 0 - }); - } - - afterAll(afterAllFunction, timeout) { - ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); - - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - - this.currentDeclarationSuite_.afterAll({ - fn: afterAllFunction, - timeout: timeout || 0 - }); - } - - it_(description, fn, timeout, filename) { - if (timeout) { - j$.private.util.validateTimeout(timeout); - } - - this.checkDuplicate_(description, 'spec'); - - const spec = this.specFactory_(description, fn, timeout, filename); - if (this.currentDeclarationSuite_.markedExcluding) { - spec.exclude(); - } - this.currentDeclarationSuite_.addChild(spec); - - return spec; - } - - checkDuplicate_(description, type) { - if (!this.env_.configuration().forbidDuplicateNames) { - return; - } - - if (this.currentDeclarationSuite_.hasChildWithDescription(description)) { - const parentDesc = - this.currentDeclarationSuite_ === this.topSuite - ? 'top suite' - : `"${this.currentDeclarationSuite_.getFullName()}"`; - throw new Error( - `Duplicate ${type} name "${description}" found in ${parentDesc}` - ); - } - } - - suiteFactory_(description, filename) { - if (this.topSuite) { - this.checkDuplicate_(description, 'suite'); - } - - const config = this.env_.configuration(); - const parentSuite = this.currentDeclarationSuite_; - const reportedParentSuiteId = - parentSuite === this.topSuite ? null : parentSuite.id; - return new j$.private.Suite({ - id: 'suite' + this.nextSuiteId_++, - description, - filename, - parentSuite, - reportedParentSuiteId, - timer: new j$.Timer(), - expectationFactory: this.expectationFactory_, - asyncExpectationFactory: this.suiteAsyncExpectationFactory_, - throwOnExpectationFailure: config.stopSpecOnExpectationFailure, - autoCleanClosures: config.autoCleanClosures, - onLateError: this.onLateError_ - }); - } - - addSpecsToSuite_(suite, definitionFn) { - const parentSuite = this.currentDeclarationSuite_; - parentSuite.addChild(suite); - this.currentDeclarationSuite_ = suite; - let threw = false; - - try { - definitionFn(); - } catch (e) { - suite.handleException(e); - threw = true; - } - - if (suite.parentSuite && !suite.children.length && !threw) { - throw new Error( - `describe with no children (describe() or it()): ${suite.getFullName()}` - ); - } - - this.currentDeclarationSuite_ = parentSuite; - } - - specFactory_(description, fn, timeout, filename) { - this.totalSpecsDefined++; - const config = this.env_.configuration(); - const suite = this.currentDeclarationSuite_; - const parentSuiteId = suite === this.topSuite ? null : suite.id; - const spec = new j$.private.Spec({ - id: 'spec' + this.nextSpecId_++, - filename, - parentSuiteId, - beforeAndAfterFns: beforeAndAfterFns(suite), - expectationFactory: this.expectationFactory_, - asyncExpectationFactory: this.specAsyncExpectationFactory_, - onLateError: this.onLateError_, - getPath: spec => this.getSpecPath_(spec, suite), - description: description, - userContext: function() { - return suite.clonedSharedUserContext(); - }, - queueableFn: { - fn: fn, - timeout: timeout || 0 - }, - throwOnExpectationFailure: config.stopSpecOnExpectationFailure, - autoCleanClosures: config.autoCleanClosures, - timer: new j$.Timer() - }); - return spec; - } - - getSpecPath_(spec, suite) { - const path = [spec.description]; - - while (suite && suite !== this.topSuite) { - path.unshift(suite.description); - suite = suite.parentSuite; - } - - return path; - } - - unfocusAncestor_() { - const focusedAncestor = findFocusedAncestor( - this.currentDeclarationSuite_ - ); - - if (focusedAncestor) { - for (let i = 0; i < this.focusedRunables.length; i++) { - if (this.focusedRunables[i] === focusedAncestor) { - this.focusedRunables.splice(i, 1); - break; - } - } - } - } - } - - function findFocusedAncestor(suite) { - while (suite) { - if (suite.isFocused) { - return suite.id; - } - suite = suite.parentSuite; - } - - return null; - } - - function ensureIsFunction(fn, caller) { - if (!j$.private.isFunction(fn)) { - throw new Error( - caller + - ' expects a function argument; received ' + - j$.private.getType(fn) - ); - } - } - - function ensureIsFunctionOrAsync(fn, caller) { - if (!j$.private.isFunction(fn) && !j$.private.isAsyncFunction(fn)) { - throw new Error( - caller + - ' expects a function argument; received ' + - j$.private.getType(fn) - ); - } - } - - function beforeAndAfterFns(targetSuite) { - return function() { - let befores = [], - afters = [], - suite = targetSuite; - - while (suite) { - befores = befores.concat(suite.beforeFns); - afters = afters.concat(suite.afterFns); - - suite = suite.parentSuite; - } - - return { - befores: befores.reverse(), - afters: afters - }; - }; - } - - return SuiteBuilder; -}; - -getJasmineRequireObj().Timer = function() { - 'use strict'; - - const defaultNow = (function(Date) { - return function() { - return new Date().getTime(); - }; - })(Date); - - /** - * @class Timer - * @classdesc Tracks elapsed time - * @example - * const timer = new jasmine.Timer(); - * timer.start(); - * const elapsed = timer.elapsed() - */ - function Timer(options) { - options = options || {}; - - const now = options.now || defaultNow; - let startTime; - - /** - * Starts the timer. - * @function - * @name Timer#start - */ - this.start = function() { - startTime = now(); - }; - - /** - * Determines the time since the timer was started. - * @function - * @name Timer#elapsed - * @returns {number} Elapsed time in milliseconds, or NaN if the timer has not been started - */ - this.elapsed = function() { - return now() - startTime; - }; - } - - return Timer; -}; - -getJasmineRequireObj().TreeProcessor = function(j$) { - 'use strict'; - - const defaultMin = Infinity; - const defaultMax = 1 - Infinity; - - // Transforms the suite tree into an execution tree, which represents the set - // of specs and suites to be run in the order they are to be run in. - class TreeProcessor { - #tree; - #runnableIds; - #orderChildren; - #excludeNode; - #stats; - - constructor(attrs) { - this.#tree = attrs.tree; - this.#runnableIds = attrs.runnableIds; - - this.#orderChildren = - attrs.orderChildren || - function(node) { - return node.children; - }; - this.#excludeNode = - attrs.excludeNode || - function(node) { - return false; - }; - } - - processTree() { - this.#stats = {}; - this.#processNode(this.#tree, true); - const result = new ExecutionTree(this.#tree, this.#stats); - this.#stats = null; - return result; - } - - #runnableIndex(id) { - for (let i = 0; i < this.#runnableIds.length; i++) { - if (this.#runnableIds[i] === id) { - return i; - } - } - } - - #processNode(node, parentExcluded) { - const executableIndex = this.#runnableIndex(node.id); - - if (executableIndex !== undefined) { - parentExcluded = false; - } - - if (!node.children) { - const excluded = parentExcluded || this.#excludeNode(node); - this.#stats[node.id] = { - excluded: excluded, - willExecute: !excluded && !node.markedPending, - segments: [ - { - index: 0, - owner: node, - nodes: [node], - min: startingMin(executableIndex), - max: startingMax(executableIndex) - } - ] - }; - } else { - let hasExecutableChild = false; - - const orderedChildren = this.#orderChildren(node); - - for (let i = 0; i < orderedChildren.length; i++) { - const child = orderedChildren[i]; - this.#processNode(child, parentExcluded); - const childStats = this.#stats[child.id]; - hasExecutableChild = hasExecutableChild || childStats.willExecute; - } - - this.#stats[node.id] = { - excluded: parentExcluded, - willExecute: hasExecutableChild - }; - - segmentChildren(node, orderedChildren, this.#stats, executableIndex); - - if (this.#stats[node.id].segments.length > 1) { - throw new Error('Invalid order: would split up a suite'); - } - } - } - } - - class ExecutionTree { - #stats; - - constructor(topSuite, stats) { - Object.defineProperty(this, 'topSuite', { - writable: false, - value: topSuite - }); - this.#stats = stats; - } - - childrenOfTopSuite() { - return this.childrenOfSuite(this.topSuite); - } - - childrenOfSuite(suite) { - const segmentChildren = this.#stats[suite.id].segments[0].nodes; - return segmentChildren.map(function(child) { - if (child.owner.children) { - return { suite: child.owner }; - } else { - return { spec: child.owner }; - } - }); - } - - isExcluded(node) { - const nodeStats = this.#stats[node.id]; - return node.children ? !nodeStats.willExecute : nodeStats.excluded; - } - - numExcludedSpecs(node) { - if (!node) { - return this.numExcludedSpecs(this.topSuite); - } else if (node.children) { - let result = 0; - - for (const child of node.children) { - result += this.numExcludedSpecs(child); - } - - return result; - } else { - const nodeStats = this.#stats[node.id]; - return nodeStats.willExecute ? 0 : 1; - } - } - } - - function segmentChildren(node, orderedChildren, stats, executableIndex) { - let currentSegment = { - index: 0, - owner: node, - nodes: [], - min: startingMin(executableIndex), - max: startingMax(executableIndex) - }, - result = [currentSegment], - lastMax = defaultMax, - orderedChildSegments = orderChildSegments(orderedChildren, stats); - - function isSegmentBoundary(minIndex) { - return ( - lastMax !== defaultMax && - minIndex !== defaultMin && - lastMax < minIndex - 1 - ); - } - - for (let i = 0; i < orderedChildSegments.length; i++) { - const childSegment = orderedChildSegments[i], - maxIndex = childSegment.max, - minIndex = childSegment.min; - - if (isSegmentBoundary(minIndex)) { - currentSegment = { - index: result.length, - owner: node, - nodes: [], - min: defaultMin, - max: defaultMax - }; - result.push(currentSegment); - } - - currentSegment.nodes.push(childSegment); - currentSegment.min = Math.min(currentSegment.min, minIndex); - currentSegment.max = Math.max(currentSegment.max, maxIndex); - lastMax = maxIndex; - } - - stats[node.id].segments = result; - } - - function orderChildSegments(children, stats) { - const specifiedOrder = [], - unspecifiedOrder = []; - - for (let i = 0; i < children.length; i++) { - const child = children[i], - segments = stats[child.id].segments; - - for (let j = 0; j < segments.length; j++) { - const seg = segments[j]; - - if (seg.min === defaultMin) { - unspecifiedOrder.push(seg); - } else { - specifiedOrder.push(seg); - } - } - } - - specifiedOrder.sort(function(a, b) { - return a.min - b.min; - }); - - return specifiedOrder.concat(unspecifiedOrder); - } - - function startingMin(executableIndex) { - return executableIndex === undefined ? defaultMin : executableIndex; - } - - function startingMax(executableIndex) { - return executableIndex === undefined ? defaultMax : executableIndex; - } - - return TreeProcessor; -}; - -getJasmineRequireObj().TreeRunner = function(j$) { - 'use strict'; - - class TreeRunner { - #executionTree; - #setTimeout; - #globalErrors; - #runableResources; - #reportDispatcher; - #runQueue; - #getConfig; - #currentRunableTracker; - #hasFailures; - - constructor(attrs) { - this.#executionTree = attrs.executionTree; - this.#globalErrors = attrs.globalErrors; - this.#setTimeout = attrs.setTimeout || setTimeout.bind(globalThis); - this.#runableResources = attrs.runableResources; - this.#reportDispatcher = attrs.reportDispatcher; - this.#runQueue = attrs.runQueue; - this.#getConfig = attrs.getConfig; - this.#currentRunableTracker = attrs.currentRunableTracker; - } - - async execute() { - this.#hasFailures = false; - await new Promise(resolve => { - this.#executeSuite(this.#executionTree.topSuite, resolve); - }); - return { hasFailures: this.#hasFailures }; - } - - #wrapNodes(nodes) { - return nodes.map(node => { - return { - fn: done => { - if (node.suite) { - this.#executeSuite(node.suite, done); - } else { - this._executeSpec(node.spec, done); - } - } - }; - }); - } - - // Only exposed for testing. - _executeSpec(spec, specOverallDone) { - const onStart = next => { - this.#currentRunableTracker.setCurrentSpec(spec); - this.#runableResources.initForRunable( - spec.id, - spec.parentSuiteId || this.#executionTree.topSuite.id - ); - this.#reportDispatcher.specStarted(spec.startedEvent()).then(next); - }; - const resultCallback = (result, next) => { - this.#specComplete(spec).then(next); - }; - const queueableFns = this.#specQueueableFns( - spec, - onStart, - resultCallback - ); - - this.#runQueue({ - isLeaf: true, - queueableFns, - onException: e => spec.handleException(e), - onMultipleDone: () => { - // Issue an erorr. Include the context ourselves and pass - // ignoreRunnable: true, since getting here always means that we've already - // moved on and the current runnable isn't the one that caused the problem. - spec.onLateError( - new Error( - 'An asynchronous spec, beforeEach, or afterEach function called its ' + - "'done' callback more than once.\n(in spec: " + - spec.getFullName() + - ')' - ) - ); - }, - onComplete: () => { - if (spec.status() === 'failed') { - specOverallDone(new j$.private.StopExecutionError('spec failed')); - } else { - specOverallDone(); - } - }, - userContext: spec.userContext(), - runnableName: spec.getFullName.bind(spec), - SkipPolicy: j$.private.CompleteOnFirstErrorSkipPolicy - }); - } - - #specQueueableFns(spec, onStart, resultCallback) { - const config = this.#getConfig(); - const excluded = this.#executionTree.isExcluded(spec); - const ba = spec.beforeAndAfterFns(); - let fns = [...ba.befores, spec.queueableFn, ...ba.afters]; - - if (spec.markedPending || excluded === true) { - fns = []; - } - - const start = { - fn(done) { - spec.executionStarted(); - onStart(done); - } - }; - - const complete = { - fn(done) { - spec.executionFinished(excluded, config.failSpecWithNoExpectations); - resultCallback(spec.doneEvent(), done); - }, - type: 'specCleanup' - }; - - fns.unshift(start); - - if (config.detectLateRejectionHandling) { - fns.push(this.#lateUnhandledRejectionChecker()); - } - - fns.push(complete); - return fns; - } - - #executeSuite(suite, done) { - const isTopSuite = suite === this.#executionTree.topSuite; - const isExcluded = this.#executionTree.isExcluded(suite); - let befores = []; - let afters = []; - - if (suite.beforeAllFns.length > 0 && !isExcluded) { - befores = [...suite.beforeAllFns]; - if (this.#getConfig().detectLateRejectionHandling) { - befores.push(this.#lateUnhandledRejectionChecker()); - } - } - - if (suite.afterAllFns.length > 0 && !isExcluded) { - afters = [...suite.afterAllFns]; - if (this.#getConfig().detectLateRejectionHandling) { - afters.push(this.#lateUnhandledRejectionChecker()); - } - } - - const children = isTopSuite - ? this.#executionTree.childrenOfTopSuite() - : this.#executionTree.childrenOfSuite(suite); - const queueableFns = [ - ...befores, - ...this.#wrapNodes(children), - ...afters - ]; - - if (!isTopSuite) { - queueableFns.unshift({ - fn: next => { - this.#suiteSegmentStart(suite, next); - } - }); - } - - this.#runQueue({ - onComplete: maybeError => { - this.#suiteSegmentComplete(suite, () => { - done(maybeError); - }); - }, - queueableFns, - userContext: suite.sharedUserContext(), - onException: function() { - suite.handleException.apply(suite, arguments); - }, - onMultipleDone: suite.onMultipleDone - ? suite.onMultipleDone.bind(suite) - : null, - SkipPolicy: this.#suiteSkipPolicy() - }); - } - - // Returns a queueable fn that reports any still-unhandled rejections in - // cases where detectLateRejectionHandling is enabled. Should only be called - // when detectLateRejectionHandling is enabled, because the setTimeout - // imposes a significant performance penalty in suites with lots of fast - // specs. - #lateUnhandledRejectionChecker() { - const globalErrors = this.#globalErrors; - return { - fn: done => { - // setTimeout is necessary to trigger rejectionhandled events - this.#setTimeout(function() { - globalErrors.reportUnhandledRejections(); - done(); - }); - } - }; - } - - #suiteSegmentStart(suite, next) { - this.#currentRunableTracker.pushSuite(suite); - this.#runableResources.initForRunable(suite.id, suite.parentSuite.id); - this.#reportDispatcher.suiteStarted(suite.startedEvent()).then(next); - suite.startTimer(); - } - - #suiteSegmentComplete(suite, next) { - suite.endTimer(); - const isTopSuite = suite === this.#executionTree.topSuite; - - if (!isTopSuite) { - if (suite !== this.#currentRunableTracker.currentSuite()) { - throw new Error('Tried to complete the wrong suite'); - } - - // suite.cleanupBeforeAfter() is conditional because calling it on the - // top suite breaks parallel mode. The top suite is reentered every time - // a runner runs another file, so its before and after fns need to be - // preserved. - suite.cleanupBeforeAfter(); - this.#runableResources.clearForRunable(suite.id); - this.#currentRunableTracker.popSuite(); - - if (suite.doneEvent().status === 'failed') { - this.#hasFailures = true; - } - } - - const finish = isTopSuite - ? next - : () => this.#reportSuiteDone(suite, next); - - if (suite.hadBeforeAllFailure) { - this.#reportChildrenOfBeforeAllFailure(suite).then(finish); - } else { - finish(); - } - } - - #reportSuiteDone(suite, next) { - suite.reportedDone = true; - this.#reportDispatcher.suiteDone(suite.doneEvent()).then(next); - } - - async #specComplete(spec) { - this.#runableResources.clearForRunable(spec.id); - this.#currentRunableTracker.setCurrentSpec(null); - - if (spec.status() === 'failed') { - this.#hasFailures = true; - } - - await this.#reportSpecDone(spec); - } - - async #reportSpecDone(spec) { - spec.reportedDone = true; - await this.#reportDispatcher.specDone(spec.doneEvent()); - } - - async #reportChildrenOfBeforeAllFailure(suite) { - for (const child of suite.children) { - if (child instanceof j$.private.Suite) { - await this.#reportDispatcher.suiteStarted(child.startedEvent()); - await this.#reportChildrenOfBeforeAllFailure(child); - await this.#reportDispatcher.suiteDone(child.doneEvent()); - } else { - /* a spec */ - await this.#reportDispatcher.specStarted(child.startedEvent()); - child.hadBeforeAllFailure(); - await this.#reportSpecDone(child); - } - } - } - - #suiteSkipPolicy() { - if (this.#getConfig().stopOnSpecFailure) { - return j$.private.CompleteOnFirstErrorSkipPolicy; - } else { - return j$.private.SkipAfterBeforeAllErrorPolicy; - } - } - } - - return TreeRunner; -}; - -getJasmineRequireObj().UserContext = function(j$) { - 'use strict'; - - function UserContext() {} - - UserContext.fromExisting = function(oldContext) { - const context = new UserContext(); - - for (const prop in oldContext) { - if (oldContext.hasOwnProperty(prop)) { - context[prop] = oldContext[prop]; - } - } - - return context; - }; - - return UserContext; -}; - -getJasmineRequireObj().version = function() { - return '6.0.1'; -}; diff --git a/src/static/tests/LICENSE b/src/static_src/tests/LICENSE similarity index 100% rename from src/static/tests/LICENSE rename to src/static_src/tests/LICENSE diff --git a/src/static/tests/Spec.js b/src/static_src/tests/Spec.js similarity index 100% rename from src/static/tests/Spec.js rename to src/static_src/tests/Spec.js diff --git a/src/static/tests/SpecRunner.html b/src/static_src/tests/SpecRunner.html similarity index 92% rename from src/static/tests/SpecRunner.html rename to src/static_src/tests/SpecRunner.html index 4f947e7..329bfa1 100644 --- a/src/static/tests/SpecRunner.html +++ b/src/static_src/tests/SpecRunner.html @@ -20,7 +20,7 @@ - +