Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4f8669835 | ||
|
|
26be252e70 | ||
|
|
2a1b7a04f7 | ||
|
|
4c8a4f2b00 | ||
|
|
8bc95ae2e3 | ||
|
|
80b9d6c2e0 | ||
|
|
66ffb5f7a3 | ||
|
|
225194c343 | ||
|
|
7a75cc7643 | ||
|
|
ec7a9e2416 | ||
|
|
7896ae84e6 |
@@ -4,13 +4,25 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
|
|
||||||
executors:
|
executors:
|
||||||
node20:
|
|
||||||
docker:
|
|
||||||
- image: cimg/node:20.0.0
|
|
||||||
working_directory: ~/workspace
|
|
||||||
node18:
|
node18:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:18.0.0
|
- image: cimg/node:18.0.0 # Latest 18.x
|
||||||
|
working_directory: ~/workspace
|
||||||
|
node16:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:16.14.2 # Latest 16.x
|
||||||
|
working_directory: ~/workspace
|
||||||
|
node14:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:14.17.4 # Latest 14.x
|
||||||
|
working_directory: ~/workspace
|
||||||
|
node12_latest:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:12.22.10 # Latest 12.x
|
||||||
|
working_directory: ~/workspace
|
||||||
|
node12_17:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:12.17.0 # Oldest version supported by Jasmine
|
||||||
working_directory: ~/workspace
|
working_directory: ~/workspace
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -47,20 +59,8 @@ jobs:
|
|||||||
name: Run tests
|
name: Run tests
|
||||||
command: npm test
|
command: npm test
|
||||||
|
|
||||||
test_parallel: &test_parallel
|
|
||||||
parameters:
|
|
||||||
executor:
|
|
||||||
type: executor
|
|
||||||
executor: << parameters.executor >>
|
|
||||||
steps:
|
|
||||||
- attach_workspace:
|
|
||||||
at: .
|
|
||||||
- run:
|
|
||||||
name: Run tests in parallel
|
|
||||||
command: npx grunt execSpecsInParallel
|
|
||||||
|
|
||||||
test_browsers: &test_browsers
|
test_browsers: &test_browsers
|
||||||
executor: node18
|
executor: node14
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: .
|
at: .
|
||||||
@@ -94,35 +94,49 @@ workflows:
|
|||||||
|
|
||||||
push:
|
push:
|
||||||
jobs:
|
jobs:
|
||||||
- build:
|
|
||||||
executor: node20
|
|
||||||
name: build_node_20
|
|
||||||
- build:
|
- build:
|
||||||
executor: node18
|
executor: node18
|
||||||
name: build_node_18
|
name: build_node_18
|
||||||
- test_node:
|
- build:
|
||||||
executor: node20
|
executor: node16
|
||||||
name: test_node_20
|
name: build_node_16
|
||||||
requires:
|
- build:
|
||||||
- build_node_20
|
executor: node14
|
||||||
|
name: build_node_14
|
||||||
|
- build:
|
||||||
|
executor: node12_latest
|
||||||
|
name: build_node_12_latest
|
||||||
|
- build:
|
||||||
|
executor: node12_17
|
||||||
|
name: build_node_12_17
|
||||||
- test_node:
|
- test_node:
|
||||||
executor: node18
|
executor: node18
|
||||||
name: test_node_18
|
name: test_node_18
|
||||||
requires:
|
requires:
|
||||||
- build_node_18
|
- build_node_18
|
||||||
- test_parallel:
|
- test_node:
|
||||||
executor: node18
|
executor: node16
|
||||||
name: test_parallel_node_18
|
name: test_node_16
|
||||||
requires:
|
requires:
|
||||||
- build_node_18
|
- build_node_16
|
||||||
- test_parallel:
|
- test_node:
|
||||||
executor: node20
|
executor: node14
|
||||||
name: test_parallel_node_20
|
name: test_node_14
|
||||||
requires:
|
requires:
|
||||||
- build_node_20
|
- build_node_14
|
||||||
|
- test_node:
|
||||||
|
executor: node12_latest
|
||||||
|
name: test_node_12_latest
|
||||||
|
requires:
|
||||||
|
- build_node_12_latest
|
||||||
|
- test_node:
|
||||||
|
executor: node12_17
|
||||||
|
name: test_node_12_17
|
||||||
|
requires:
|
||||||
|
- build_node_12_17
|
||||||
- test_browsers:
|
- test_browsers:
|
||||||
requires:
|
requires:
|
||||||
- build_node_18
|
- build_node_14
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore: /pull\/.*/ # Don't run on pull requests.
|
ignore: /pull\/.*/ # Don't run on pull requests.
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,6 +1,6 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: I think I've found a bug in Jasmine
|
description: I think I've found a bug in Jasmine
|
||||||
labels: ["bug report"]
|
labels: ["unconfirmed bug"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
46
Gruntfile.js
46
Gruntfile.js
@@ -30,9 +30,9 @@ module.exports = function(grunt) {
|
|||||||
function() {
|
function() {
|
||||||
verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals());
|
verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals());
|
||||||
const done = this.async(),
|
const done = this.async(),
|
||||||
Jasmine = require('jasmine'),
|
Jasmine = require('jasmine'),
|
||||||
jasmineCore = require('./lib/jasmine-core.js'),
|
jasmineCore = require('./lib/jasmine-core.js'),
|
||||||
jasmine = new Jasmine({jasmineCore: jasmineCore});
|
jasmine = new Jasmine({jasmineCore: jasmineCore});
|
||||||
|
|
||||||
jasmine.loadConfigFile('./spec/support/jasmine.json');
|
jasmine.loadConfigFile('./spec/support/jasmine.json');
|
||||||
jasmine.exitOnCompletion = false;
|
jasmine.exitOnCompletion = false;
|
||||||
@@ -40,50 +40,12 @@ module.exports = function(grunt) {
|
|||||||
result => done(result.overallStatus === 'passed'),
|
result => done(result.overallStatus === 'passed'),
|
||||||
err => {
|
err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
done(false);
|
exit(1);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
grunt.registerTask("execSpecsInParallel",
|
|
||||||
"Run Jasmine core specs in parallel in Node.js",
|
|
||||||
function() {
|
|
||||||
// Need to require this here rather than at the top of the file
|
|
||||||
// so that we don't break verifyNoGlobals above by loading jasmine-core
|
|
||||||
// too early
|
|
||||||
const ParallelRunner = require('jasmine/parallel');
|
|
||||||
let numWorkers = require('os').cpus().length;
|
|
||||||
|
|
||||||
if (process.env['CIRCLECI']) {
|
|
||||||
// On Circle CI, the above gives the number of CPU cores on the host
|
|
||||||
// computer, which is unrelated to the resources actually available
|
|
||||||
// to the container. 2 workers gives peak performance with our current
|
|
||||||
// configuration, but 4 might increase the odds of discovering any
|
|
||||||
// parallel-specific bugs.
|
|
||||||
numWorkers = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
const done = this.async();
|
|
||||||
const runner = new ParallelRunner({
|
|
||||||
jasmineCore: require('./lib/jasmine-core.js'),
|
|
||||||
numWorkers
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.loadConfigFile('./spec/support/jasmine.json')
|
|
||||||
.then(() => {
|
|
||||||
runner.exitOnCompletion = false;
|
|
||||||
return runner.execute();
|
|
||||||
}).then(
|
|
||||||
jasmineDoneInfo => done(jasmineDoneInfo.overallStatus === 'passed'),
|
|
||||||
err => {
|
|
||||||
console.error(err);
|
|
||||||
done(false);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
grunt.registerTask("execSpecsInNode:performance",
|
grunt.registerTask("execSpecsInNode:performance",
|
||||||
"Run Jasmine performance specs in Node.js",
|
"Run Jasmine performance specs in Node.js",
|
||||||
function() {
|
function() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
Copyright (c) 2008-2019 Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2023 The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -30,13 +30,13 @@ for information on writing specs, and [the FAQ](https://jasmine.github.io/pages/
|
|||||||
Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and
|
Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and
|
||||||
Microsoft Edge) as well as Node.
|
Microsoft Edge) as well as Node.
|
||||||
|
|
||||||
| Environment | Supported versions |
|
| Environment | Supported versions |
|
||||||
|-------------------|---------------------|
|
|-------------------|--------------------|
|
||||||
| Node | 18, 20 |
|
| Node | 12.17+, 14, 16, 18 |
|
||||||
| Safari | 15-16 |
|
| Safari | 14-16 |
|
||||||
| Chrome | Evergreen |
|
| Chrome | Evergreen |
|
||||||
| Firefox | Evergreen, 102 |
|
| Firefox | Evergreen, 91, 102 |
|
||||||
| Edge | Evergreen |
|
| Edge | Evergreen |
|
||||||
|
|
||||||
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
|
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
|
||||||
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
|
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
|
||||||
@@ -58,4 +58,6 @@ To find out what environments work with a particular Jasmine release, see the [r
|
|||||||
* [Christian Williams](mailto:antixian666@gmail.com)
|
* [Christian Williams](mailto:antixian666@gmail.com)
|
||||||
* Sheel Choksi
|
* Sheel Choksi
|
||||||
|
|
||||||
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/MIT.LICENSE).
|
Copyright (c) 2008-2019 Pivotal Labs<br>
|
||||||
|
Copyright (c) 2008-2024 The Jasmine developers<br>
|
||||||
|
This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE).
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ module.exports = {
|
|||||||
src: ['src/boot/boot1.js'],
|
src: ['src/boot/boot1.js'],
|
||||||
dest: 'lib/jasmine-core/boot1.js'
|
dest: 'lib/jasmine-core/boot1.js'
|
||||||
},
|
},
|
||||||
|
nodeBoot: {
|
||||||
|
src: ['src/boot/node_boot.js'],
|
||||||
|
dest: 'lib/jasmine-core/node_boot.js'
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
banner: license(),
|
banner: license(),
|
||||||
process: {
|
process: {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2008-<%= currentYear %> Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-<%= currentYear %> The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -6,51 +6,36 @@
|
|||||||
const jasmineRequire = require('./jasmine-core/jasmine.js');
|
const jasmineRequire = require('./jasmine-core/jasmine.js');
|
||||||
module.exports = jasmineRequire;
|
module.exports = jasmineRequire;
|
||||||
|
|
||||||
const boot = (function() {
|
|
||||||
let jasmine, jasmineInterface;
|
|
||||||
|
|
||||||
return function bootWithoutGlobals(reinitialize) {
|
|
||||||
if (!jasmineInterface || reinitialize === true) {
|
|
||||||
jasmine = jasmineRequire.core(jasmineRequire);
|
|
||||||
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
|
||||||
jasmineInterface = jasmineRequire.interface(jasmine, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {jasmine, jasmineInterface};
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
|
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
|
||||||
* If boot is called multiple times, the same object is returned every time
|
|
||||||
* unless true is passed.
|
|
||||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
|
||||||
* @type {function}
|
* @type {function}
|
||||||
* @return {jasmine}
|
* @return {jasmine}
|
||||||
*/
|
*/
|
||||||
module.exports.boot = function(reinitialize) {
|
module.exports.boot = require('./jasmine-core/node_boot.js');
|
||||||
const {jasmine, jasmineInterface} = boot(reinitialize);
|
|
||||||
|
|
||||||
for (const k in jasmineInterface) {
|
|
||||||
global[k] = jasmineInterface[k];
|
|
||||||
}
|
|
||||||
|
|
||||||
return jasmine;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boots a copy of Jasmine and returns an object containing the properties
|
* Boots a copy of Jasmine and returns an object containing the properties
|
||||||
* that would normally be added to the global object. If noGlobals is called
|
* that would normally be added to the global object. If noGlobals is called
|
||||||
* multiple times, the same object is returned every time unless true is passed.
|
* multiple times, the same object is returned every time.
|
||||||
|
*
|
||||||
|
* Do not call boot() if you also call noGlobals().
|
||||||
*
|
*
|
||||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
|
||||||
* @example
|
* @example
|
||||||
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
|
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
|
||||||
*/
|
*/
|
||||||
module.exports.noGlobals = function(reinitialize) {
|
module.exports.noGlobals = (function() {
|
||||||
const {jasmineInterface} = boot(reinitialize);
|
let jasmineInterface;
|
||||||
return jasmineInterface;
|
|
||||||
};
|
return function bootWithoutGlobals() {
|
||||||
|
if (!jasmineInterface) {
|
||||||
|
const jasmine = jasmineRequire.core(jasmineRequire);
|
||||||
|
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||||
|
jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jasmineInterface;
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
|
||||||
const path = require('path'),
|
const path = require('path'),
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
@@ -58,9 +43,10 @@ const path = require('path'),
|
|||||||
const rootPath = path.join(__dirname, 'jasmine-core'),
|
const rootPath = path.join(__dirname, 'jasmine-core'),
|
||||||
bootFiles = ['boot0.js', 'boot1.js'],
|
bootFiles = ['boot0.js', 'boot1.js'],
|
||||||
legacyBootFiles = ['boot.js'],
|
legacyBootFiles = ['boot.js'],
|
||||||
|
nodeBootFiles = ['node_boot.js'],
|
||||||
cssFiles = [],
|
cssFiles = [],
|
||||||
jsFiles = [],
|
jsFiles = [],
|
||||||
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles);
|
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles, nodeBootFiles);
|
||||||
|
|
||||||
fs.readdirSync(rootPath).forEach(function(file) {
|
fs.readdirSync(rootPath).forEach(function(file) {
|
||||||
if(fs.statSync(path.join(rootPath, file)).isFile()) {
|
if(fs.statSync(path.join(rootPath, file)).isFile()) {
|
||||||
@@ -70,18 +56,18 @@ fs.readdirSync(rootPath).forEach(function(file) {
|
|||||||
break;
|
break;
|
||||||
case '.js':
|
case '.js':
|
||||||
if (jsFilesToSkip.indexOf(file) < 0) {
|
if (jsFilesToSkip.indexOf(file) < 0) {
|
||||||
jsFiles.push(file);
|
jsFiles.push(file);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports.files = {
|
module.exports.files = {
|
||||||
self: __filename,
|
|
||||||
path: rootPath,
|
path: rootPath,
|
||||||
bootDir: rootPath,
|
bootDir: rootPath,
|
||||||
bootFiles: bootFiles,
|
bootFiles: bootFiles,
|
||||||
|
nodeBootFiles: nodeBootFiles,
|
||||||
cssFiles: cssFiles,
|
cssFiles: cssFiles,
|
||||||
jsFiles: ['jasmine.js'].concat(jsFiles),
|
jsFiles: ['jasmine.js'].concat(jsFiles),
|
||||||
imagesDir: path.join(__dirname, '../images')
|
imagesDir: path.join(__dirname, '../images')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2008-2023 Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2024 The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2008-2023 Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2024 The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2008-2023 Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2024 The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2008-2023 Pivotal Labs
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2024 The Jasmine developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
@@ -89,9 +90,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
||||||
j$
|
j$
|
||||||
);
|
);
|
||||||
j$.reporterEvents = jRequire.reporterEvents(j$);
|
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$);
|
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
j$.Runner = jRequire.Runner(j$);
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
@@ -809,6 +808,14 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
this.result.properties[key] = value;
|
this.result.properties[key] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Spec.prototype.expect = function(actual) {
|
||||||
|
return this.expectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Spec.prototype.expectAsync = function(actual) {
|
||||||
|
return this.asyncExpectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
Spec.prototype.execute = function(
|
Spec.prototype.execute = function(
|
||||||
queueRunnerFactory,
|
queueRunnerFactory,
|
||||||
onComplete,
|
onComplete,
|
||||||
@@ -1175,7 +1182,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
let reporter;
|
let reporter;
|
||||||
let topSuite;
|
let topSuite;
|
||||||
let runner;
|
let runner;
|
||||||
let parallelLoadingState = null; // 'specs', 'helpers', or null for non-parallel
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents the available options to configure Jasmine.
|
* This represents the available options to configure Jasmine.
|
||||||
@@ -1204,10 +1210,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
seed: null,
|
seed: null,
|
||||||
/**
|
/**
|
||||||
* Whether to stop execution of the suite after the first spec failure
|
* Whether to stop execution of the suite after the first spec failure
|
||||||
*
|
|
||||||
* <p>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.</p>
|
|
||||||
* @name Configuration#stopOnSpecFailure
|
* @name Configuration#stopOnSpecFailure
|
||||||
* @since 3.9.0
|
* @since 3.9.0
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
@@ -1283,14 +1285,20 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
if (!options.suppressLoadErrors) {
|
if (!options.suppressLoadErrors) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
globalErrors.pushListener(function loadtimeErrorHandler(error, event) {
|
globalErrors.pushListener(function loadtimeErrorHandler(
|
||||||
|
message,
|
||||||
|
filename,
|
||||||
|
lineno,
|
||||||
|
colNo,
|
||||||
|
err
|
||||||
|
) {
|
||||||
topSuite.result.failedExpectations.push({
|
topSuite.result.failedExpectations.push({
|
||||||
passed: false,
|
passed: false,
|
||||||
globalErrorType: 'load',
|
globalErrorType: 'load',
|
||||||
message: error ? error.message : event.message,
|
message: message,
|
||||||
stack: error && error.stack,
|
stack: err && err.stack,
|
||||||
filename: event && event.filename,
|
filename: filename,
|
||||||
lineno: event && event.lineno
|
lineno: lineno
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1303,12 +1311,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
this.configure = function(configuration) {
|
this.configure = function(configuration) {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error(
|
|
||||||
'Jasmine cannot be configured via Env in parallel mode'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const booleanProps = [
|
const booleanProps = [
|
||||||
'random',
|
'random',
|
||||||
'failSpecWithNoExpectations',
|
'failSpecWithNoExpectations',
|
||||||
@@ -1393,49 +1395,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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 Expectation} 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.
|
|
||||||
* @property {Boolean} passed - Whether the expectation passed or failed.
|
|
||||||
* @property {Object} expected - If the expectation failed, what was the expected value.
|
|
||||||
* @property {Object} actual - If the expectation failed, what actual value was produced.
|
|
||||||
*/
|
|
||||||
const error = new Error(result.message);
|
|
||||||
error.passed = result.passed;
|
|
||||||
error.message = result.message;
|
|
||||||
error.expected = result.expected;
|
|
||||||
error.actual = result.actual;
|
|
||||||
error.matcherName = result.matcherName;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const throwUnlessFactory = function(actual, spec) {
|
|
||||||
return j$.Expectation.factory({
|
|
||||||
matchersUtil: runableResources.makeMatchersUtil(),
|
|
||||||
customMatchers: runableResources.customMatchers(),
|
|
||||||
actual: actual,
|
|
||||||
addExpectationResult: handleThrowUnlessFailure
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const throwUnlessAsyncFactory = function(actual, spec) {
|
|
||||||
return j$.Expectation.asyncFactory({
|
|
||||||
matchersUtil: runableResources.makeMatchersUtil(),
|
|
||||||
customAsyncMatchers: runableResources.customAsyncMatchers(),
|
|
||||||
actual: actual,
|
|
||||||
addExpectationResult: handleThrowUnlessFailure
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
||||||
// diagnostic info added by the latter is probably useful in most cases.
|
// diagnostic info added by the latter is probably useful in most cases.
|
||||||
function recordLateError(error) {
|
function recordLateError(error) {
|
||||||
@@ -1557,6 +1516,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function(e) {
|
function(e) {
|
||||||
(runner.currentRunable() || topSuite).handleException(e);
|
(runner.currentRunable() || topSuite).handleException(e);
|
||||||
};
|
};
|
||||||
|
options.deprecated = self.deprecated;
|
||||||
|
|
||||||
new j$.QueueRunner(options).execute();
|
new j$.QueueRunner(options).execute();
|
||||||
}
|
}
|
||||||
@@ -1582,7 +1542,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
this.topSuite = function() {
|
this.topSuite = function() {
|
||||||
ensureNonParallel('topSuite');
|
|
||||||
return topSuite.metadata;
|
return topSuite.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1592,7 +1551,72 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
reporter = new j$.ReportDispatcher(
|
reporter = new j$.ReportDispatcher(
|
||||||
j$.reporterEvents,
|
[
|
||||||
|
/**
|
||||||
|
* `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 {SuiteResult} 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 {SuiteResult} 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 {SpecResult} 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 {SpecResult} 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'
|
||||||
|
],
|
||||||
function(options) {
|
function(options) {
|
||||||
options.SkipPolicy = j$.NeverSkipPolicy;
|
options.SkipPolicy = j$.NeverSkipPolicy;
|
||||||
return queueRunnerFactory(options);
|
return queueRunnerFactory(options);
|
||||||
@@ -1611,24 +1635,21 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
reportSpecDone
|
reportSpecDone
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setParallelLoadingState = function(state) {
|
|
||||||
parallelLoadingState = state;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.parallelReset = function() {
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
runner.parallelReset();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the specs.
|
* Executes the specs.
|
||||||
*
|
*
|
||||||
* If called with no parameter or with a falsy parameter,
|
* If called with no parameters or with a falsy value as the first parameter,
|
||||||
* all specs will be executed except those that are excluded by a
|
* all specs will be executed except those that are excluded by a
|
||||||
* [spec filter]{@link Configuration#specFilter} or other mechanism. If the
|
* [spec filter]{@link Configuration#specFilter} or other mechanism. If the
|
||||||
* parameter is a list of spec/suite IDs, only those specs/suites will
|
* first parameter is a list of spec/suite IDs, only those specs/suites will
|
||||||
* be run.
|
* be run.
|
||||||
*
|
*
|
||||||
|
* Both parameters are optional, but a completion callback is only valid as
|
||||||
|
* the second parameter. To specify a completion callback but not a list of
|
||||||
|
* specs/suites to run, pass null or undefined as the first parameter. The
|
||||||
|
* completion callback is supported for backward compatibility. In most
|
||||||
|
* cases it will be more convenient to use the returned promise instead.
|
||||||
|
*
|
||||||
* execute should not be called more than once unless the env has been
|
* execute should not be called more than once unless the env has been
|
||||||
* configured with `{autoCleanClosures: false}`.
|
* configured with `{autoCleanClosures: false}`.
|
||||||
*
|
*
|
||||||
@@ -1636,26 +1657,25 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* {@link JasmineDoneInfo|overall result} that's passed to a reporter's
|
* {@link JasmineDoneInfo|overall result} that's passed to a reporter's
|
||||||
* `jasmineDone` method, even if the suite did not pass. To determine
|
* `jasmineDone` method, even if the suite did not pass. To determine
|
||||||
* whether the suite passed, check the value that the promise resolves to
|
* 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
|
* or use a {@link Reporter}.
|
||||||
* certain serious errors that prevent execution from starting.
|
|
||||||
*
|
*
|
||||||
* @name Env#execute
|
* @name Env#execute
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
* @function
|
* @function
|
||||||
* @async
|
|
||||||
* @param {(string[])=} runablesToRun IDs of suites and/or specs to run
|
* @param {(string[])=} runablesToRun IDs of suites and/or specs to run
|
||||||
|
* @param {Function=} onComplete Function that will be called after all specs have run
|
||||||
* @return {Promise<JasmineDoneInfo>}
|
* @return {Promise<JasmineDoneInfo>}
|
||||||
*/
|
*/
|
||||||
this.execute = async function(runablesToRun) {
|
this.execute = function(runablesToRun, onComplete) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
|
|
||||||
if (parallelLoadingState) {
|
return runner.execute(runablesToRun).then(function(jasmineDoneInfo) {
|
||||||
validateConfigForParallel();
|
if (onComplete) {
|
||||||
}
|
onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
const result = await runner.execute(runablesToRun);
|
return jasmineDoneInfo;
|
||||||
this.cleanup_();
|
});
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1667,10 +1687,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
this.addReporter = function(reporterToAdd) {
|
this.addReporter = function(reporterToAdd) {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error('Reporters cannot be added via Env in parallel mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter.addReporter(reporterToAdd);
|
reporter.addReporter(reporterToAdd);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1693,10 +1709,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
this.clearReporters = function() {
|
this.clearReporters = function() {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error('Reporters cannot be removed via Env in parallel mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter.clearReporters();
|
reporter.clearReporters();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1796,38 +1808,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
this.describe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('describe');
|
ensureIsNotNested('describe');
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
@@ -1844,7 +1824,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.fdescribe = function(description, definitionFn) {
|
this.fdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('fdescribe');
|
ensureIsNotNested('fdescribe');
|
||||||
ensureNonParallel('fdescribe');
|
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
@@ -1886,7 +1865,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.fit = function(description, fn, timeout) {
|
this.fit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('fit');
|
ensureIsNotNested('fit');
|
||||||
ensureNonParallel('fit');
|
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
@@ -1939,72 +1917,42 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.expect = function(actual) {
|
this.expect = function(actual) {
|
||||||
const runable = runner.currentRunable();
|
if (!runner.currentRunable()) {
|
||||||
|
|
||||||
if (!runable) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runable.expectationFactory(actual, runable);
|
return runner.currentRunable().expect(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.expectAsync = function(actual) {
|
this.expectAsync = function(actual) {
|
||||||
const runable = runner.currentRunable();
|
if (!runner.currentRunable()) {
|
||||||
|
|
||||||
if (!runable) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runable.asyncExpectationFactory(actual, runable);
|
return runner.currentRunable().expectAsync(actual);
|
||||||
};
|
|
||||||
|
|
||||||
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) {
|
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||||
ensureIsNotNested('beforeEach');
|
ensureIsNotNested('beforeEach');
|
||||||
ensureNonParallelOrInHelperOrInDescribe('beforeEach');
|
|
||||||
suiteBuilder.beforeEach(beforeEachFunction, timeout);
|
suiteBuilder.beforeEach(beforeEachFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.beforeAll = function(beforeAllFunction, timeout) {
|
this.beforeAll = function(beforeAllFunction, timeout) {
|
||||||
ensureIsNotNested('beforeAll');
|
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);
|
suiteBuilder.beforeAll(beforeAllFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.afterEach = function(afterEachFunction, timeout) {
|
this.afterEach = function(afterEachFunction, timeout) {
|
||||||
ensureIsNotNested('afterEach');
|
ensureIsNotNested('afterEach');
|
||||||
ensureNonParallelOrInHelperOrInDescribe('afterEach');
|
|
||||||
suiteBuilder.afterEach(afterEachFunction, timeout);
|
suiteBuilder.afterEach(afterEachFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.afterAll = function(afterAllFunction, timeout) {
|
this.afterAll = function(afterAllFunction, timeout) {
|
||||||
ensureIsNotNested('afterAll');
|
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);
|
suiteBuilder.afterAll(afterAllFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2059,10 +2007,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function callerCallerFilename() {
|
function callerCallerFilename() {
|
||||||
const frames = new j$.StackTrace(new Error()).frames;
|
return new j$.StackTrace(new Error()).frames[3].file;
|
||||||
// frames[3] should always exist except in Jasmine's own tests, which bypass
|
|
||||||
// the global it/describe layer, but don't crash if it doesn't.
|
|
||||||
return frames[3] && frames[3].file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Env;
|
return Env;
|
||||||
@@ -2700,11 +2645,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
|||||||
} else if (options.stack) {
|
} else if (options.stack) {
|
||||||
error = options;
|
error = options;
|
||||||
} else {
|
} else {
|
||||||
try {
|
error = new Error(message());
|
||||||
throw new Error(message());
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Omit the message from the stack trace because it will be
|
// Omit the message from the stack trace because it will be
|
||||||
@@ -3615,7 +3556,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
|||||||
const result = {};
|
const result = {};
|
||||||
let empty = true;
|
let empty = true;
|
||||||
|
|
||||||
for (const prop of Object.keys(error)) {
|
for (const prop in error) {
|
||||||
if (ignoredProperties.includes(prop)) {
|
if (ignoredProperties.includes(prop)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4061,22 +4002,18 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
let overrideHandler = null,
|
let overrideHandler = null,
|
||||||
onRemoveOverrideHandler = null;
|
onRemoveOverrideHandler = null;
|
||||||
|
|
||||||
function onBrowserError(event) {
|
function onerror(message, source, lineno, colno, error) {
|
||||||
dispatchBrowserError(event.error, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dispatchBrowserError(error, event) {
|
|
||||||
if (overrideHandler) {
|
if (overrideHandler) {
|
||||||
overrideHandler(error);
|
overrideHandler(error || message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(error, event);
|
handler.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw arguments[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4153,7 +4090,8 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
this.installOne_('uncaughtException', 'Uncaught exception');
|
this.installOne_('uncaughtException', 'Uncaught exception');
|
||||||
this.installOne_('unhandledRejection', 'Unhandled promise rejection');
|
this.installOne_('unhandledRejection', 'Unhandled promise rejection');
|
||||||
} else {
|
} else {
|
||||||
global.addEventListener('error', onBrowserError);
|
const originalHandler = global.onerror;
|
||||||
|
global.onerror = onerror;
|
||||||
|
|
||||||
const browserRejectionHandler = function browserRejectionHandler(
|
const browserRejectionHandler = function browserRejectionHandler(
|
||||||
event
|
event
|
||||||
@@ -4161,19 +4099,16 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
if (j$.isError_(event.reason)) {
|
if (j$.isError_(event.reason)) {
|
||||||
event.reason.jasmineMessage =
|
event.reason.jasmineMessage =
|
||||||
'Unhandled promise rejection: ' + event.reason;
|
'Unhandled promise rejection: ' + event.reason;
|
||||||
dispatchBrowserError(event.reason, event);
|
global.onerror(event.reason);
|
||||||
} else {
|
} else {
|
||||||
dispatchBrowserError(
|
global.onerror('Unhandled promise rejection: ' + event.reason);
|
||||||
'Unhandled promise rejection: ' + event.reason,
|
|
||||||
event
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
||||||
|
|
||||||
this.uninstall = function uninstall() {
|
this.uninstall = function uninstall() {
|
||||||
global.removeEventListener('error', onBrowserError);
|
global.onerror = originalHandler;
|
||||||
global.removeEventListener(
|
global.removeEventListener(
|
||||||
'unhandledrejection',
|
'unhandledrejection',
|
||||||
browserRejectionHandler
|
browserRejectionHandler
|
||||||
@@ -4182,13 +4117,6 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The listener at the top of the stack will be called with two arguments:
|
|
||||||
// the error and the event. Either of them may be falsy.
|
|
||||||
// The error will normally be provided, but will be falsy in the case of
|
|
||||||
// some browser load-time errors. The event will normally be provided in
|
|
||||||
// browsers but will be falsy in Node.
|
|
||||||
// Listeners that are pushed after spec files have been loaded should be
|
|
||||||
// able to just use the error parameter.
|
|
||||||
this.pushListener = function pushListener(listener) {
|
this.pushListener = function pushListener(listener) {
|
||||||
handlers.push(listener);
|
handlers.push(listener);
|
||||||
};
|
};
|
||||||
@@ -7158,100 +7086,6 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
|
|||||||
return NeverSkipPolicy;
|
return NeverSkipPolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
|
||||||
/**
|
|
||||||
* @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$.ReportDispatcher;
|
|
||||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
|
||||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
|
||||||
const dispatcher = ReportDispatcher(
|
|
||||||
j$.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$.reporterEvents) {
|
|
||||||
self[eventName] = dispatcher[eventName].bind(dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ParallelReportDispatcher;
|
|
||||||
};
|
|
||||||
|
|
||||||
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
||||||
class SinglePrettyPrintRun {
|
class SinglePrettyPrintRun {
|
||||||
constructor(customObjectFormatters, pp) {
|
constructor(customObjectFormatters, pp) {
|
||||||
@@ -7676,11 +7510,15 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
if (typeof this.onComplete !== 'function') {
|
if (typeof this.onComplete !== 'function') {
|
||||||
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
|
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
|
||||||
}
|
}
|
||||||
|
this.deprecated = attrs.deprecated;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueRunner.prototype.execute = function() {
|
QueueRunner.prototype.execute = function() {
|
||||||
this.handleFinalError = error => {
|
this.handleFinalError = (message, source, lineno, colno, error) => {
|
||||||
this.onException(error);
|
// Older browsers would send the error as the first parameter. HTML5
|
||||||
|
// specifies the the five parameters above. The error instance should
|
||||||
|
// be preffered, otherwise the call stack would get lost.
|
||||||
|
this.onException(error || message);
|
||||||
};
|
};
|
||||||
this.globalErrors.pushListener(this.handleFinalError);
|
this.globalErrors.pushListener(this.handleFinalError);
|
||||||
this.run(0);
|
this.run(0);
|
||||||
@@ -7869,21 +7707,17 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
// on the stack at this point.
|
// on the stack at this point.
|
||||||
if (j$.isAsyncFunction_(fn)) {
|
if (j$.isAsyncFunction_(fn)) {
|
||||||
this.onException(
|
this.onException(
|
||||||
new Error(
|
'An asynchronous before/it/after ' +
|
||||||
'An asynchronous before/it/after ' +
|
'function was defined with the async keyword but also took a ' +
|
||||||
'function was defined with the async keyword but also took a ' +
|
'done callback. Either remove the done callback (recommended) or ' +
|
||||||
'done callback. Either remove the done callback (recommended) or ' +
|
'remove the async keyword.'
|
||||||
'remove the async keyword.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.onException(
|
this.onException(
|
||||||
new Error(
|
'An asynchronous before/it/after ' +
|
||||||
'An asynchronous before/it/after ' +
|
'function took a done callback but also returned a promise. ' +
|
||||||
'function took a done callback but also returned a promise. ' +
|
'Either remove the done callback (recommended) or change the ' +
|
||||||
'Either remove the done callback (recommended) or change the ' +
|
'function to not return a promise.'
|
||||||
'function to not return a promise.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7983,77 +7817,6 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
return ReportDispatcher;
|
return ReportDispatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().reporterEvents = function() {
|
|
||||||
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 {SuiteResult} 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 {SuiteResult} 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 {SpecResult} 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 {SpecResult} 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) {
|
getJasmineRequireObj().interface = function(jasmine, env) {
|
||||||
const jasmineInterface = {
|
const jasmineInterface = {
|
||||||
/**
|
/**
|
||||||
@@ -8281,54 +8044,6 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
|||||||
return env.expectAsync(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
|
|
||||||
* @param actual
|
|
||||||
* @global
|
|
||||||
* @param {Object} actual - Actual computed value to test expectations against.
|
|
||||||
* @return {matchers}
|
|
||||||
*/
|
|
||||||
throwUnlessAsync: function(actual) {
|
|
||||||
return env.throwUnless(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
|
|
||||||
* @param actual
|
|
||||||
* @global
|
|
||||||
* @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.
|
* Mark a spec as pending, expectation results will be ignored.
|
||||||
* @name pending
|
* @name pending
|
||||||
@@ -8693,7 +8408,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
class Runner {
|
class Runner {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.topSuite_ = options.topSuite;
|
this.topSuite_ = options.topSuite;
|
||||||
// TODO use names that read like getters
|
|
||||||
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
||||||
this.focusedRunables_ = options.focusedRunables;
|
this.focusedRunables_ = options.focusedRunables;
|
||||||
this.runableResources_ = options.runableResources;
|
this.runableResources_ = options.runableResources;
|
||||||
@@ -8718,11 +8432,11 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
parallelReset() {
|
// Although execute returns a promise, it isn't async for backwards
|
||||||
this.executedBefore_ = false;
|
// compatibility: The "Invalid order" exception needs to be propagated
|
||||||
}
|
// synchronously from Env#execute.
|
||||||
|
// TODO: make this and Env#execute async in the next major release
|
||||||
async execute(runablesToRun) {
|
execute(runablesToRun) {
|
||||||
if (this.executedBefore_) {
|
if (this.executedBefore_) {
|
||||||
this.topSuite_.reset();
|
this.topSuite_.reset();
|
||||||
}
|
}
|
||||||
@@ -8818,17 +8532,13 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
/**
|
/**
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
* @typedef JasmineStartedInfo
|
* @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} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
* @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 {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
* @property {Boolean} parallel - Whether Jasmine is being run in parallel mode.
|
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
await this.reporter_.jasmineStarted({
|
await this.reporter_.jasmineStarted({
|
||||||
// In parallel mode, the jasmineStarted event is separately dispatched
|
|
||||||
// by jasmine-npm. This event only reaches reporters in non-parallel.
|
|
||||||
totalSpecsDefined,
|
totalSpecsDefined,
|
||||||
order: order,
|
order: order
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.currentlyExecutingSuites_.push(this.topSuite_);
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
@@ -8840,7 +8550,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
|
|
||||||
this.runableResources_.clearForRunable(this.topSuite_.id);
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
this.currentlyExecutingSuites_.pop();
|
this.currentlyExecutingSuites_.pop();
|
||||||
let overallStatus, incompleteReason, incompleteCode;
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.hasFailures ||
|
this.hasFailures ||
|
||||||
@@ -8850,11 +8560,9 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
} else if (this.focusedRunables_().length > 0) {
|
} else if (this.focusedRunables_().length > 0) {
|
||||||
overallStatus = 'incomplete';
|
overallStatus = 'incomplete';
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
incompleteCode = 'focused';
|
|
||||||
} else if (totalSpecsDefined === 0) {
|
} else if (totalSpecsDefined === 0) {
|
||||||
overallStatus = 'incomplete';
|
overallStatus = 'incomplete';
|
||||||
incompleteReason = 'No specs found';
|
incompleteReason = 'No specs found';
|
||||||
incompleteCode = 'noSpecsFound';
|
|
||||||
} else {
|
} else {
|
||||||
overallStatus = 'passed';
|
overallStatus = 'passed';
|
||||||
}
|
}
|
||||||
@@ -8864,10 +8572,8 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
* @typedef JasmineDoneInfo
|
* @typedef JasmineDoneInfo
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
* @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 {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 {IncompleteReason} incompleteReason - 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.
|
||||||
* @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 {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
||||||
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
@@ -8876,7 +8582,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
overallStatus: overallStatus,
|
overallStatus: overallStatus,
|
||||||
totalTime: jasmineTimer.elapsed(),
|
totalTime: jasmineTimer.elapsed(),
|
||||||
incompleteReason: incompleteReason,
|
incompleteReason: incompleteReason,
|
||||||
incompleteCode: incompleteCode,
|
|
||||||
order: order,
|
order: order,
|
||||||
failedExpectations: this.topSuite_.result.failedExpectations,
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
@@ -9852,6 +9557,14 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.result.properties[key] = value;
|
this.result.properties[key] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Suite.prototype.expect = function(actual) {
|
||||||
|
return this.expectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite.prototype.expectAsync = function(actual) {
|
||||||
|
return this.asyncExpectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
Suite.prototype.getFullName = function() {
|
Suite.prototype.getFullName = function() {
|
||||||
const fullName = [];
|
const fullName = [];
|
||||||
for (
|
for (
|
||||||
@@ -9954,10 +9667,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.reportedDone = false;
|
this.reportedDone = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Suite.prototype.removeChildren = function() {
|
|
||||||
this.children = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
Suite.prototype.addChild = function(child) {
|
Suite.prototype.addChild = function(child) {
|
||||||
this.children.push(child);
|
this.children.push(child);
|
||||||
};
|
};
|
||||||
@@ -10173,17 +9882,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
this.focusedRunables = [];
|
this.focusedRunables = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
inDescribe() {
|
|
||||||
return this.currentDeclarationSuite_ !== this.topSuite;
|
|
||||||
}
|
|
||||||
|
|
||||||
parallelReset() {
|
|
||||||
this.topSuite.removeChildren();
|
|
||||||
this.topSuite.reset();
|
|
||||||
this.totalSpecsDefined = 0;
|
|
||||||
this.focusedRunables = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe(description, definitionFn, filename) {
|
describe(description, definitionFn, filename) {
|
||||||
ensureIsFunction(definitionFn, 'describe');
|
ensureIsFunction(definitionFn, 'describe');
|
||||||
const suite = this.suiteFactory_(description, filename);
|
const suite = this.suiteFactory_(description, filename);
|
||||||
@@ -10481,35 +10179,16 @@ getJasmineRequireObj().Timer = function() {
|
|||||||
};
|
};
|
||||||
})(Date);
|
})(Date);
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Timer
|
|
||||||
* @classdesc Tracks elapsed time
|
|
||||||
* @example
|
|
||||||
* const timer = new jasmine.Timer();
|
|
||||||
* timer.start();
|
|
||||||
* const elapsed = timer.elapsed()
|
|
||||||
*/
|
|
||||||
function Timer(options) {
|
function Timer(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
const now = options.now || defaultNow;
|
const now = options.now || defaultNow;
|
||||||
let startTime;
|
let startTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the timer.
|
|
||||||
* @function
|
|
||||||
* @name Timer#start
|
|
||||||
*/
|
|
||||||
this.start = function() {
|
this.start = function() {
|
||||||
startTime = now();
|
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() {
|
this.elapsed = function() {
|
||||||
return now() - startTime;
|
return now() - startTime;
|
||||||
};
|
};
|
||||||
@@ -10802,5 +10481,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().version = function() {
|
getJasmineRequireObj().version = function() {
|
||||||
return '5.1.0';
|
return '4.6.1';
|
||||||
};
|
};
|
||||||
|
|||||||
39
lib/jasmine-core/node_boot.js
Normal file
39
lib/jasmine-core/node_boot.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2008-2019 Pivotal Labs
|
||||||
|
Copyright (c) 2008-2024 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.
|
||||||
|
*/
|
||||||
|
module.exports = function(jasmineRequire) {
|
||||||
|
const jasmine = jasmineRequire.core(jasmineRequire);
|
||||||
|
|
||||||
|
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||||
|
|
||||||
|
const jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||||
|
|
||||||
|
extend(global, jasmineInterface);
|
||||||
|
|
||||||
|
function extend(destination, source) {
|
||||||
|
for (const property in source) destination[property] = source[property];
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jasmine;
|
||||||
|
};
|
||||||
26
package.json
26
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jasmine-core",
|
"name": "jasmine-core",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "5.1.0",
|
"version": "4.6.1",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/jasmine/jasmine.git"
|
"url": "https://github.com/jasmine/jasmine.git"
|
||||||
@@ -34,21 +34,21 @@
|
|||||||
"package.json"
|
"package.json"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.36.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-compat": "^4.0.0",
|
"eslint-plugin-compat": ">=4.0.0 <4.1.0",
|
||||||
"glob": "^10.2.3",
|
"glob": "^7.2.0",
|
||||||
"grunt": "^1.0.4",
|
"grunt": ">=1.0.4 <1.6.0",
|
||||||
"grunt-cli": "^1.3.2",
|
"grunt-cli": "^1.3.2",
|
||||||
"grunt-contrib-compress": "^2.0.0",
|
"grunt-contrib-compress": "^2.0.0",
|
||||||
"grunt-contrib-concat": "^2.0.0",
|
"grunt-contrib-concat": "^2.0.0",
|
||||||
"grunt-css-url-embed": "^1.11.1",
|
"grunt-css-url-embed": "^1.11.1",
|
||||||
"grunt-sass": "^3.0.2",
|
"grunt-sass": "^3.0.2",
|
||||||
"jasmine": "^5.0.0",
|
"jasmine": "^4.1.0",
|
||||||
"jasmine-browser-runner": "github:jasmine/jasmine-browser-runner",
|
"jasmine-browser-runner": "^1.0.0",
|
||||||
"jsdom": "^22.0.0",
|
"jsdom": "^19.0.0",
|
||||||
"load-grunt-tasks": "^5.1.0",
|
"load-grunt-tasks": "^5.1.0",
|
||||||
"prettier": "1.17.1",
|
"prettier": "1.17.1",
|
||||||
"sass": "^1.58.3",
|
"sass": "1.58.3",
|
||||||
"shelljs": "^0.8.3",
|
"shelljs": "^0.8.3",
|
||||||
"temp": "^0.9.0"
|
"temp": "^0.9.0"
|
||||||
},
|
},
|
||||||
@@ -97,14 +97,14 @@
|
|||||||
],
|
],
|
||||||
"space-before-blocks": "error",
|
"space-before-blocks": "error",
|
||||||
"no-eval": "error",
|
"no-eval": "error",
|
||||||
"no-var": "error",
|
"no-var": "error"
|
||||||
"no-debugger": "error"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"Safari >= 15",
|
"Safari >= 14",
|
||||||
"Firefox >= 102",
|
|
||||||
"last 2 Chrome versions",
|
"last 2 Chrome versions",
|
||||||
|
"last 2 Firefox versions",
|
||||||
|
"Firefox >= 91",
|
||||||
"last 2 Edge versions"
|
"last 2 Edge versions"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
# Jasmine Core 5.0.0-alpha.0 Release Notes
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
This release primarily adds support for parallel execution via the `jasmine`
|
|
||||||
package. Please see its release notes and the
|
|
||||||
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
|
||||||
for more information. Additionally, this release cleans up a few outdated
|
|
||||||
interfaces.
|
|
||||||
|
|
||||||
This is a pre-release for a major version. It contains breaking changes, and
|
|
||||||
there may be further breaking changes between this release and the final 5.0.0
|
|
||||||
release.
|
|
||||||
|
|
||||||
## Breaking changes
|
|
||||||
|
|
||||||
* Use addEventListener in browsers rather than setting window.onerror
|
|
||||||
|
|
||||||
This simplifies error handling in browsers, makes Jasmine's own integration
|
|
||||||
tests easier to debug, and provides stack traces for more unhandled
|
|
||||||
exceptions. However, some browsers will provide less error information when
|
|
||||||
the error comes from a file:// URL. Additionally, Jasmine will no longer
|
|
||||||
override existing onerror handlers, and setting window.onerror will no longer
|
|
||||||
override Jasmine's global error handling. (Use `jasmine.spyOnGlobalErrors`
|
|
||||||
instead.)
|
|
||||||
|
|
||||||
* Made Env#execute async
|
|
||||||
* Env#execute no longer takes a callback
|
|
||||||
* The `boot` function exported by the core module returns the same object
|
|
||||||
every time it's called.
|
|
||||||
* Removed node_boot.js. Use the exported `boot` function instead.
|
|
||||||
|
|
||||||
### Changes to supported environments
|
|
||||||
|
|
||||||
The following previously supported environments are no longer supported:
|
|
||||||
|
|
||||||
* Node <16.14
|
|
||||||
* Safari 14
|
|
||||||
* Firefox 91
|
|
||||||
|
|
||||||
Although this release may still work in some of those environments, we no
|
|
||||||
longer test against them and won't try to maintain compatibility with them in
|
|
||||||
future releases.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
|
|
||||||
* Support for parallel execution in Node.js using the `jasmine` package
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
|
|
||||||
* The global error handler is uninstalled at the end of env execution.
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.0.0-alpha.0 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 16.14+, 18 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 111 |
|
|
||||||
| Firefox | 102, 111 |
|
|
||||||
| Edge | 111 |
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Jasmine Core 5.0.0-alpha.1 Release Notes
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
This release provides improved support for parallel execution via the `jasmine`
|
|
||||||
package. Please see its release notes and the
|
|
||||||
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
## New features and bug fixes
|
|
||||||
|
|
||||||
* Parallel: Cleaner interface for reporter dispatching
|
|
||||||
* When Env#config is called from spec and helper files in parallel mode, throw
|
|
||||||
an error rather than behaving unpredictably.
|
|
||||||
|
|
||||||
## Documentation improvements
|
|
||||||
|
|
||||||
* API reference docs for parallel support APIs that jasmine-npm uses
|
|
||||||
|
|
||||||
## Internal improvements
|
|
||||||
|
|
||||||
* Updated dev dependencies
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.0.0-alpha.1 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 16.14+, 18 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 112 |
|
|
||||||
| Firefox | 102, 111 |
|
|
||||||
| Edge | 111 |
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Jasmine Core 5.0.0-beta.0 Release Notes
|
|
||||||
|
|
||||||
This release supports the 5.0.0-beta-0 release of the `jasmine` package.
|
|
||||||
|
|
||||||
## Breaking changes
|
|
||||||
|
|
||||||
* Dropped support for Node 16
|
|
||||||
|
|
||||||
## New features
|
|
||||||
|
|
||||||
* Added support for Node 20
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.0.0-beta.0 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 18, 20 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 112 |
|
|
||||||
| Firefox | 102, 112 |
|
|
||||||
| Edge | 112 |
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# Jasmine Core 5.0.0 Release Notes
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
This is a major release that includes breaking changes. It primarily adds
|
|
||||||
support for parallel execution in Node via the `jasmine` package. Most users
|
|
||||||
should be able to upgrade without changes, but please read the list of breaking
|
|
||||||
changes below and see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0)
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
## Breaking changes
|
|
||||||
|
|
||||||
* Dropped support for Node 12, 14, and 16
|
|
||||||
* Dropped support for Safari 14 and Firefox 91
|
|
||||||
* Made Env#execute async and removed the callback parameter
|
|
||||||
* Global errors are detected via addEventListener rather than setting window.onerror
|
|
||||||
* The `boot` function exported by the core module returns the same object
|
|
||||||
every time it's called.
|
|
||||||
* Removed node_boot.js. Use the exported `boot` function instead.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
|
|
||||||
* Support for parallel execution in Node via the `jasmine` package
|
|
||||||
See the [parallel guide](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
|
||||||
for more information.
|
|
||||||
* Added Node 20 to supported environments
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
|
|
||||||
* Accessibility: Always provide a non-color indication that a spec is pending
|
|
||||||
* Accessibility: Improved contrast of version number and inactive tab links
|
|
||||||
* Uninstall the global error handler at the end of env execution
|
|
||||||
|
|
||||||
## Internal improvements
|
|
||||||
|
|
||||||
* Updated dev dependencies
|
|
||||||
* Dogfood parallel execution feature in CI
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.0.0 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 18, 20 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 113 |
|
|
||||||
| Firefox | 102, 113 |
|
|
||||||
| Edge | 113 |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Jasmine Core 5.0.1 Release Notes
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
* Optionally restore the pre-5.0 behavior of boot() always creating a new instance
|
|
||||||
|
|
||||||
This is needed by jasmine-npm (and likely other tools like it) that may
|
|
||||||
need to create and use multiple envs in sequence.
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.0.1 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 18, 20 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 114 |
|
|
||||||
| Firefox | 102, 113 |
|
|
||||||
| Edge | 113 |
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Jasmine Core 5.1.0 Release Notes
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
* Exclude inherited Error properties from stack trace
|
|
||||||
|
|
||||||
* Fixed error when formatting Error object with non-Error cause property
|
|
||||||
|
|
||||||
Merges [#2013](https://github.com/jasmine/jasmine/pull/2013) from @angrycat9000.
|
|
||||||
|
|
||||||
Fixes [#2011](https://github.com/jasmine/jasmine/issues/2011).
|
|
||||||
|
|
||||||
* Added `throwUnless` and `throwUnlessAsync`
|
|
||||||
|
|
||||||
These are similar to `expect` and `expectAsync` except that they throw
|
|
||||||
exceptions rather than recording matcher failures as spec/suite failures.
|
|
||||||
They're intended to support using Jasmine matchers in [testing-library's](https://testing-library.com/)
|
|
||||||
`waitFor`, and also provide a way to integration-test custom matchers.
|
|
||||||
|
|
||||||
Fixes [#2003](https://github.com/jasmine/jasmine/issues/2003).
|
|
||||||
|
|
||||||
Fixes [#1980](https://github.com/jasmine/jasmine/issues/1980).
|
|
||||||
|
|
||||||
## Supported environments
|
|
||||||
|
|
||||||
jasmine-core 5.1.0 has been tested in the following environments.
|
|
||||||
|
|
||||||
| Environment | Supported versions |
|
|
||||||
|-------------------|--------------------|
|
|
||||||
| Node | 18, 20 |
|
|
||||||
| Safari | 15-16 |
|
|
||||||
| Chrome | 114 |
|
|
||||||
| Firefox | 102, 113 |
|
|
||||||
| Edge | 113 |
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
run_browser() {
|
run_browser() {
|
||||||
browser=$1
|
browser=$1
|
||||||
version=$2
|
version=$2
|
||||||
|
os="$3"
|
||||||
description="$browser $version"
|
description="$browser $version"
|
||||||
if [ $version = "latest" ]; then
|
if [ $version = "latest" ]; then
|
||||||
version=""
|
version=""
|
||||||
@@ -12,7 +13,7 @@ run_browser() {
|
|||||||
echo
|
echo
|
||||||
echo "Running $description"
|
echo "Running $description"
|
||||||
echo
|
echo
|
||||||
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version npm run ci
|
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version SAUCE_OS="$os" npm run ci
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "PASS: $description" >> "$passfile"
|
echo "PASS: $description" >> "$passfile"
|
||||||
@@ -23,11 +24,23 @@ run_browser() {
|
|||||||
|
|
||||||
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||||
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||||
run_browser chrome latest
|
|
||||||
|
# As of 2023-09-30, Sauce Connect doesn't work with the latest Chrome version
|
||||||
|
# on the default Linux. Run on Mac OS instead. The OS specification may need to
|
||||||
|
# be updated or removed when new Chrome versions stop being available on Mac OS
|
||||||
|
# 12, although historically this has taken several major OS versions.
|
||||||
|
# See <https://saucelabs.com/products/supported-browsers-devices>.
|
||||||
|
# On Saucelabs, the test suite frequently runs ~30s slower on Mac OS than it
|
||||||
|
# does on Linux, so it's probably worth removing the OS specification once Sauce
|
||||||
|
# Connect works with Chrome latest on Linux again.
|
||||||
|
run_browser chrome latest "macOS 12"
|
||||||
|
|
||||||
run_browser firefox latest
|
run_browser firefox latest
|
||||||
run_browser firefox 102
|
run_browser firefox 102
|
||||||
|
run_browser firefox 91
|
||||||
run_browser safari 16
|
run_browser safari 16
|
||||||
run_browser safari 15
|
run_browser safari 15
|
||||||
|
run_browser safari 14
|
||||||
run_browser MicrosoftEdge latest
|
run_browser MicrosoftEdge latest
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ describe('AsyncExpectation', function() {
|
|||||||
|
|
||||||
it('converts a fail to a pass', function() {
|
it('converts a fail to a pass', function() {
|
||||||
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||||
actual = Promise.reject(new Error('nope')),
|
actual = Promise.reject(),
|
||||||
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||||
matchersUtil: new jasmineUnderTest.MatchersUtil({
|
matchersUtil: new jasmineUnderTest.MatchersUtil({
|
||||||
pp: function() {}
|
pp: function() {}
|
||||||
@@ -138,7 +138,7 @@ describe('AsyncExpectation', function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||||
actual = Promise.reject(new Error('nope')),
|
actual = Promise.reject(),
|
||||||
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||||
actual: actual,
|
actual: actual,
|
||||||
addExpectationResult: addExpectationResult,
|
addExpectationResult: addExpectationResult,
|
||||||
|
|||||||
@@ -80,19 +80,6 @@ describe('Env', function() {
|
|||||||
);
|
);
|
||||||
expect(suite.children[1].children[1].children[0].children).toBeFalsy();
|
expect(suite.children[1].children[1].children[0].children).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if called in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
check();
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
check();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
expect(function() {
|
|
||||||
env.topSuite();
|
|
||||||
}).toThrowError("'topSuite' is not available in parallel mode");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts its own current configureation', function() {
|
it('accepts its own current configureation', function() {
|
||||||
@@ -264,15 +251,6 @@ describe('Env', function() {
|
|||||||
|
|
||||||
describe('#fdescribe', function() {
|
describe('#fdescribe', function() {
|
||||||
behavesLikeDescribe('fdescribe');
|
behavesLikeDescribe('fdescribe');
|
||||||
|
|
||||||
it('throws an error in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.fdescribe('a suite', function() {
|
|
||||||
env.it('a spec');
|
|
||||||
});
|
|
||||||
}).toThrowError("'fdescribe' is not available in parallel mode");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('xdescribe', function() {
|
describe('xdescribe', function() {
|
||||||
@@ -394,13 +372,6 @@ describe('Env', function() {
|
|||||||
env.fit('huge timeout', function() {}, 2147483648);
|
env.fit('huge timeout', function() {}, 2147483648);
|
||||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws an error in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.fit('a spec', function() {});
|
|
||||||
}).toThrowError("'fit' is not available in parallel mode");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#beforeEach', function() {
|
describe('#beforeEach', function() {
|
||||||
@@ -423,28 +394,6 @@ describe('Env', function() {
|
|||||||
env.beforeEach(function() {}, 2147483648);
|
env.beforeEach(function() {}, 2147483648);
|
||||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws when called at the top level in a spec file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.beforeEach(function() {});
|
|
||||||
}).toThrowError(
|
|
||||||
'In parallel mode, beforeEach must be in a describe block or in a helper file'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when called at the top level in a helper file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
env.beforeEach(function() {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when called in a describe in a spec file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
env.describe('a suite', function() {
|
|
||||||
env.beforeEach(function() {});
|
|
||||||
env.it('a spec');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#beforeAll', function() {
|
describe('#beforeAll', function() {
|
||||||
@@ -467,47 +416,6 @@ describe('Env', function() {
|
|||||||
env.beforeAll(function() {}, 2147483648);
|
env.beforeAll(function() {}, 2147483648);
|
||||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('in parallel mode', function() {
|
|
||||||
it('throws an error when called at the top level', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
check();
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
check();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
expect(function() {
|
|
||||||
env.beforeAll(function() {});
|
|
||||||
}).toThrowError(
|
|
||||||
"In parallel mode, 'beforeAll' must be in a describe block. " +
|
|
||||||
'Use the globalSetup config property for exactly-once setup in' +
|
|
||||||
' parallel mode.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw an error when called in a describe', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
check();
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
check();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
let done = false;
|
|
||||||
|
|
||||||
env.describe('a suite', function() {
|
|
||||||
expect(function() {
|
|
||||||
env.it('a spec');
|
|
||||||
env.beforeAll(function() {});
|
|
||||||
}).not.toThrow();
|
|
||||||
|
|
||||||
done = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(done).toBeTrue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#afterEach', function() {
|
describe('#afterEach', function() {
|
||||||
@@ -530,28 +438,6 @@ describe('Env', function() {
|
|||||||
env.afterEach(function() {}, 2147483648);
|
env.afterEach(function() {}, 2147483648);
|
||||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws when called at the top level in a spec file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.afterEach(function() {});
|
|
||||||
}).toThrowError(
|
|
||||||
'In parallel mode, afterEach must be in a describe block or in a helper file'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when called at the top level in a helper file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
env.afterEach(function() {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when called in a describe in a spec file in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
env.describe('a suite', function() {
|
|
||||||
env.afterEach(function() {});
|
|
||||||
env.it('a spec');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#afterAll', function() {
|
describe('#afterAll', function() {
|
||||||
@@ -574,47 +460,6 @@ describe('Env', function() {
|
|||||||
env.afterAll(function() {}, 2147483648);
|
env.afterAll(function() {}, 2147483648);
|
||||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('in parallel mode', function() {
|
|
||||||
it('throws an error when called at the top level', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
check();
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
check();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
expect(function() {
|
|
||||||
env.afterAll(function() {});
|
|
||||||
}).toThrowError(
|
|
||||||
"In parallel mode, 'afterAll' must be in a describe block. " +
|
|
||||||
'Use the globalTeardown config property for exactly-once ' +
|
|
||||||
'teardown in parallel mode.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw an error when called in a describe', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
check();
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
check();
|
|
||||||
|
|
||||||
function check() {
|
|
||||||
let done = false;
|
|
||||||
|
|
||||||
env.describe('a suite', function() {
|
|
||||||
expect(function() {
|
|
||||||
env.it('a spec');
|
|
||||||
env.afterAll(function() {});
|
|
||||||
}).not.toThrow();
|
|
||||||
|
|
||||||
done = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(done).toBeTrue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when not constructed with suppressLoadErrors: true', function() {
|
describe('when not constructed with suppressLoadErrors: true', function() {
|
||||||
@@ -747,32 +592,6 @@ describe('Env', function() {
|
|||||||
expect(id).toEqual(env.topSuite().id);
|
expect(id).toEqual(env.topSuite().id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not reset the topSuite if parallelReset was called since the last run', async function() {
|
|
||||||
await env.execute();
|
|
||||||
env.parallelReset();
|
|
||||||
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
|
|
||||||
await env.execute();
|
|
||||||
expect(jasmineUnderTest.Suite.prototype.reset).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('In parallel mode', function() {
|
|
||||||
it('rejects if random is set to false', async function() {
|
|
||||||
env.configure({ random: false });
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
await expectAsync(env.execute()).toBeRejectedWithError(
|
|
||||||
'Randomization cannot be disabled in parallel mode'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects if seed is set', async function() {
|
|
||||||
env.configure({ seed: 1234 });
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
await expectAsync(env.execute()).toBeRejectedWithError(
|
|
||||||
'Random seed cannot be set in parallel mode'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#spyOnGlobalErrorsAsync', function() {
|
describe('#spyOnGlobalErrorsAsync', function() {
|
||||||
@@ -789,46 +608,4 @@ describe('Env', function() {
|
|||||||
).toBeRejectedWithError(msg);
|
).toBeRejectedWithError(msg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#addReporter', function() {
|
|
||||||
it('throws when called in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
expect(function() {
|
|
||||||
env.addReporter({});
|
|
||||||
}).toThrowError('Reporters cannot be added via Env in parallel mode');
|
|
||||||
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.addReporter({});
|
|
||||||
}).toThrowError('Reporters cannot be added via Env in parallel mode');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#clearReporters', function() {
|
|
||||||
it('throws when called in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
expect(function() {
|
|
||||||
env.clearReporters();
|
|
||||||
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
|
|
||||||
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.clearReporters();
|
|
||||||
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#configure', function() {
|
|
||||||
it('throws when called in parallel mode', function() {
|
|
||||||
env.setParallelLoadingState('helpers');
|
|
||||||
expect(function() {
|
|
||||||
env.configure({});
|
|
||||||
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
|
|
||||||
|
|
||||||
env.setParallelLoadingState('specs');
|
|
||||||
expect(function() {
|
|
||||||
env.configure({});
|
|
||||||
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ describe('ExceptionFormatter', function() {
|
|||||||
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
|
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes the error's own properties in stack", function() {
|
it('includes error properties in stack', function() {
|
||||||
const error = new Error('an error');
|
const error = new Error('an error');
|
||||||
error.someProperty = 'hello there';
|
error.someProperty = 'hello there';
|
||||||
|
|
||||||
@@ -206,19 +206,6 @@ describe('ExceptionFormatter', function() {
|
|||||||
expect(result).toMatch(/error properties:.*someProperty.*hello there/);
|
expect(result).toMatch(/error properties:.*someProperty.*hello there/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not include inherited error properties', function() {
|
|
||||||
function CustomError(msg) {
|
|
||||||
Error.call(this, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomError.prototype = new Error();
|
|
||||||
CustomError.prototype.anInheritedProp = 'something';
|
|
||||||
const error = new CustomError('nope');
|
|
||||||
|
|
||||||
const result = new jasmineUnderTest.ExceptionFormatter().stack(error);
|
|
||||||
expect(result).not.toContain('anInheritedProp');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('When omitMessage is true', function() {
|
describe('When omitMessage is true', function() {
|
||||||
it('filters the message from V8-style stack traces', function() {
|
it('filters the message from V8-style stack traces', function() {
|
||||||
const error = {
|
const error = {
|
||||||
@@ -270,7 +257,17 @@ describe('ExceptionFormatter', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the error has a cause property', function() {
|
describe('In environments that support the cause property of Errors', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
const inner = new Error('inner');
|
||||||
|
const outer = new Error('outer', { cause: inner });
|
||||||
|
|
||||||
|
if (!outer.cause) {
|
||||||
|
// Currently: Node 12, Node 14, Safari 14
|
||||||
|
pending('Environment does not support error cause');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('recursively includes the cause in the stack trace in this environment', function() {
|
it('recursively includes the cause in the stack trace in this environment', function() {
|
||||||
const subject = new jasmineUnderTest.ExceptionFormatter();
|
const subject = new jasmineUnderTest.ExceptionFormatter();
|
||||||
const rootCause = new Error('root cause');
|
const rootCause = new Error('root cause');
|
||||||
|
|||||||
@@ -1,42 +1,56 @@
|
|||||||
describe('GlobalErrors', function() {
|
describe('GlobalErrors', function() {
|
||||||
it('calls the added handler on error', function() {
|
it('calls the added handler on error', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const handler = jasmine.createSpy('errorHandler');
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
|
|
||||||
const error = new Error('nope');
|
fakeGlobal.onerror('foo');
|
||||||
dispatchErrorEvent(fakeGlobal, { error });
|
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(
|
expect(handler).toHaveBeenCalledWith('foo');
|
||||||
jasmine.is(error),
|
|
||||||
jasmine.objectContaining({ error: jasmine.is(error) })
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is not affected by overriding global.onerror', function() {
|
it('enables external interception of error by overriding global.onerror', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const handler = jasmine.createSpy('errorHandler');
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
|
const hijackHandler = jasmine.createSpy('hijackErrorHandler');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
|
|
||||||
fakeGlobal.onerror = () => {};
|
fakeGlobal.onerror = hijackHandler;
|
||||||
|
|
||||||
const error = new Error('nope');
|
fakeGlobal.onerror('foo');
|
||||||
dispatchErrorEvent(fakeGlobal, { error });
|
|
||||||
|
expect(hijackHandler).toHaveBeenCalledWith('foo');
|
||||||
|
expect(handler).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls the global error handler with all parameters', function() {
|
||||||
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
const fooError = new Error('foo');
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
fakeGlobal.onerror(fooError.message, 'foo.js', 1, 1, fooError);
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(
|
expect(handler).toHaveBeenCalledWith(
|
||||||
jasmine.is(error),
|
fooError.message,
|
||||||
jasmine.objectContaining({ error: jasmine.is(error) })
|
'foo.js',
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
fooError
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('only calls the most recent handler', function() {
|
it('only calls the most recent handler', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const handler1 = jasmine.createSpy('errorHandler1');
|
const handler1 = jasmine.createSpy('errorHandler1');
|
||||||
const handler2 = jasmine.createSpy('errorHandler2');
|
const handler2 = jasmine.createSpy('errorHandler2');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
@@ -45,18 +59,14 @@ describe('GlobalErrors', function() {
|
|||||||
errors.pushListener(handler1);
|
errors.pushListener(handler1);
|
||||||
errors.pushListener(handler2);
|
errors.pushListener(handler2);
|
||||||
|
|
||||||
const error = new Error('nope');
|
fakeGlobal.onerror('foo');
|
||||||
dispatchErrorEvent(fakeGlobal, { error });
|
|
||||||
|
|
||||||
expect(handler1).not.toHaveBeenCalled();
|
expect(handler1).not.toHaveBeenCalled();
|
||||||
expect(handler2).toHaveBeenCalledWith(
|
expect(handler2).toHaveBeenCalledWith('foo');
|
||||||
jasmine.is(error),
|
|
||||||
jasmine.objectContaining({ error: jasmine.is(error) })
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls previous handlers when one is removed', function() {
|
it('calls previous handlers when one is removed', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const handler1 = jasmine.createSpy('errorHandler1');
|
const handler1 = jasmine.createSpy('errorHandler1');
|
||||||
const handler2 = jasmine.createSpy('errorHandler2');
|
const handler2 = jasmine.createSpy('errorHandler2');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
@@ -67,13 +77,9 @@ describe('GlobalErrors', function() {
|
|||||||
|
|
||||||
errors.popListener(handler2);
|
errors.popListener(handler2);
|
||||||
|
|
||||||
const error = new Error('nope');
|
fakeGlobal.onerror('foo');
|
||||||
dispatchErrorEvent(fakeGlobal, { error });
|
|
||||||
|
|
||||||
expect(handler1).toHaveBeenCalledWith(
|
expect(handler1).toHaveBeenCalledWith('foo');
|
||||||
jasmine.is(error),
|
|
||||||
jasmine.objectContaining({ error: jasmine.is(error) })
|
|
||||||
);
|
|
||||||
expect(handler2).not.toHaveBeenCalled();
|
expect(handler2).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -84,27 +90,34 @@ describe('GlobalErrors', function() {
|
|||||||
}).toThrowError('popListener expects a listener');
|
}).toThrowError('popListener expects a listener');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uninstalls itself', function() {
|
it('uninstalls itself, putting back a previous callback', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const originalCallback = jasmine.createSpy('error');
|
||||||
|
const fakeGlobal = {
|
||||||
|
...minimalBrowserGlobal(),
|
||||||
|
onerror: originalCallback
|
||||||
|
};
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
function unrelatedListener() {}
|
|
||||||
|
expect(fakeGlobal.onerror).toBe(originalCallback);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
fakeGlobal.addEventListener('error', unrelatedListener);
|
|
||||||
|
expect(fakeGlobal.onerror).not.toBe(originalCallback);
|
||||||
|
|
||||||
errors.uninstall();
|
errors.uninstall();
|
||||||
|
|
||||||
expect(fakeGlobal.listeners_.error).toEqual([unrelatedListener]);
|
expect(fakeGlobal.onerror).toBe(originalCallback);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rethrows the original error when there is no handler', function() {
|
it('rethrows the original error when there is no handler', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
const originalError = new Error('nope');
|
const originalError = new Error('nope');
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dispatchErrorEvent(fakeGlobal, { error: originalError });
|
fakeGlobal.onerror(originalError);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e).toBe(originalError);
|
expect(e).toBe(originalError);
|
||||||
}
|
}
|
||||||
@@ -276,61 +289,128 @@ describe('GlobalErrors', function() {
|
|||||||
|
|
||||||
describe('Reporting unhandled promise rejections in the browser', function() {
|
describe('Reporting unhandled promise rejections in the browser', function() {
|
||||||
it('subscribes and unsubscribes from the unhandledrejection event', function() {
|
it('subscribes and unsubscribes from the unhandledrejection event', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = jasmine.createSpyObj('globalErrors', [
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
'addEventListener',
|
||||||
|
'removeEventListener',
|
||||||
|
'onerror'
|
||||||
|
]),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
expect(fakeGlobal.listeners_.unhandledrejection).toEqual([
|
expect(fakeGlobal.addEventListener).toHaveBeenCalledWith(
|
||||||
|
'unhandledrejection',
|
||||||
jasmine.any(Function)
|
jasmine.any(Function)
|
||||||
]);
|
);
|
||||||
|
|
||||||
|
const addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
|
||||||
errors.uninstall();
|
errors.uninstall();
|
||||||
expect(fakeGlobal.listeners_.unhandledrejection).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports rejections whose reason is a string', function() {
|
expect(fakeGlobal.removeEventListener).toHaveBeenCalledWith(
|
||||||
const fakeGlobal = browserGlobal();
|
'unhandledrejection',
|
||||||
const handler = jasmine.createSpy('errorHandler');
|
addedListener
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
|
||||||
|
|
||||||
errors.install();
|
|
||||||
errors.pushListener(handler);
|
|
||||||
|
|
||||||
const event = { reason: 'nope' };
|
|
||||||
dispatchUnhandledRejectionEvent(fakeGlobal, event);
|
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(
|
|
||||||
'Unhandled promise rejection: nope',
|
|
||||||
event
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports rejections whose reason is an Error', function() {
|
it('reports rejections whose reason is a string', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = jasmine.createSpyObj('globalErrors', [
|
||||||
const handler = jasmine.createSpy('errorHandler');
|
'addEventListener',
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
'removeEventListener',
|
||||||
|
'onerror'
|
||||||
|
]),
|
||||||
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
const addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
|
||||||
|
addedListener({ reason: 'nope' });
|
||||||
|
|
||||||
|
expect(handler).toHaveBeenCalledWith('Unhandled promise rejection: nope');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reports rejections whose reason is an Error', function() {
|
||||||
|
const fakeGlobal = jasmine.createSpyObj('globalErrors', [
|
||||||
|
'addEventListener',
|
||||||
|
'removeEventListener',
|
||||||
|
'onerror'
|
||||||
|
]),
|
||||||
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
const addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
|
||||||
const reason = new Error('bar');
|
const reason = new Error('bar');
|
||||||
const event = { reason };
|
|
||||||
dispatchUnhandledRejectionEvent(fakeGlobal, event);
|
addedListener({ reason: reason });
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(
|
expect(handler).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
||||||
message: reason.message,
|
message: reason.message,
|
||||||
stack: reason.stack
|
stack: reason.stack
|
||||||
}),
|
})
|
||||||
event
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Enabling external interception of reported rejections by overriding global.onerror', function() {
|
||||||
|
it('overriding global.onerror intercepts rejections whose reason is a string', function() {
|
||||||
|
const fakeGlobal = jasmine.createSpyObj('globalErrors', [
|
||||||
|
'addEventListener'
|
||||||
|
]),
|
||||||
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
fakeGlobal.onerror = hijackHandler;
|
||||||
|
|
||||||
|
const addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
|
||||||
|
addedListener({ reason: 'nope' });
|
||||||
|
|
||||||
|
expect(hijackHandler).toHaveBeenCalledWith(
|
||||||
|
'Unhandled promise rejection: nope'
|
||||||
|
);
|
||||||
|
expect(handler).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('overriding global.onerror intercepts rejections whose reason is an Error', function() {
|
||||||
|
const fakeGlobal = jasmine.createSpyObj('globalErrors', [
|
||||||
|
'addEventListener'
|
||||||
|
]),
|
||||||
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
fakeGlobal.onerror = hijackHandler;
|
||||||
|
|
||||||
|
const addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1];
|
||||||
|
const reason = new Error('bar');
|
||||||
|
|
||||||
|
addedListener({ reason: reason });
|
||||||
|
|
||||||
|
expect(hijackHandler).toHaveBeenCalledWith(
|
||||||
|
jasmine.objectContaining({
|
||||||
|
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
||||||
|
message: reason.message,
|
||||||
|
stack: reason.stack
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(handler).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#setOverrideListener', function() {
|
describe('#setOverrideListener', function() {
|
||||||
it('overrides the existing handlers in browsers until removed', function() {
|
it('overrides the existing handlers in browsers until removed', function() {
|
||||||
const fakeGlobal = browserGlobal();
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
const handler0 = jasmine.createSpy('handler0');
|
const handler0 = jasmine.createSpy('handler0');
|
||||||
const handler1 = jasmine.createSpy('handler1');
|
const handler1 = jasmine.createSpy('handler1');
|
||||||
const overrideHandler = jasmine.createSpy('overrideHandler');
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
||||||
@@ -340,18 +420,19 @@ describe('GlobalErrors', function() {
|
|||||||
errors.pushListener(handler0);
|
errors.pushListener(handler0);
|
||||||
errors.setOverrideListener(overrideHandler, () => {});
|
errors.setOverrideListener(overrideHandler, () => {});
|
||||||
errors.pushListener(handler1);
|
errors.pushListener(handler1);
|
||||||
dispatchErrorEvent(fakeGlobal, { error: 'foo' });
|
fakeGlobal.onerror('foo');
|
||||||
|
fakeGlobal.onerror(null, null, null, null, new Error('bar'));
|
||||||
|
|
||||||
expect(overrideHandler).toHaveBeenCalledWith('foo');
|
expect(overrideHandler).toHaveBeenCalledWith('foo');
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('bar'));
|
||||||
expect(handler0).not.toHaveBeenCalled();
|
expect(handler0).not.toHaveBeenCalled();
|
||||||
expect(handler1).not.toHaveBeenCalled();
|
expect(handler1).not.toHaveBeenCalled();
|
||||||
|
|
||||||
errors.removeOverrideListener();
|
errors.removeOverrideListener();
|
||||||
|
|
||||||
const event = { error: 'baz' };
|
fakeGlobal.onerror('baz');
|
||||||
dispatchErrorEvent(fakeGlobal, event);
|
|
||||||
expect(overrideHandler).not.toHaveBeenCalledWith('baz');
|
expect(overrideHandler).not.toHaveBeenCalledWith('baz');
|
||||||
expect(handler1).toHaveBeenCalledWith('baz', event);
|
expect(handler1).toHaveBeenCalledWith('baz');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('overrides the existing handlers in Node until removed', function() {
|
it('overrides the existing handlers in Node until removed', function() {
|
||||||
@@ -451,7 +532,7 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws if there is already an override handler', function() {
|
it('throws if there is already an override handler', function() {
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
|
|
||||||
errors.setOverrideListener(() => {}, () => {});
|
errors.setOverrideListener(() => {}, () => {});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
@@ -463,7 +544,7 @@ describe('GlobalErrors', function() {
|
|||||||
describe('#removeOverrideListener', function() {
|
describe('#removeOverrideListener', function() {
|
||||||
it("calls the handler's onRemove callback", function() {
|
it("calls the handler's onRemove callback", function() {
|
||||||
const onRemove = jasmine.createSpy('onRemove');
|
const onRemove = jasmine.createSpy('onRemove');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
|
|
||||||
errors.setOverrideListener(() => {}, onRemove);
|
errors.setOverrideListener(() => {}, onRemove);
|
||||||
errors.removeOverrideListener();
|
errors.removeOverrideListener();
|
||||||
@@ -472,43 +553,17 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not throw if there is no handler', function() {
|
it('does not throw if there is no handler', function() {
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(browserGlobal());
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
|
|
||||||
expect(() => errors.removeOverrideListener()).not.toThrow();
|
expect(() => errors.removeOverrideListener()).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function browserGlobal() {
|
function minimalBrowserGlobal() {
|
||||||
return {
|
return {
|
||||||
listeners_: { error: [], unhandledrejection: [] },
|
addEventListener() {},
|
||||||
addEventListener(eventName, listener) {
|
removeEventListener() {},
|
||||||
this.listeners_[eventName].push(listener);
|
onerror: null
|
||||||
},
|
|
||||||
removeEventListener(eventName, listener) {
|
|
||||||
this.listeners_[eventName] = this.listeners_[eventName].filter(
|
|
||||||
l => l !== listener
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatchErrorEvent(global, event) {
|
|
||||||
expect(global.listeners_.error.length)
|
|
||||||
.withContext('number of error listeners')
|
|
||||||
.toBeGreaterThan(0);
|
|
||||||
|
|
||||||
for (const l of global.listeners_.error) {
|
|
||||||
l(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dispatchUnhandledRejectionEvent(global, event) {
|
|
||||||
expect(global.listeners_.unhandledrejection.length)
|
|
||||||
.withContext('number of unhandledrejection listeners')
|
|
||||||
.toBeGreaterThan(0);
|
|
||||||
|
|
||||||
for (const l of global.listeners_.unhandledrejection) {
|
|
||||||
l(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
describe('ParallelReportDispatcher', function() {
|
|
||||||
it('dispatches the standard reporter events', async function() {
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
|
||||||
globalErrors: mockGlobalErrors()
|
|
||||||
});
|
|
||||||
const events = [
|
|
||||||
'jasmineStarted',
|
|
||||||
'jasmineDone',
|
|
||||||
'suiteStarted',
|
|
||||||
'suiteDone',
|
|
||||||
'specStarted',
|
|
||||||
'specDone'
|
|
||||||
];
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', events);
|
|
||||||
subject.addReporter(reporter);
|
|
||||||
|
|
||||||
for (const eventName of events) {
|
|
||||||
const payload = { payloadFor: eventName };
|
|
||||||
await subject[eventName](payload);
|
|
||||||
expect(reporter[eventName]).toHaveBeenCalledWith(payload);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installs and uninstalls the global error handler', function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
|
|
||||||
subject.installGlobalErrors();
|
|
||||||
expect(globalErrors.install).toHaveBeenCalled();
|
|
||||||
|
|
||||||
subject.uninstallGlobalErrors();
|
|
||||||
expect(globalErrors.uninstall).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles global errors from async reporters', async function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const onError = jasmine.createSpy('onError');
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'jasmineStarted',
|
|
||||||
'jasmineDone'
|
|
||||||
]);
|
|
||||||
let resolveStarted;
|
|
||||||
reporter.jasmineStarted.and.callFake(function() {
|
|
||||||
return new Promise(function(res) {
|
|
||||||
resolveStarted = res;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
subject.addReporter(reporter);
|
|
||||||
|
|
||||||
const promise = subject.jasmineStarted({});
|
|
||||||
expect(globalErrors.pushListener).toHaveBeenCalled();
|
|
||||||
expect(globalErrors.popListener).not.toHaveBeenCalled();
|
|
||||||
const error = new Error('nope');
|
|
||||||
globalErrors.pushListener.calls.argsFor(0)[0](error);
|
|
||||||
expect(onError).toHaveBeenCalledWith(error);
|
|
||||||
|
|
||||||
resolveStarted();
|
|
||||||
await promise;
|
|
||||||
expect(globalErrors.popListener).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles done(error) from callback-style async reporters', function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const onError = jasmine.createSpy('onError');
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'jasmineStarted',
|
|
||||||
'jasmineDone'
|
|
||||||
]);
|
|
||||||
let callback;
|
|
||||||
reporter.jasmineStarted = function(event, cb) {
|
|
||||||
callback = cb;
|
|
||||||
};
|
|
||||||
subject.addReporter(reporter);
|
|
||||||
|
|
||||||
subject.jasmineStarted({});
|
|
||||||
|
|
||||||
expect(callback).toBeInstanceOf(Function);
|
|
||||||
const error = new Error('nope');
|
|
||||||
callback(error);
|
|
||||||
|
|
||||||
expect(onError).toHaveBeenCalledWith(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles done.fail() from callback-style async reporters', function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const onError = jasmine.createSpy('onError');
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'jasmineStarted',
|
|
||||||
'jasmineDone'
|
|
||||||
]);
|
|
||||||
let callback;
|
|
||||||
reporter.jasmineStarted = function(event, cb) {
|
|
||||||
callback = cb;
|
|
||||||
};
|
|
||||||
subject.addReporter(reporter);
|
|
||||||
|
|
||||||
subject.jasmineStarted({});
|
|
||||||
|
|
||||||
expect(callback).toBeInstanceOf(Function);
|
|
||||||
const error = new Error('nope');
|
|
||||||
callback.fail(error);
|
|
||||||
expect(onError).toHaveBeenCalledWith(error);
|
|
||||||
onError.calls.reset();
|
|
||||||
|
|
||||||
callback.fail();
|
|
||||||
expect(onError).toHaveBeenCalledWith(
|
|
||||||
new Error('A reporter called done.fail()')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles errors due to mixed async style in reporters', async function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const onError = jasmine.createSpy('onError');
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
subject.addReporter({
|
|
||||||
async jasmineStarted(event, done) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await subject.jasmineStarted({});
|
|
||||||
expect(onError).toHaveBeenCalledWith(
|
|
||||||
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.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles errors due to multiple done calls in reporters', async function() {
|
|
||||||
const globalErrors = mockGlobalErrors();
|
|
||||||
const onError = jasmine.createSpy('onError');
|
|
||||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
|
||||||
globalErrors
|
|
||||||
});
|
|
||||||
subject.addReporter({
|
|
||||||
jasmineStarted(event, done) {
|
|
||||||
done();
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await subject.jasmineStarted({});
|
|
||||||
expect(onError).toHaveBeenCalledWith(
|
|
||||||
new Error(
|
|
||||||
"An asynchronous reporter callback called its 'done' callback more than once."
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
function mockGlobalErrors() {
|
|
||||||
const globalErrors = jasmine.createSpyObj('globalErrors', [
|
|
||||||
'install',
|
|
||||||
'pushListener',
|
|
||||||
'popListener'
|
|
||||||
]);
|
|
||||||
|
|
||||||
globalErrors.install.and.callFake(function() {
|
|
||||||
globalErrors.uninstall = jasmine.createSpy('globalErrors.uninstall');
|
|
||||||
});
|
|
||||||
|
|
||||||
return globalErrors;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -185,20 +185,43 @@ describe('QueueRunner', function() {
|
|||||||
|
|
||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not log a deprecation', function(done) {
|
||||||
|
const err = new Error('foo'),
|
||||||
|
queueableFn1 = {
|
||||||
|
fn: function() {
|
||||||
|
return Promise.resolve(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deprecated = jasmine.createSpy('deprecated'),
|
||||||
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||||
|
queueableFns: [queueableFn1],
|
||||||
|
deprecated: deprecated,
|
||||||
|
onComplete: function() {
|
||||||
|
expect(deprecated).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queueRunner.execute();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('and the argument is not an Error', function() {
|
describe('and the argument is not an Error', function() {
|
||||||
it('does not report a failure', function(done) {
|
it('does not log a deprecation or report a failure', function(done) {
|
||||||
const queueableFn1 = {
|
const queueableFn1 = {
|
||||||
fn: function() {
|
fn: function() {
|
||||||
return Promise.resolve('not an error');
|
return Promise.resolve('not an error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
failFn = jasmine.createSpy('fail'),
|
failFn = jasmine.createSpy('fail'),
|
||||||
|
deprecated = jasmine.createSpy('deprecated'),
|
||||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||||
queueableFns: [queueableFn1],
|
queueableFns: [queueableFn1],
|
||||||
|
deprecated: deprecated,
|
||||||
fail: failFn,
|
fail: failFn,
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
|
expect(deprecated).not.toHaveBeenCalled();
|
||||||
expect(failFn).not.toHaveBeenCalled();
|
expect(failFn).not.toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
@@ -383,12 +406,17 @@ describe('QueueRunner', function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
|
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
|
||||||
|
deprecated = jasmine.createSpy('deprecated'),
|
||||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||||
|
deprecated: deprecated,
|
||||||
queueableFns: [queueableFn, nextQueueableFn]
|
queueableFns: [queueableFn, nextQueueableFn]
|
||||||
});
|
});
|
||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
jasmine.clock().tick(1);
|
jasmine.clock().tick(1);
|
||||||
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
||||||
|
// Don't issue a deprecation. The error already tells the user that
|
||||||
|
// something went wrong.
|
||||||
|
expect(deprecated).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a null when you call done', function() {
|
it('should return a null when you call done', function() {
|
||||||
@@ -595,13 +623,11 @@ describe('QueueRunner', function() {
|
|||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
|
|
||||||
expect(onException).toHaveBeenCalledWith(
|
expect(onException).toHaveBeenCalledWith(
|
||||||
new Error(
|
'An asynchronous ' +
|
||||||
'An asynchronous ' +
|
'before/it/after function took a done callback but also returned a ' +
|
||||||
'before/it/after function took a done callback but also returned a ' +
|
'promise. ' +
|
||||||
'promise. ' +
|
'Either remove the done callback (recommended) or change the function ' +
|
||||||
'Either remove the done callback (recommended) or change the function ' +
|
'to not return a promise.'
|
||||||
'to not return a promise.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -617,17 +643,15 @@ describe('QueueRunner', function() {
|
|||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
|
|
||||||
expect(onException).toHaveBeenCalledWith(
|
expect(onException).toHaveBeenCalledWith(
|
||||||
new Error(
|
'An asynchronous ' +
|
||||||
'An asynchronous ' +
|
'before/it/after function was defined with the async keyword but ' +
|
||||||
'before/it/after function was defined with the async keyword but ' +
|
'also took a done callback. Either remove the done callback ' +
|
||||||
'also took a done callback. Either remove the done callback ' +
|
'(recommended) or remove the async keyword.'
|
||||||
'(recommended) or remove the async keyword.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes final errors to exception handlers', function() {
|
it('passes the error instance to exception handlers in HTML browsers', function() {
|
||||||
const error = new Error('fake error'),
|
const error = new Error('fake error'),
|
||||||
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
||||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||||
@@ -635,11 +659,24 @@ describe('QueueRunner', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
queueRunner.handleFinalError(error);
|
queueRunner.handleFinalError(error.message, 'fake.js', 1, 1, error);
|
||||||
|
|
||||||
expect(onExceptionCallback).toHaveBeenCalledWith(error);
|
expect(onExceptionCallback).toHaveBeenCalledWith(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('passes the first argument to exception handlers for compatibility', function() {
|
||||||
|
const error = new Error('fake error'),
|
||||||
|
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
||||||
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||||
|
onException: onExceptionCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
queueRunner.execute();
|
||||||
|
queueRunner.handleFinalError(error.message);
|
||||||
|
|
||||||
|
expect(onExceptionCallback).toHaveBeenCalledWith(error.message);
|
||||||
|
});
|
||||||
|
|
||||||
it('calls exception handlers when an exception is thrown in a fn', function() {
|
it('calls exception handlers when an exception is thrown in a fn', function() {
|
||||||
const queueableFn = {
|
const queueableFn = {
|
||||||
type: 'queueable',
|
type: 'queueable',
|
||||||
|
|||||||
@@ -175,91 +175,4 @@ describe('SuiteBuilder', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('#parallelReset', function() {
|
|
||||||
it('resets the top suite result', function() {
|
|
||||||
jasmineUnderTest.Suite.prototype.handleException.and.callThrough();
|
|
||||||
|
|
||||||
const env = { configuration: () => ({}) };
|
|
||||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
|
||||||
|
|
||||||
suiteBuilder.topSuite.handleException(new Error('nope'));
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
|
|
||||||
expect(suiteBuilder.topSuite.result).toEqual({
|
|
||||||
id: suiteBuilder.topSuite.id,
|
|
||||||
description: 'Jasmine__TopLevel__Suite',
|
|
||||||
fullName: '',
|
|
||||||
failedExpectations: [],
|
|
||||||
deprecationWarnings: [],
|
|
||||||
duration: null,
|
|
||||||
properties: null,
|
|
||||||
parentSuiteId: null,
|
|
||||||
filename: undefined
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes children of the top suite', function() {
|
|
||||||
const env = { configuration: () => ({}) };
|
|
||||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
|
||||||
suiteBuilder.describe('a suite', function() {
|
|
||||||
suiteBuilder.it('a nested spec');
|
|
||||||
});
|
|
||||||
suiteBuilder.it('a spec');
|
|
||||||
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
|
|
||||||
expect(suiteBuilder.topSuite.children).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves top suite befores and afters', function() {
|
|
||||||
const env = { configuration: () => ({}) };
|
|
||||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
|
||||||
|
|
||||||
function beforeAll() {}
|
|
||||||
function beforeEach() {}
|
|
||||||
function afterEach() {}
|
|
||||||
function afterAll() {}
|
|
||||||
|
|
||||||
suiteBuilder.beforeAll(beforeAll);
|
|
||||||
suiteBuilder.beforeEach(beforeEach);
|
|
||||||
suiteBuilder.afterEach(afterEach);
|
|
||||||
suiteBuilder.afterAll(afterAll);
|
|
||||||
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
|
|
||||||
expect(suiteBuilder.topSuite.beforeAllFns).toEqual([
|
|
||||||
jasmine.objectContaining({ fn: beforeAll })
|
|
||||||
]);
|
|
||||||
expect(suiteBuilder.topSuite.beforeFns).toEqual([
|
|
||||||
jasmine.objectContaining({ fn: beforeEach })
|
|
||||||
]);
|
|
||||||
expect(suiteBuilder.topSuite.afterFns).toEqual([
|
|
||||||
jasmine.objectContaining({ fn: afterEach })
|
|
||||||
]);
|
|
||||||
expect(suiteBuilder.topSuite.afterAllFns).toEqual([
|
|
||||||
jasmine.objectContaining({ fn: afterAll })
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resets totalSpecsDefined', function() {
|
|
||||||
const env = { configuration: () => ({}) };
|
|
||||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
|
||||||
suiteBuilder.it('a spec');
|
|
||||||
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
|
|
||||||
expect(suiteBuilder.totalSpecsDefined).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resets focusedRunables', function() {
|
|
||||||
const env = { configuration: () => ({}) };
|
|
||||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
|
||||||
suiteBuilder.fit('a spec', function() {});
|
|
||||||
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
|
|
||||||
expect(suiteBuilder.focusedRunables).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ describe('base helpers', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns a promise that resolves to false when the promise is rejected', function() {
|
it('returns a promise that resolves to false when the promise is rejected', function() {
|
||||||
const promise = Promise.reject(new Error('nope'));
|
const promise = Promise.reject();
|
||||||
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
|
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
describe('Env integration', function() {
|
describe('Env integration', function() {
|
||||||
let env;
|
let env;
|
||||||
const isBrowser = typeof window !== 'undefined';
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
jasmine.getEnv().registerIntegrationMatchers();
|
jasmine.getEnv().registerIntegrationMatchers();
|
||||||
@@ -456,7 +455,7 @@ describe('Env integration', function() {
|
|||||||
env.describe('A suite', function() {
|
env.describe('A suite', function() {
|
||||||
env.it('fails', function(specDone) {
|
env.it('fails', function(specDone) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
dispatchErrorEvent(global, { error: 'fail' });
|
global.onerror('fail');
|
||||||
specDone();
|
specDone();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -510,14 +509,10 @@ describe('Env integration', function() {
|
|||||||
},
|
},
|
||||||
specDone: function() {
|
specDone: function() {
|
||||||
clearStackCallbacks[clearStackCallCount + 1] = function() {
|
clearStackCallbacks[clearStackCallCount + 1] = function() {
|
||||||
dispatchErrorEvent(global, {
|
global.onerror('fail at the end of the reporter queue');
|
||||||
error: 'fail at the end of the reporter queue'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
clearStackCallbacks[clearStackCallCount + 2] = function() {
|
clearStackCallbacks[clearStackCallCount + 2] = function() {
|
||||||
dispatchErrorEvent(global, {
|
global.onerror('fail at the end of the spec queue');
|
||||||
error: 'fail at the end of the spec queue'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -564,7 +559,7 @@ describe('Env integration', function() {
|
|||||||
specDone();
|
specDone();
|
||||||
queueMicrotask(function() {
|
queueMicrotask(function() {
|
||||||
queueMicrotask(function() {
|
queueMicrotask(function() {
|
||||||
dispatchErrorEvent(global, { error: 'fail' });
|
global.onerror('fail');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -627,14 +622,10 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
if (result.description === 'A nested suite') {
|
if (result.description === 'A nested suite') {
|
||||||
clearStackCallbacks[clearStackCallCount + 1] = function() {
|
clearStackCallbacks[clearStackCallCount + 1] = function() {
|
||||||
dispatchErrorEvent(global, {
|
global.onerror('fail at the end of the reporter queue');
|
||||||
error: 'fail at the end of the reporter queue'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
clearStackCallbacks[clearStackCallCount + 2] = function() {
|
clearStackCallbacks[clearStackCallCount + 2] = function() {
|
||||||
dispatchErrorEvent(global, {
|
global.onerror('fail at the end of the suite queue');
|
||||||
error: 'fail at the end of the suite queue'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -677,7 +668,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
env.addReporter({
|
env.addReporter({
|
||||||
jasmineDone: function() {
|
jasmineDone: function() {
|
||||||
dispatchErrorEvent(global, { error: 'a very late error' });
|
global.onerror('a very late error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -729,7 +720,7 @@ describe('Env integration', function() {
|
|||||||
expectedErrors.push(`${msg} thrown`);
|
expectedErrors.push(`${msg} thrown`);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchErrorEvent(global, { error: msg });
|
global.onerror(msg);
|
||||||
realClearStack(fn);
|
realClearStack(fn);
|
||||||
});
|
});
|
||||||
spyOn(console, 'error');
|
spyOn(console, 'error');
|
||||||
@@ -1888,8 +1879,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||||
totalSpecsDefined: 1,
|
totalSpecsDefined: 1,
|
||||||
order: jasmine.any(jasmineUnderTest.Order),
|
order: jasmine.any(jasmineUnderTest.Order)
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
||||||
@@ -1923,8 +1913,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||||
totalSpecsDefined: 1,
|
totalSpecsDefined: 1,
|
||||||
order: jasmine.any(jasmineUnderTest.Order),
|
order: jasmine.any(jasmineUnderTest.Order)
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
||||||
@@ -1978,8 +1967,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||||
totalSpecsDefined: 6,
|
totalSpecsDefined: 6,
|
||||||
order: jasmine.any(jasmineUnderTest.Order),
|
order: jasmine.any(jasmineUnderTest.Order)
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(reporter.specStarted.calls.count()).toBe(6);
|
expect(reporter.specStarted.calls.count()).toBe(6);
|
||||||
@@ -2316,8 +2304,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||||
totalSpecsDefined: 1,
|
totalSpecsDefined: 1,
|
||||||
order: jasmine.any(jasmineUnderTest.Order),
|
order: jasmine.any(jasmineUnderTest.Order)
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
||||||
@@ -2721,24 +2708,15 @@ describe('Env integration', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(2);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('suite'));
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('spec'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
||||||
'async suite',
|
'async suite',
|
||||||
[/Error: suite/]
|
[/^(((Uncaught )?(exception: )?Error: suite( thrown)?)|(suite thrown))$/]
|
||||||
);
|
);
|
||||||
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
||||||
'suite async spec',
|
'suite async spec',
|
||||||
[/Error: spec/]
|
[/^(((Uncaught )?(exception: )?Error: spec( thrown)?)|(spec thrown))$/]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2872,14 +2850,14 @@ describe('Env integration', function() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
dispatchErrorEvent(global, {
|
global.onerror(
|
||||||
message: 'Uncaught SyntaxError: Unexpected end of input',
|
'Uncaught SyntaxError: Unexpected end of input',
|
||||||
error: undefined,
|
'borkenSpec.js',
|
||||||
filename: 'borkenSpec.js',
|
42,
|
||||||
lineno: 42
|
undefined,
|
||||||
});
|
{ stack: 'a stack' }
|
||||||
const error = new Error('ENOCHEESE');
|
);
|
||||||
dispatchErrorEvent(global, { error });
|
global.onerror('Uncaught Error: ENOCHEESE');
|
||||||
|
|
||||||
await env.execute();
|
await env.execute();
|
||||||
|
|
||||||
@@ -2889,15 +2867,15 @@ describe('Env integration', function() {
|
|||||||
passed: false,
|
passed: false,
|
||||||
globalErrorType: 'load',
|
globalErrorType: 'load',
|
||||||
message: 'Uncaught SyntaxError: Unexpected end of input',
|
message: 'Uncaught SyntaxError: Unexpected end of input',
|
||||||
stack: undefined,
|
stack: 'a stack',
|
||||||
filename: 'borkenSpec.js',
|
filename: 'borkenSpec.js',
|
||||||
lineno: 42
|
lineno: 42
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
passed: false,
|
passed: false,
|
||||||
globalErrorType: 'load',
|
globalErrorType: 'load',
|
||||||
message: 'ENOCHEESE',
|
message: 'Uncaught Error: ENOCHEESE',
|
||||||
stack: error.stack,
|
stack: undefined,
|
||||||
filename: undefined,
|
filename: undefined,
|
||||||
lineno: undefined
|
lineno: undefined
|
||||||
}
|
}
|
||||||
@@ -3129,7 +3107,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
env.it('passes', function() {});
|
env.it('passes', function() {});
|
||||||
dispatchErrorEvent(global, { error: 'ENOCHEESE' });
|
global.onerror('Uncaught Error: ENOCHEESE');
|
||||||
await env.execute();
|
await env.execute();
|
||||||
|
|
||||||
expect(reporter.jasmineDone).toHaveBeenCalled();
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
||||||
@@ -3150,7 +3128,6 @@ describe('Env integration', function() {
|
|||||||
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
||||||
expect(e.overallStatus).toEqual('incomplete');
|
expect(e.overallStatus).toEqual('incomplete');
|
||||||
expect(e.incompleteReason).toEqual('No specs found');
|
expect(e.incompleteReason).toEqual('No specs found');
|
||||||
expect(e.incompleteCode).toEqual('noSpecsFound');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3169,7 +3146,6 @@ describe('Env integration', function() {
|
|||||||
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
||||||
expect(e.overallStatus).toEqual('incomplete');
|
expect(e.overallStatus).toEqual('incomplete');
|
||||||
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
||||||
expect(e.incompleteCode).toEqual('focused');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3190,7 +3166,6 @@ describe('Env integration', function() {
|
|||||||
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
||||||
expect(e.overallStatus).toEqual('incomplete');
|
expect(e.overallStatus).toEqual('incomplete');
|
||||||
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
||||||
expect(e.incompleteCode).toEqual('focused');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3211,7 +3186,6 @@ describe('Env integration', function() {
|
|||||||
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
||||||
expect(e.overallStatus).toEqual('failed');
|
expect(e.overallStatus).toEqual('failed');
|
||||||
expect(e.incompleteReason).toBeUndefined();
|
expect(e.incompleteReason).toBeUndefined();
|
||||||
expect(e.incompleteCode).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -3862,6 +3836,16 @@ describe('Env integration', function() {
|
|||||||
expect(failedExpectations).toEqual([]);
|
expect(failedExpectations).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls the optional done callback when finished', function(done) {
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
|
||||||
|
env.execute(null, function() {
|
||||||
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#spyOnGlobalErrorsAsync', function() {
|
describe('#spyOnGlobalErrorsAsync', function() {
|
||||||
const leftInstalledMessage =
|
const leftInstalledMessage =
|
||||||
'Global error spy was not uninstalled. ' +
|
'Global error spy was not uninstalled. ' +
|
||||||
@@ -3902,16 +3886,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(2);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('nope'));
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('yep'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const passingResult = resultForRunable(
|
const passingResult = resultForRunable(
|
||||||
reporter.specDone,
|
reporter.specDone,
|
||||||
@@ -3958,17 +3933,7 @@ describe('Env integration', function() {
|
|||||||
'suiteDone'
|
'suiteDone'
|
||||||
]);
|
]);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(
|
|
||||||
new Error('should fail the spec')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const suiteResult = resultForRunable(reporter.suiteDone, 'Suite 1');
|
const suiteResult = resultForRunable(reporter.suiteDone, 'Suite 1');
|
||||||
expect(suiteResult.status).toEqual('failed');
|
expect(suiteResult.status).toEqual('failed');
|
||||||
@@ -4013,17 +3978,7 @@ describe('Env integration', function() {
|
|||||||
'suiteDone'
|
'suiteDone'
|
||||||
]);
|
]);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(
|
|
||||||
new Error('should fail the spec')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
||||||
'Suite 1',
|
'Suite 1',
|
||||||
@@ -4073,18 +4028,7 @@ describe('Env integration', function() {
|
|||||||
'suiteDone'
|
'suiteDone'
|
||||||
]);
|
]);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(
|
|
||||||
new Error('should fail the spec')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
||||||
expect(spec1Result.status).toEqual('failed');
|
expect(spec1Result.status).toEqual('failed');
|
||||||
@@ -4120,17 +4064,7 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(
|
|
||||||
new Error('should fail the spec')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const spec1Result = resultForRunable(reporter.specDone, 'spec 1');
|
const spec1Result = resultForRunable(reporter.specDone, 'spec 1');
|
||||||
expect(spec1Result.status).toEqual('failed');
|
expect(spec1Result.status).toEqual('failed');
|
||||||
@@ -4175,17 +4109,7 @@ describe('Env integration', function() {
|
|||||||
'suiteDone'
|
'suiteDone'
|
||||||
]);
|
]);
|
||||||
env.addReporter(reporter);
|
env.addReporter(reporter);
|
||||||
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
await env.execute();
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
if (isBrowser) {
|
|
||||||
// Verify that there were no unexpected errors
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(globalErrorSpy).toHaveBeenCalledWith(
|
|
||||||
new Error('should fail the spec')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
||||||
expect(spec1Result.status).toEqual('failed');
|
expect(spec1Result.status).toEqual('failed');
|
||||||
@@ -4334,136 +4258,10 @@ describe('Env integration', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('throwUnless', function() {
|
|
||||||
it('throws when the matcher fails', async function() {
|
|
||||||
let thrown;
|
|
||||||
|
|
||||||
env.it('a spec', function() {
|
|
||||||
try {
|
|
||||||
env.throwUnless(1).toEqual(2);
|
|
||||||
} catch (e) {
|
|
||||||
thrown = e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(thrown).toBeInstanceOf(Error);
|
|
||||||
expect(thrown.passed).toEqual(false);
|
|
||||||
expect(thrown.matcherName).toEqual('toEqual');
|
|
||||||
expect(thrown.message).toEqual('Expected 1 to equal 2.');
|
|
||||||
expect(thrown.actual).toEqual(1);
|
|
||||||
expect(thrown.expected).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when the matcher passes', async function() {
|
|
||||||
let threw = false;
|
|
||||||
|
|
||||||
env.it('a spec', function() {
|
|
||||||
try {
|
|
||||||
env.throwUnless(1).toEqual(1);
|
|
||||||
} catch (e) {
|
|
||||||
threw = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(threw).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
|
||||||
env.it('a spec', function() {
|
|
||||||
try {
|
|
||||||
env.throwUnless(1).toEqual(2);
|
|
||||||
} catch (e) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
||||||
jasmine.objectContaining({ status: 'passed' })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('throwUnlessAsync', function() {
|
|
||||||
it('throws when the matcher fails', async function() {
|
|
||||||
const promise = Promise.resolve('a');
|
|
||||||
let thrown;
|
|
||||||
|
|
||||||
env.it('a spec', async function() {
|
|
||||||
try {
|
|
||||||
await env.throwUnlessAsync(promise).toBeResolvedTo('b');
|
|
||||||
} catch (e) {
|
|
||||||
thrown = e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(thrown).toBeInstanceOf(Error);
|
|
||||||
expect(thrown.passed).toEqual(false);
|
|
||||||
expect(thrown.matcherName).toEqual('toBeResolvedTo');
|
|
||||||
expect(thrown.message).toEqual(
|
|
||||||
"Expected a promise to be resolved to 'b' but it was resolved to 'a'."
|
|
||||||
);
|
|
||||||
expect(thrown.actual).toBe(promise);
|
|
||||||
expect(thrown.expected).toEqual('b');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not throw when the matcher passes', async function() {
|
|
||||||
let threw = false;
|
|
||||||
|
|
||||||
env.it('a spec', async function() {
|
|
||||||
try {
|
|
||||||
await env.throwUnlessAsync(Promise.resolve()).toBeResolved();
|
|
||||||
} catch (e) {
|
|
||||||
threw = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(threw).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
|
||||||
env.it('a spec', async function() {
|
|
||||||
try {
|
|
||||||
await env.throwUnlessAsync(Promise.resolve()).toBeRejected();
|
|
||||||
} catch (e) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
||||||
jasmine.objectContaining({ status: 'passed' })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function browserEventMethods() {
|
function browserEventMethods() {
|
||||||
return {
|
return {
|
||||||
listeners_: { error: [], unhandledrejection: [] },
|
addEventListener() {},
|
||||||
addEventListener(eventName, listener) {
|
removeEventListener() {}
|
||||||
this.listeners_[eventName].push(listener);
|
|
||||||
},
|
|
||||||
removeEventListener(eventName, listener) {
|
|
||||||
this.listeners_[eventName] = this.listeners_[eventName].filter(
|
|
||||||
l => l !== listener
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatchErrorEvent(global, event) {
|
|
||||||
expect(global.listeners_.error.length)
|
|
||||||
.withContext('number of error listeners')
|
|
||||||
.toBeGreaterThan(0);
|
|
||||||
|
|
||||||
for (const l of global.listeners_.error) {
|
|
||||||
l(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ describe('Matchers (Integration)', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
verifyFailsAsync(function(env) {
|
verifyFailsAsync(function(env) {
|
||||||
return env.expectAsync(Promise.reject(new Error('nope'))).toBeResolved();
|
return env.expectAsync(Promise.reject()).toBeResolved();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
describe('Support for parallel execution', function() {
|
|
||||||
let env;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
env = new jasmineUnderTest.Env();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
env.cleanup_();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes specs and suites from previous batches', async function() {
|
|
||||||
env.describe('a suite', function() {
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
});
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
env.parallelReset();
|
|
||||||
|
|
||||||
env.describe('a suite in a new batch', function() {
|
|
||||||
env.it('a spec in a new batch', function() {});
|
|
||||||
});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'suiteDone',
|
|
||||||
'specDone'
|
|
||||||
]);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
fullName: 'a suite in a new batch'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledOnceWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
fullName: 'a suite in a new batch a spec in a new batch'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves top-level before and after fns from previous batches', async function() {
|
|
||||||
const beforeAll = jasmine.createSpy('beforeAll');
|
|
||||||
const beforeEach = jasmine.createSpy('beforeEach');
|
|
||||||
const afterEach = jasmine.createSpy('afterEach');
|
|
||||||
const afterAll = jasmine.createSpy('afterAll');
|
|
||||||
env.beforeAll(beforeAll);
|
|
||||||
env.beforeEach(beforeEach);
|
|
||||||
env.afterEach(afterEach);
|
|
||||||
env.afterAll(afterAll);
|
|
||||||
|
|
||||||
env.parallelReset();
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(beforeAll).toHaveBeenCalled();
|
|
||||||
expect(beforeEach).toHaveBeenCalled();
|
|
||||||
expect(afterEach).toHaveBeenCalled();
|
|
||||||
expect(afterAll).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not remember focused runables from previous batches', async function() {
|
|
||||||
env.fit('a focused spec', function() {});
|
|
||||||
env.parallelReset();
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'specDone',
|
|
||||||
'jasmineDone'
|
|
||||||
]);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.specDone).toHaveBeenCalledOnceWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
fullName: 'a spec',
|
|
||||||
status: 'passed'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(reporter.jasmineDone).toHaveBeenCalledWith(
|
|
||||||
jasmine.objectContaining({ overallStatus: 'passed' })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not remember failures from previous batches', async function() {
|
|
||||||
env.it('a failing spec', function() {
|
|
||||||
env.expect(true).toBe(false);
|
|
||||||
});
|
|
||||||
await env.execute();
|
|
||||||
env.parallelReset();
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', [
|
|
||||||
'specDone',
|
|
||||||
'jasmineDone'
|
|
||||||
]);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.jasmineDone).toHaveBeenCalledWith(
|
|
||||||
jasmine.objectContaining({ overallStatus: 'passed' })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports errors thrown from describe', async function() {
|
|
||||||
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
|
|
||||||
env.addReporter(reporter);
|
|
||||||
|
|
||||||
env.describe('borken', function() {
|
|
||||||
throw new Error('nope');
|
|
||||||
});
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
description: 'borken',
|
|
||||||
status: 'failed',
|
|
||||||
failedExpectations: [
|
|
||||||
jasmine.objectContaining({
|
|
||||||
message: jasmine.stringContaining('Error: nope')
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Errors in subsequent suites should also be reported
|
|
||||||
reporter.suiteDone.calls.reset();
|
|
||||||
env.parallelReset();
|
|
||||||
env.describe('zarro boogs', function() {
|
|
||||||
throw new Error('nor that either');
|
|
||||||
});
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
description: 'zarro boogs',
|
|
||||||
status: 'failed',
|
|
||||||
failedExpectations: [
|
|
||||||
jasmine.objectContaining({
|
|
||||||
message: jasmine.stringContaining('Error: nor that either')
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Failure state should not persist across resets
|
|
||||||
reporter.suiteDone.calls.reset();
|
|
||||||
env.parallelReset();
|
|
||||||
env.describe('actually works', function() {
|
|
||||||
env.it('a spec', function() {});
|
|
||||||
});
|
|
||||||
await env.execute();
|
|
||||||
|
|
||||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
|
||||||
jasmine.objectContaining({
|
|
||||||
description: 'actually works',
|
|
||||||
status: 'passed',
|
|
||||||
failedExpectations: []
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -626,7 +626,7 @@ describe('spec running', function() {
|
|||||||
expect(actions).toEqual(['spec2', 'spec3', 'spec1']);
|
expect(actions).toEqual(['spec2', 'spec3', 'spec1']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('refuses to re-enter suites with a beforeAll', async function() {
|
it('refuses to re-enter suites with a beforeAll', function() {
|
||||||
const actions = [];
|
const actions = [];
|
||||||
let spec1;
|
let spec1;
|
||||||
let spec2;
|
let spec2;
|
||||||
@@ -648,12 +648,13 @@ describe('spec running', function() {
|
|||||||
actions.push('spec3');
|
actions.push('spec3');
|
||||||
});
|
});
|
||||||
|
|
||||||
const promise = env.execute([spec2.id, spec3.id, spec1.id]);
|
expect(function() {
|
||||||
await expectAsync(promise).toBeRejectedWithError(/beforeAll/);
|
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||||
|
}).toThrowError(/beforeAll/);
|
||||||
expect(actions).toEqual([]);
|
expect(actions).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('refuses to re-enter suites with a afterAll', async function() {
|
it('refuses to re-enter suites with a afterAll', function() {
|
||||||
const actions = [];
|
const actions = [];
|
||||||
let spec1;
|
let spec1;
|
||||||
let spec2;
|
let spec2;
|
||||||
@@ -675,8 +676,9 @@ describe('spec running', function() {
|
|||||||
actions.push('spec3');
|
actions.push('spec3');
|
||||||
});
|
});
|
||||||
|
|
||||||
const promise = env.execute([spec2.id, spec3.id, spec1.id]);
|
expect(function() {
|
||||||
await expectAsync(promise).toBeRejectedWithError(/afterAll/);
|
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||||
|
}).toThrowError(/afterAll/);
|
||||||
expect(actions).toEqual([]);
|
expect(actions).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -78,10 +78,15 @@ describe('npm package', function() {
|
|||||||
|
|
||||||
it('has bootFiles', function() {
|
it('has bootFiles', function() {
|
||||||
expect(this.packagedCore.files.bootFiles).toEqual(['boot0.js', 'boot1.js']);
|
expect(this.packagedCore.files.bootFiles).toEqual(['boot0.js', 'boot1.js']);
|
||||||
|
expect(this.packagedCore.files.nodeBootFiles).toEqual(['node_boot.js']);
|
||||||
|
|
||||||
for (const fileName of this.packagedCore.files.bootFiles) {
|
for (const fileName of this.packagedCore.files.bootFiles) {
|
||||||
expect(fileName).toExistInPath(this.packagedCore.files.bootDir);
|
expect(fileName).toExistInPath(this.packagedCore.files.bootDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const fileName of this.packagedCore.files.nodeBootFiles) {
|
||||||
|
expect(fileName).toExistInPath(this.packagedCore.files.bootDir);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has an imagesDir', function() {
|
it('has an imagesDir', function() {
|
||||||
|
|||||||
@@ -28,19 +28,16 @@ module.exports = {
|
|||||||
random: true,
|
random: true,
|
||||||
browser: {
|
browser: {
|
||||||
name: process.env.JASMINE_BROWSER || 'firefox',
|
name: process.env.JASMINE_BROWSER || 'firefox',
|
||||||
useRemoteSeleniumGrid: process.env.USE_SAUCE === 'true',
|
useSauce: process.env.USE_SAUCE === 'true',
|
||||||
remoteSeleniumGrid: {
|
sauce: {
|
||||||
url: 'https://ondemand.saucelabs.com/wd/hub',
|
name: `jasmine-core ${new Date().toISOString()}`,
|
||||||
|
os: process.env.SAUCE_OS,
|
||||||
browserVersion: process.env.SAUCE_BROWSER_VERSION,
|
browserVersion: process.env.SAUCE_BROWSER_VERSION,
|
||||||
platformName: process.env.SAUCE_OS,
|
build: `Core ${process.env.TRAVIS_BUILD_NUMBER || 'Ran locally'}`,
|
||||||
'sauce:options': {
|
tags: ['Jasmine-Core'],
|
||||||
name: `jasmine-core ${new Date().toISOString()}`,
|
tunnelIdentifier: process.env.SAUCE_TUNNEL_IDENTIFIER,
|
||||||
build: `Core ${process.env.CIRCLE_BUILD_NUM || 'Ran locally'}`,
|
username: process.env.SAUCE_USERNAME,
|
||||||
tags: ['Jasmine-Core'],
|
accessKey: process.env.SAUCE_ACCESS_KEY
|
||||||
tunnelIdentifier: process.env.SAUCE_TUNNEL_IDENTIFIER,
|
|
||||||
username: process.env.SAUCE_USERNAME,
|
|
||||||
accessKey: process.env.SAUCE_ACCESS_KEY
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
16
src/boot/node_boot.js
Normal file
16
src/boot/node_boot.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module.exports = function(jasmineRequire) {
|
||||||
|
const jasmine = jasmineRequire.core(jasmineRequire);
|
||||||
|
|
||||||
|
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||||
|
|
||||||
|
const jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||||
|
|
||||||
|
extend(global, jasmineInterface);
|
||||||
|
|
||||||
|
function extend(destination, source) {
|
||||||
|
for (const property in source) destination[property] = source[property];
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jasmine;
|
||||||
|
};
|
||||||
262
src/core/Env.js
262
src/core/Env.js
@@ -46,7 +46,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
let reporter;
|
let reporter;
|
||||||
let topSuite;
|
let topSuite;
|
||||||
let runner;
|
let runner;
|
||||||
let parallelLoadingState = null; // 'specs', 'helpers', or null for non-parallel
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents the available options to configure Jasmine.
|
* This represents the available options to configure Jasmine.
|
||||||
@@ -75,10 +74,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
seed: null,
|
seed: null,
|
||||||
/**
|
/**
|
||||||
* Whether to stop execution of the suite after the first spec failure
|
* Whether to stop execution of the suite after the first spec failure
|
||||||
*
|
|
||||||
* <p>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.</p>
|
|
||||||
* @name Configuration#stopOnSpecFailure
|
* @name Configuration#stopOnSpecFailure
|
||||||
* @since 3.9.0
|
* @since 3.9.0
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
@@ -154,14 +149,20 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
if (!options.suppressLoadErrors) {
|
if (!options.suppressLoadErrors) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
globalErrors.pushListener(function loadtimeErrorHandler(error, event) {
|
globalErrors.pushListener(function loadtimeErrorHandler(
|
||||||
|
message,
|
||||||
|
filename,
|
||||||
|
lineno,
|
||||||
|
colNo,
|
||||||
|
err
|
||||||
|
) {
|
||||||
topSuite.result.failedExpectations.push({
|
topSuite.result.failedExpectations.push({
|
||||||
passed: false,
|
passed: false,
|
||||||
globalErrorType: 'load',
|
globalErrorType: 'load',
|
||||||
message: error ? error.message : event.message,
|
message: message,
|
||||||
stack: error && error.stack,
|
stack: err && err.stack,
|
||||||
filename: event && event.filename,
|
filename: filename,
|
||||||
lineno: event && event.lineno
|
lineno: lineno
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -174,12 +175,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
this.configure = function(configuration) {
|
this.configure = function(configuration) {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error(
|
|
||||||
'Jasmine cannot be configured via Env in parallel mode'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const booleanProps = [
|
const booleanProps = [
|
||||||
'random',
|
'random',
|
||||||
'failSpecWithNoExpectations',
|
'failSpecWithNoExpectations',
|
||||||
@@ -264,49 +259,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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 Expectation} 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.
|
|
||||||
* @property {Boolean} passed - Whether the expectation passed or failed.
|
|
||||||
* @property {Object} expected - If the expectation failed, what was the expected value.
|
|
||||||
* @property {Object} actual - If the expectation failed, what actual value was produced.
|
|
||||||
*/
|
|
||||||
const error = new Error(result.message);
|
|
||||||
error.passed = result.passed;
|
|
||||||
error.message = result.message;
|
|
||||||
error.expected = result.expected;
|
|
||||||
error.actual = result.actual;
|
|
||||||
error.matcherName = result.matcherName;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const throwUnlessFactory = function(actual, spec) {
|
|
||||||
return j$.Expectation.factory({
|
|
||||||
matchersUtil: runableResources.makeMatchersUtil(),
|
|
||||||
customMatchers: runableResources.customMatchers(),
|
|
||||||
actual: actual,
|
|
||||||
addExpectationResult: handleThrowUnlessFailure
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const throwUnlessAsyncFactory = function(actual, spec) {
|
|
||||||
return j$.Expectation.asyncFactory({
|
|
||||||
matchersUtil: runableResources.makeMatchersUtil(),
|
|
||||||
customAsyncMatchers: runableResources.customAsyncMatchers(),
|
|
||||||
actual: actual,
|
|
||||||
addExpectationResult: handleThrowUnlessFailure
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
||||||
// diagnostic info added by the latter is probably useful in most cases.
|
// diagnostic info added by the latter is probably useful in most cases.
|
||||||
function recordLateError(error) {
|
function recordLateError(error) {
|
||||||
@@ -428,6 +380,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function(e) {
|
function(e) {
|
||||||
(runner.currentRunable() || topSuite).handleException(e);
|
(runner.currentRunable() || topSuite).handleException(e);
|
||||||
};
|
};
|
||||||
|
options.deprecated = self.deprecated;
|
||||||
|
|
||||||
new j$.QueueRunner(options).execute();
|
new j$.QueueRunner(options).execute();
|
||||||
}
|
}
|
||||||
@@ -453,7 +406,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
this.topSuite = function() {
|
this.topSuite = function() {
|
||||||
ensureNonParallel('topSuite');
|
|
||||||
return topSuite.metadata;
|
return topSuite.metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -463,7 +415,72 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
reporter = new j$.ReportDispatcher(
|
reporter = new j$.ReportDispatcher(
|
||||||
j$.reporterEvents,
|
[
|
||||||
|
/**
|
||||||
|
* `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 {SuiteResult} 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 {SuiteResult} 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 {SpecResult} 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 {SpecResult} 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'
|
||||||
|
],
|
||||||
function(options) {
|
function(options) {
|
||||||
options.SkipPolicy = j$.NeverSkipPolicy;
|
options.SkipPolicy = j$.NeverSkipPolicy;
|
||||||
return queueRunnerFactory(options);
|
return queueRunnerFactory(options);
|
||||||
@@ -482,24 +499,21 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
reportSpecDone
|
reportSpecDone
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setParallelLoadingState = function(state) {
|
|
||||||
parallelLoadingState = state;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.parallelReset = function() {
|
|
||||||
suiteBuilder.parallelReset();
|
|
||||||
runner.parallelReset();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the specs.
|
* Executes the specs.
|
||||||
*
|
*
|
||||||
* If called with no parameter or with a falsy parameter,
|
* If called with no parameters or with a falsy value as the first parameter,
|
||||||
* all specs will be executed except those that are excluded by a
|
* all specs will be executed except those that are excluded by a
|
||||||
* [spec filter]{@link Configuration#specFilter} or other mechanism. If the
|
* [spec filter]{@link Configuration#specFilter} or other mechanism. If the
|
||||||
* parameter is a list of spec/suite IDs, only those specs/suites will
|
* first parameter is a list of spec/suite IDs, only those specs/suites will
|
||||||
* be run.
|
* be run.
|
||||||
*
|
*
|
||||||
|
* Both parameters are optional, but a completion callback is only valid as
|
||||||
|
* the second parameter. To specify a completion callback but not a list of
|
||||||
|
* specs/suites to run, pass null or undefined as the first parameter. The
|
||||||
|
* completion callback is supported for backward compatibility. In most
|
||||||
|
* cases it will be more convenient to use the returned promise instead.
|
||||||
|
*
|
||||||
* execute should not be called more than once unless the env has been
|
* execute should not be called more than once unless the env has been
|
||||||
* configured with `{autoCleanClosures: false}`.
|
* configured with `{autoCleanClosures: false}`.
|
||||||
*
|
*
|
||||||
@@ -507,26 +521,25 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* {@link JasmineDoneInfo|overall result} that's passed to a reporter's
|
* {@link JasmineDoneInfo|overall result} that's passed to a reporter's
|
||||||
* `jasmineDone` method, even if the suite did not pass. To determine
|
* `jasmineDone` method, even if the suite did not pass. To determine
|
||||||
* whether the suite passed, check the value that the promise resolves to
|
* 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
|
* or use a {@link Reporter}.
|
||||||
* certain serious errors that prevent execution from starting.
|
|
||||||
*
|
*
|
||||||
* @name Env#execute
|
* @name Env#execute
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
* @function
|
* @function
|
||||||
* @async
|
|
||||||
* @param {(string[])=} runablesToRun IDs of suites and/or specs to run
|
* @param {(string[])=} runablesToRun IDs of suites and/or specs to run
|
||||||
|
* @param {Function=} onComplete Function that will be called after all specs have run
|
||||||
* @return {Promise<JasmineDoneInfo>}
|
* @return {Promise<JasmineDoneInfo>}
|
||||||
*/
|
*/
|
||||||
this.execute = async function(runablesToRun) {
|
this.execute = function(runablesToRun, onComplete) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
|
|
||||||
if (parallelLoadingState) {
|
return runner.execute(runablesToRun).then(function(jasmineDoneInfo) {
|
||||||
validateConfigForParallel();
|
if (onComplete) {
|
||||||
}
|
onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
const result = await runner.execute(runablesToRun);
|
return jasmineDoneInfo;
|
||||||
this.cleanup_();
|
});
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -538,10 +551,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
this.addReporter = function(reporterToAdd) {
|
this.addReporter = function(reporterToAdd) {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error('Reporters cannot be added via Env in parallel mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter.addReporter(reporterToAdd);
|
reporter.addReporter(reporterToAdd);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -564,10 +573,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
this.clearReporters = function() {
|
this.clearReporters = function() {
|
||||||
if (parallelLoadingState) {
|
|
||||||
throw new Error('Reporters cannot be removed via Env in parallel mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter.clearReporters();
|
reporter.clearReporters();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -667,38 +672,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
this.describe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('describe');
|
ensureIsNotNested('describe');
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
@@ -715,7 +688,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.fdescribe = function(description, definitionFn) {
|
this.fdescribe = function(description, definitionFn) {
|
||||||
ensureIsNotNested('fdescribe');
|
ensureIsNotNested('fdescribe');
|
||||||
ensureNonParallel('fdescribe');
|
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
return suiteBuilder.fdescribe(description, definitionFn, filename)
|
||||||
.metadata;
|
.metadata;
|
||||||
@@ -757,7 +729,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
this.fit = function(description, fn, timeout) {
|
this.fit = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('fit');
|
ensureIsNotNested('fit');
|
||||||
ensureNonParallel('fit');
|
|
||||||
const filename = callerCallerFilename();
|
const filename = callerCallerFilename();
|
||||||
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
return suiteBuilder.fit(description, fn, timeout, filename).metadata;
|
||||||
};
|
};
|
||||||
@@ -810,72 +781,42 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.expect = function(actual) {
|
this.expect = function(actual) {
|
||||||
const runable = runner.currentRunable();
|
if (!runner.currentRunable()) {
|
||||||
|
|
||||||
if (!runable) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runable.expectationFactory(actual, runable);
|
return runner.currentRunable().expect(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.expectAsync = function(actual) {
|
this.expectAsync = function(actual) {
|
||||||
const runable = runner.currentRunable();
|
if (!runner.currentRunable()) {
|
||||||
|
|
||||||
if (!runable) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runable.asyncExpectationFactory(actual, runable);
|
return runner.currentRunable().expectAsync(actual);
|
||||||
};
|
|
||||||
|
|
||||||
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) {
|
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||||
ensureIsNotNested('beforeEach');
|
ensureIsNotNested('beforeEach');
|
||||||
ensureNonParallelOrInHelperOrInDescribe('beforeEach');
|
|
||||||
suiteBuilder.beforeEach(beforeEachFunction, timeout);
|
suiteBuilder.beforeEach(beforeEachFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.beforeAll = function(beforeAllFunction, timeout) {
|
this.beforeAll = function(beforeAllFunction, timeout) {
|
||||||
ensureIsNotNested('beforeAll');
|
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);
|
suiteBuilder.beforeAll(beforeAllFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.afterEach = function(afterEachFunction, timeout) {
|
this.afterEach = function(afterEachFunction, timeout) {
|
||||||
ensureIsNotNested('afterEach');
|
ensureIsNotNested('afterEach');
|
||||||
ensureNonParallelOrInHelperOrInDescribe('afterEach');
|
|
||||||
suiteBuilder.afterEach(afterEachFunction, timeout);
|
suiteBuilder.afterEach(afterEachFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.afterAll = function(afterAllFunction, timeout) {
|
this.afterAll = function(afterAllFunction, timeout) {
|
||||||
ensureIsNotNested('afterAll');
|
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);
|
suiteBuilder.afterAll(afterAllFunction, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -930,10 +871,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function callerCallerFilename() {
|
function callerCallerFilename() {
|
||||||
const frames = new j$.StackTrace(new Error()).frames;
|
return new j$.StackTrace(new Error()).frames[3].file;
|
||||||
// frames[3] should always exist except in Jasmine's own tests, which bypass
|
|
||||||
// the global it/describe layer, but don't crash if it doesn't.
|
|
||||||
return frames[3] && frames[3].file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Env;
|
return Env;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
|||||||
const result = {};
|
const result = {};
|
||||||
let empty = true;
|
let empty = true;
|
||||||
|
|
||||||
for (const prop of Object.keys(error)) {
|
for (const prop in error) {
|
||||||
if (ignoredProperties.includes(prop)) {
|
if (ignoredProperties.includes(prop)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,18 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
let overrideHandler = null,
|
let overrideHandler = null,
|
||||||
onRemoveOverrideHandler = null;
|
onRemoveOverrideHandler = null;
|
||||||
|
|
||||||
function onBrowserError(event) {
|
function onerror(message, source, lineno, colno, error) {
|
||||||
dispatchBrowserError(event.error, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dispatchBrowserError(error, event) {
|
|
||||||
if (overrideHandler) {
|
if (overrideHandler) {
|
||||||
overrideHandler(error);
|
overrideHandler(error || message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(error, event);
|
handler.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw arguments[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +94,8 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
this.installOne_('uncaughtException', 'Uncaught exception');
|
this.installOne_('uncaughtException', 'Uncaught exception');
|
||||||
this.installOne_('unhandledRejection', 'Unhandled promise rejection');
|
this.installOne_('unhandledRejection', 'Unhandled promise rejection');
|
||||||
} else {
|
} else {
|
||||||
global.addEventListener('error', onBrowserError);
|
const originalHandler = global.onerror;
|
||||||
|
global.onerror = onerror;
|
||||||
|
|
||||||
const browserRejectionHandler = function browserRejectionHandler(
|
const browserRejectionHandler = function browserRejectionHandler(
|
||||||
event
|
event
|
||||||
@@ -106,19 +103,16 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
if (j$.isError_(event.reason)) {
|
if (j$.isError_(event.reason)) {
|
||||||
event.reason.jasmineMessage =
|
event.reason.jasmineMessage =
|
||||||
'Unhandled promise rejection: ' + event.reason;
|
'Unhandled promise rejection: ' + event.reason;
|
||||||
dispatchBrowserError(event.reason, event);
|
global.onerror(event.reason);
|
||||||
} else {
|
} else {
|
||||||
dispatchBrowserError(
|
global.onerror('Unhandled promise rejection: ' + event.reason);
|
||||||
'Unhandled promise rejection: ' + event.reason,
|
|
||||||
event
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
||||||
|
|
||||||
this.uninstall = function uninstall() {
|
this.uninstall = function uninstall() {
|
||||||
global.removeEventListener('error', onBrowserError);
|
global.onerror = originalHandler;
|
||||||
global.removeEventListener(
|
global.removeEventListener(
|
||||||
'unhandledrejection',
|
'unhandledrejection',
|
||||||
browserRejectionHandler
|
browserRejectionHandler
|
||||||
@@ -127,13 +121,6 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The listener at the top of the stack will be called with two arguments:
|
|
||||||
// the error and the event. Either of them may be falsy.
|
|
||||||
// The error will normally be provided, but will be falsy in the case of
|
|
||||||
// some browser load-time errors. The event will normally be provided in
|
|
||||||
// browsers but will be falsy in Node.
|
|
||||||
// Listeners that are pushed after spec files have been loaded should be
|
|
||||||
// able to just use the error parameter.
|
|
||||||
this.pushListener = function pushListener(listener) {
|
this.pushListener = function pushListener(listener) {
|
||||||
handlers.push(listener);
|
handlers.push(listener);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
|
||||||
/**
|
|
||||||
* @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$.ReportDispatcher;
|
|
||||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
|
||||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
|
||||||
const dispatcher = ReportDispatcher(
|
|
||||||
j$.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$.reporterEvents) {
|
|
||||||
self[eventName] = dispatcher[eventName].bind(dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ParallelReportDispatcher;
|
|
||||||
};
|
|
||||||
@@ -62,11 +62,15 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
if (typeof this.onComplete !== 'function') {
|
if (typeof this.onComplete !== 'function') {
|
||||||
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
|
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
|
||||||
}
|
}
|
||||||
|
this.deprecated = attrs.deprecated;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueRunner.prototype.execute = function() {
|
QueueRunner.prototype.execute = function() {
|
||||||
this.handleFinalError = error => {
|
this.handleFinalError = (message, source, lineno, colno, error) => {
|
||||||
this.onException(error);
|
// Older browsers would send the error as the first parameter. HTML5
|
||||||
|
// specifies the the five parameters above. The error instance should
|
||||||
|
// be preffered, otherwise the call stack would get lost.
|
||||||
|
this.onException(error || message);
|
||||||
};
|
};
|
||||||
this.globalErrors.pushListener(this.handleFinalError);
|
this.globalErrors.pushListener(this.handleFinalError);
|
||||||
this.run(0);
|
this.run(0);
|
||||||
@@ -255,21 +259,17 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
// on the stack at this point.
|
// on the stack at this point.
|
||||||
if (j$.isAsyncFunction_(fn)) {
|
if (j$.isAsyncFunction_(fn)) {
|
||||||
this.onException(
|
this.onException(
|
||||||
new Error(
|
'An asynchronous before/it/after ' +
|
||||||
'An asynchronous before/it/after ' +
|
'function was defined with the async keyword but also took a ' +
|
||||||
'function was defined with the async keyword but also took a ' +
|
'done callback. Either remove the done callback (recommended) or ' +
|
||||||
'done callback. Either remove the done callback (recommended) or ' +
|
'remove the async keyword.'
|
||||||
'remove the async keyword.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.onException(
|
this.onException(
|
||||||
new Error(
|
'An asynchronous before/it/after ' +
|
||||||
'An asynchronous before/it/after ' +
|
'function took a done callback but also returned a promise. ' +
|
||||||
'function took a done callback but also returned a promise. ' +
|
'Either remove the done callback (recommended) or change the ' +
|
||||||
'Either remove the done callback (recommended) or change the ' +
|
'function to not return a promise.'
|
||||||
'function to not return a promise.'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
class Runner {
|
class Runner {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.topSuite_ = options.topSuite;
|
this.topSuite_ = options.topSuite;
|
||||||
// TODO use names that read like getters
|
|
||||||
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
||||||
this.focusedRunables_ = options.focusedRunables;
|
this.focusedRunables_ = options.focusedRunables;
|
||||||
this.runableResources_ = options.runableResources;
|
this.runableResources_ = options.runableResources;
|
||||||
@@ -27,11 +26,11 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
parallelReset() {
|
// Although execute returns a promise, it isn't async for backwards
|
||||||
this.executedBefore_ = false;
|
// compatibility: The "Invalid order" exception needs to be propagated
|
||||||
}
|
// synchronously from Env#execute.
|
||||||
|
// TODO: make this and Env#execute async in the next major release
|
||||||
async execute(runablesToRun) {
|
execute(runablesToRun) {
|
||||||
if (this.executedBefore_) {
|
if (this.executedBefore_) {
|
||||||
this.topSuite_.reset();
|
this.topSuite_.reset();
|
||||||
}
|
}
|
||||||
@@ -127,17 +126,13 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
/**
|
/**
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
* @typedef JasmineStartedInfo
|
* @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} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
* @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 {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
* @property {Boolean} parallel - Whether Jasmine is being run in parallel mode.
|
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
await this.reporter_.jasmineStarted({
|
await this.reporter_.jasmineStarted({
|
||||||
// In parallel mode, the jasmineStarted event is separately dispatched
|
|
||||||
// by jasmine-npm. This event only reaches reporters in non-parallel.
|
|
||||||
totalSpecsDefined,
|
totalSpecsDefined,
|
||||||
order: order,
|
order: order
|
||||||
parallel: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.currentlyExecutingSuites_.push(this.topSuite_);
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
@@ -149,7 +144,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
|
|
||||||
this.runableResources_.clearForRunable(this.topSuite_.id);
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
this.currentlyExecutingSuites_.pop();
|
this.currentlyExecutingSuites_.pop();
|
||||||
let overallStatus, incompleteReason, incompleteCode;
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.hasFailures ||
|
this.hasFailures ||
|
||||||
@@ -159,11 +154,9 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
} else if (this.focusedRunables_().length > 0) {
|
} else if (this.focusedRunables_().length > 0) {
|
||||||
overallStatus = 'incomplete';
|
overallStatus = 'incomplete';
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
incompleteCode = 'focused';
|
|
||||||
} else if (totalSpecsDefined === 0) {
|
} else if (totalSpecsDefined === 0) {
|
||||||
overallStatus = 'incomplete';
|
overallStatus = 'incomplete';
|
||||||
incompleteReason = 'No specs found';
|
incompleteReason = 'No specs found';
|
||||||
incompleteCode = 'noSpecsFound';
|
|
||||||
} else {
|
} else {
|
||||||
overallStatus = 'passed';
|
overallStatus = 'passed';
|
||||||
}
|
}
|
||||||
@@ -173,10 +166,8 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
* @typedef JasmineDoneInfo
|
* @typedef JasmineDoneInfo
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
* @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 {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 {IncompleteReason} incompleteReason - 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.
|
||||||
* @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 {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
||||||
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
||||||
* @since 2.4.0
|
* @since 2.4.0
|
||||||
@@ -185,7 +176,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
overallStatus: overallStatus,
|
overallStatus: overallStatus,
|
||||||
totalTime: jasmineTimer.elapsed(),
|
totalTime: jasmineTimer.elapsed(),
|
||||||
incompleteReason: incompleteReason,
|
incompleteReason: incompleteReason,
|
||||||
incompleteCode: incompleteCode,
|
|
||||||
order: order,
|
order: order,
|
||||||
failedExpectations: this.topSuite_.result.failedExpectations,
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
this.result.properties[key] = value;
|
this.result.properties[key] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Spec.prototype.expect = function(actual) {
|
||||||
|
return this.expectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Spec.prototype.expectAsync = function(actual) {
|
||||||
|
return this.asyncExpectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
Spec.prototype.execute = function(
|
Spec.prototype.execute = function(
|
||||||
queueRunnerFactory,
|
queueRunnerFactory,
|
||||||
onComplete,
|
onComplete,
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.result.properties[key] = value;
|
this.result.properties[key] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Suite.prototype.expect = function(actual) {
|
||||||
|
return this.expectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Suite.prototype.expectAsync = function(actual) {
|
||||||
|
return this.asyncExpectationFactory(actual, this);
|
||||||
|
};
|
||||||
|
|
||||||
Suite.prototype.getFullName = function() {
|
Suite.prototype.getFullName = function() {
|
||||||
const fullName = [];
|
const fullName = [];
|
||||||
for (
|
for (
|
||||||
@@ -130,10 +138,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.reportedDone = false;
|
this.reportedDone = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Suite.prototype.removeChildren = function() {
|
|
||||||
this.children = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
Suite.prototype.addChild = function(child) {
|
Suite.prototype.addChild = function(child) {
|
||||||
this.children.push(child);
|
this.children.push(child);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,17 +22,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
this.focusedRunables = [];
|
this.focusedRunables = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
inDescribe() {
|
|
||||||
return this.currentDeclarationSuite_ !== this.topSuite;
|
|
||||||
}
|
|
||||||
|
|
||||||
parallelReset() {
|
|
||||||
this.topSuite.removeChildren();
|
|
||||||
this.topSuite.reset();
|
|
||||||
this.totalSpecsDefined = 0;
|
|
||||||
this.focusedRunables = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe(description, definitionFn, filename) {
|
describe(description, definitionFn, filename) {
|
||||||
ensureIsFunction(definitionFn, 'describe');
|
ensureIsFunction(definitionFn, 'describe');
|
||||||
const suite = this.suiteFactory_(description, filename);
|
const suite = this.suiteFactory_(description, filename);
|
||||||
|
|||||||
@@ -5,35 +5,16 @@ getJasmineRequireObj().Timer = function() {
|
|||||||
};
|
};
|
||||||
})(Date);
|
})(Date);
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Timer
|
|
||||||
* @classdesc Tracks elapsed time
|
|
||||||
* @example
|
|
||||||
* const timer = new jasmine.Timer();
|
|
||||||
* timer.start();
|
|
||||||
* const elapsed = timer.elapsed()
|
|
||||||
*/
|
|
||||||
function Timer(options) {
|
function Timer(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
const now = options.now || defaultNow;
|
const now = options.now || defaultNow;
|
||||||
let startTime;
|
let startTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the timer.
|
|
||||||
* @function
|
|
||||||
* @name Timer#start
|
|
||||||
*/
|
|
||||||
this.start = function() {
|
this.start = function() {
|
||||||
startTime = now();
|
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() {
|
this.elapsed = function() {
|
||||||
return now() - startTime;
|
return now() - startTime;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,11 +69,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
|||||||
} else if (options.stack) {
|
} else if (options.stack) {
|
||||||
error = options;
|
error = options;
|
||||||
} else {
|
} else {
|
||||||
try {
|
error = new Error(message());
|
||||||
throw new Error(message());
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Omit the message from the stack trace because it will be
|
// Omit the message from the stack trace because it will be
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
getJasmineRequireObj().reporterEvents = function() {
|
|
||||||
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 {SuiteResult} 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 {SuiteResult} 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 {SpecResult} 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 {SpecResult} 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;
|
|
||||||
};
|
|
||||||
@@ -67,9 +67,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
||||||
j$
|
j$
|
||||||
);
|
);
|
||||||
j$.reporterEvents = jRequire.reporterEvents(j$);
|
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$);
|
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
j$.Runner = jRequire.Runner(j$);
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
|
|||||||
@@ -225,54 +225,6 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
|||||||
return env.expectAsync(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
|
|
||||||
* @param actual
|
|
||||||
* @global
|
|
||||||
* @param {Object} actual - Actual computed value to test expectations against.
|
|
||||||
* @return {matchers}
|
|
||||||
*/
|
|
||||||
throwUnlessAsync: function(actual) {
|
|
||||||
return env.throwUnless(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
|
|
||||||
* @param actual
|
|
||||||
* @global
|
|
||||||
* @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.
|
* Mark a spec as pending, expectation results will be ignored.
|
||||||
* @name pending
|
* @name pending
|
||||||
|
|||||||
Reference in New Issue
Block a user