Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
481f1e7c5c | ||
|
|
5e650953cd | ||
|
|
87f9ab29df | ||
|
|
b831e81074 | ||
|
|
4c13c2b00b | ||
|
|
4cd190b232 | ||
|
|
d4025999b7 | ||
|
|
44f331f43d | ||
|
|
59848ca151 | ||
|
|
c14bfe3e5f | ||
|
|
26c48ab324 | ||
|
|
cfecab9f79 | ||
|
|
b3d9435dbb | ||
|
|
fec8dd37b0 | ||
|
|
f934e6d816 | ||
|
|
79c6bbc189 | ||
|
|
5f3475342e | ||
|
|
21f25972bb |
31
.github/CONTRIBUTING.md
vendored
31
.github/CONTRIBUTING.md
vendored
@@ -1,19 +1,10 @@
|
|||||||
# Developing for Jasmine Core
|
# Contributing to Jasmine
|
||||||
|
|
||||||
We welcome your contributions! Thanks for helping make Jasmine a better project
|
We welcome your contributions! Thanks for helping make Jasmine a better project
|
||||||
for everyone. Please review the backlog and discussion lists before starting
|
for everyone. If you want to contribute but don't know what to work on,
|
||||||
work. What you're looking for may already have been done. If it hasn't, the
|
[issues tagged help needed](https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Ajasmine+label%3A%22help+needed%22+)
|
||||||
community can help make your contribution better. If you want to contribute but
|
|
||||||
don't know what to work on,
|
|
||||||
[issues tagged help needed](https://github.com/jasmine/jasmine/labels/help%20needed)
|
|
||||||
should have enough detail to get started.
|
should have enough detail to get started.
|
||||||
|
|
||||||
## Links
|
|
||||||
|
|
||||||
- [Jasmine Google Group](http://groups.google.com/group/jasmine-js)
|
|
||||||
- [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev)
|
|
||||||
- [Jasmine backlog](https://www.pivotaltracker.com/n/projects/10606)
|
|
||||||
|
|
||||||
## Before Submitting a Pull Request
|
## Before Submitting a Pull Request
|
||||||
|
|
||||||
1. Ensure all specs are green in browsers *and* node.
|
1. Ensure all specs are green in browsers *and* node.
|
||||||
@@ -94,14 +85,7 @@ Or, How to make a successful pull request
|
|||||||
* _Write specs_ - Jasmine's a testing framework. Don't add functionality
|
* _Write specs_ - Jasmine's a testing framework. Don't add functionality
|
||||||
without test-driving it.
|
without test-driving it.
|
||||||
* _Write code in the style of the rest of the repo_ - Jasmine should look like
|
* _Write code in the style of the rest of the repo_ - Jasmine should look like
|
||||||
a cohesive whole.
|
a cohesive whole.
|
||||||
|
|
||||||
Key exceptions:
|
|
||||||
* Use `const` or `let` for new variable declarations, even if nearby code
|
|
||||||
uses `var`.
|
|
||||||
* New async specs should usually be async/await or promise-returning, not
|
|
||||||
callback based.
|
|
||||||
|
|
||||||
* _Ensure the *entire* test suite is green_ in all the big browsers, Node, and
|
* _Ensure the *entire* test suite is green_ in all the big browsers, Node, and
|
||||||
ESLint/Prettier. Your contribution shouldn't break Jasmine for other users.
|
ESLint/Prettier. Your contribution shouldn't break Jasmine for other users.
|
||||||
|
|
||||||
@@ -119,3 +103,10 @@ chromedriver), you can also use Jasmine's CI tooling:
|
|||||||
|
|
||||||
$ JASMINE_BROWSER=<name of browser> npm run ci
|
$ JASMINE_BROWSER=<name of browser> npm run ci
|
||||||
|
|
||||||
|
### Submitting a Pull Requeset
|
||||||
|
|
||||||
|
Once you've done the steps listed under "Before Submitting a Pull Request"
|
||||||
|
above, you can submit a pull request via the
|
||||||
|
[standard GitHub process](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
|
||||||
|
TL;DR: Fork the repository, push your work up to your fork, and create a PR from
|
||||||
|
there.
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Microsoft Edge) as well as Node.
|
|||||||
| Environment | Supported versions |
|
| Environment | Supported versions |
|
||||||
|-------------------|--------------------|
|
|-------------------|--------------------|
|
||||||
| Node | 12.17+, 14, 16, 18 |
|
| Node | 12.17+, 14, 16, 18 |
|
||||||
| Safari | 14-15 |
|
| Safari | 14-16 |
|
||||||
| Chrome | Evergreen |
|
| Chrome | Evergreen |
|
||||||
| Firefox | Evergreen, 91 |
|
| Firefox | Evergreen, 91 |
|
||||||
| Edge | Evergreen |
|
| Edge | Evergreen |
|
||||||
|
|||||||
28
RELEASE.md
28
RELEASE.md
@@ -18,12 +18,11 @@ copied to `jasmine.js` when the distribution is built. When releasing a new
|
|||||||
version, update `package.json` with the new version and `npm run build` to
|
version, update `package.json` with the new version and `npm run build` to
|
||||||
update the gem version number.
|
update the gem version number.
|
||||||
|
|
||||||
Note that Jasmine should only use the "patch" version number in the following cases:
|
Note that Jasmine should only use the "patch" version number if the new release
|
||||||
|
contains only bug fixes.
|
||||||
|
|
||||||
* Changes related to packaging for a specific binding library (npm or browser-runner)
|
When `jasmine-core` revs its major or minor version, the `jasmine` NPM package
|
||||||
* Fixes for regressions.
|
should also rev to that version.
|
||||||
|
|
||||||
When jasmine-core revs its major or minor version, the binding libraries should also rev to that version.
|
|
||||||
|
|
||||||
## Release
|
## Release
|
||||||
|
|
||||||
@@ -61,20 +60,13 @@ for instructions.
|
|||||||
1. `rake release[${version}]` to copy the current edge docs to the new version
|
1. `rake release[${version}]` to copy the current edge docs to the new version
|
||||||
1. Commit and push.
|
1. Commit and push.
|
||||||
|
|
||||||
### Release the binding libraries
|
### Release the `jasmine` NPM package
|
||||||
|
|
||||||
#### NPM
|
See <https://github.com/jasmine/jasmine-npm/blob/main/RELEASE.md>.
|
||||||
|
|
||||||
1. Create release notes using Anchorman as above
|
### Publish the GitHub release
|
||||||
1. In `package.json`, update both the package version and the jasmine-core dependency version
|
|
||||||
1. Commit and push.
|
|
||||||
1. Wait for Circle CI to go green again.
|
|
||||||
1. `grunt release `. (Note: This will publish the package by running `npm publish`.)
|
|
||||||
|
|
||||||
### Finally
|
|
||||||
|
|
||||||
For each of the above GitHub repos:
|
|
||||||
1. Visit the releases page and find the tag just published.
|
1. Visit the releases page and find the tag just published.
|
||||||
1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes.
|
2. Paste in a link to the correct release notes for this release.
|
||||||
1. If it is a pre-release, mark it as such.
|
3. If it is a pre-release, mark it as such.
|
||||||
1. For core, attach the standalone zipfile.
|
4. Attach the standalone zipfile.
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
function Player() {
|
class Player {
|
||||||
}
|
play(song) {
|
||||||
Player.prototype.play = function(song) {
|
this.currentlyPlayingSong = song;
|
||||||
this.currentlyPlayingSong = song;
|
this.isPlaying = true;
|
||||||
this.isPlaying = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.pause = function() {
|
|
||||||
this.isPlaying = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.resume = function() {
|
|
||||||
if (this.isPlaying) {
|
|
||||||
throw new Error("song is already playing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isPlaying = true;
|
pause() {
|
||||||
};
|
this.isPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
Player.prototype.makeFavorite = function() {
|
resume() {
|
||||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
if (this.isPlaying) {
|
||||||
};
|
throw new Error('song is already playing');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isPlaying = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeFavorite() {
|
||||||
|
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = Player;
|
module.exports = Player;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
function Song() {
|
class Song {
|
||||||
|
persistFavoriteStatus(value) {
|
||||||
|
// something complicated
|
||||||
|
throw new Error('not yet implemented');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Song.prototype.persistFavoriteStatus = function(value) {
|
|
||||||
// something complicated
|
|
||||||
throw new Error("not yet implemented");
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Song;
|
module.exports = Song;
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ beforeEach(function () {
|
|||||||
toBePlaying: function () {
|
toBePlaying: function () {
|
||||||
return {
|
return {
|
||||||
compare: function (actual, expected) {
|
compare: function (actual, expected) {
|
||||||
var player = actual;
|
const player = actual;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,37 @@
|
|||||||
describe("Player", function() {
|
const Player = require('../../lib/jasmine_examples/Player');
|
||||||
var Player = require('../../lib/jasmine_examples/Player');
|
const Song = require('../../lib/jasmine_examples/Song');
|
||||||
var Song = require('../../lib/jasmine_examples/Song');
|
|
||||||
var player;
|
describe('Player', function() {
|
||||||
var song;
|
let player;
|
||||||
|
let song;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
player = new Player();
|
player = new Player();
|
||||||
song = new Song();
|
song = new Song();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to play a Song", function() {
|
it('should be able to play a Song', function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
expect(player.currentlyPlayingSong).toEqual(song);
|
expect(player.currentlyPlayingSong).toEqual(song);
|
||||||
|
|
||||||
//demonstrates use of custom matcher
|
// demonstrates use of custom matcher
|
||||||
expect(player).toBePlaying(song);
|
expect(player).toBePlaying(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when song has been paused", function() {
|
describe('when song has been paused', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
player.pause();
|
player.pause();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should indicate that the song is currently paused", function() {
|
it('should indicate that the song is currently paused', function() {
|
||||||
expect(player.isPlaying).toBeFalsy();
|
expect(player.isPlaying).toBeFalsy();
|
||||||
|
|
||||||
// demonstrates use of 'not' with a custom matcher
|
// demonstrates use of 'not' with a custom matcher
|
||||||
expect(player).not.toBePlaying(song);
|
expect(player).not.toBePlaying(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be possible to resume", function() {
|
it('should be possible to resume', function() {
|
||||||
player.resume();
|
player.resume();
|
||||||
expect(player.isPlaying).toBeTruthy();
|
expect(player.isPlaying).toBeTruthy();
|
||||||
expect(player.currentlyPlayingSong).toEqual(song);
|
expect(player.currentlyPlayingSong).toEqual(song);
|
||||||
@@ -38,7 +39,7 @@ describe("Player", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// demonstrates use of spies to intercept and test method calls
|
// demonstrates use of spies to intercept and test method calls
|
||||||
it("tells the current song if the user has made it a favorite", function() {
|
it('tells the current song if the user has made it a favorite', function() {
|
||||||
spyOn(song, 'persistFavoriteStatus');
|
spyOn(song, 'persistFavoriteStatus');
|
||||||
|
|
||||||
player.play(song);
|
player.play(song);
|
||||||
@@ -48,13 +49,13 @@ describe("Player", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//demonstrates use of expected exceptions
|
//demonstrates use of expected exceptions
|
||||||
describe("#resume", function() {
|
describe('#resume', function() {
|
||||||
it("should throw an exception if song is already playing", function() {
|
it('should throw an exception if song is already playing', function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
player.resume();
|
player.resume();
|
||||||
}).toThrowError("song is already playing");
|
}).toThrowError('song is already playing');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
describe("Player", function() {
|
describe('Player', function() {
|
||||||
var player;
|
let player;
|
||||||
var song;
|
let song;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
player = new Player();
|
player = new Player();
|
||||||
song = new Song();
|
song = new Song();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to play a Song", function() {
|
it('should be able to play a Song', function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
expect(player.currentlyPlayingSong).toEqual(song);
|
expect(player.currentlyPlayingSong).toEqual(song);
|
||||||
|
|
||||||
//demonstrates use of custom matcher
|
// demonstrates use of custom matcher
|
||||||
expect(player).toBePlaying(song);
|
expect(player).toBePlaying(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when song has been paused", function() {
|
describe('when song has been paused', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
player.pause();
|
player.pause();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should indicate that the song is currently paused", function() {
|
it('should indicate that the song is currently paused', function() {
|
||||||
expect(player.isPlaying).toBeFalsy();
|
expect(player.isPlaying).toBeFalsy();
|
||||||
|
|
||||||
// demonstrates use of 'not' with a custom matcher
|
// demonstrates use of 'not' with a custom matcher
|
||||||
expect(player).not.toBePlaying(song);
|
expect(player).not.toBePlaying(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be possible to resume", function() {
|
it('should be possible to resume', function() {
|
||||||
player.resume();
|
player.resume();
|
||||||
expect(player.isPlaying).toBeTruthy();
|
expect(player.isPlaying).toBeTruthy();
|
||||||
expect(player.currentlyPlayingSong).toEqual(song);
|
expect(player.currentlyPlayingSong).toEqual(song);
|
||||||
@@ -36,7 +36,7 @@ describe("Player", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// demonstrates use of spies to intercept and test method calls
|
// demonstrates use of spies to intercept and test method calls
|
||||||
it("tells the current song if the user has made it a favorite", function() {
|
it('tells the current song if the user has made it a favorite', function() {
|
||||||
spyOn(song, 'persistFavoriteStatus');
|
spyOn(song, 'persistFavoriteStatus');
|
||||||
|
|
||||||
player.play(song);
|
player.play(song);
|
||||||
@@ -46,13 +46,13 @@ describe("Player", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//demonstrates use of expected exceptions
|
//demonstrates use of expected exceptions
|
||||||
describe("#resume", function() {
|
describe('#resume', function() {
|
||||||
it("should throw an exception if song is already playing", function() {
|
it('should throw an exception if song is already playing', function() {
|
||||||
player.play(song);
|
player.play(song);
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
player.resume();
|
player.resume();
|
||||||
}).toThrowError("song is already playing");
|
}).toThrowError('song is already playing');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ beforeEach(function () {
|
|||||||
toBePlaying: function () {
|
toBePlaying: function () {
|
||||||
return {
|
return {
|
||||||
compare: function (actual, expected) {
|
compare: function (actual, expected) {
|
||||||
var player = actual;
|
const player = actual;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
function Player() {
|
class Player {
|
||||||
}
|
play(song) {
|
||||||
Player.prototype.play = function(song) {
|
this.currentlyPlayingSong = song;
|
||||||
this.currentlyPlayingSong = song;
|
this.isPlaying = true;
|
||||||
this.isPlaying = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.pause = function() {
|
|
||||||
this.isPlaying = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.resume = function() {
|
|
||||||
if (this.isPlaying) {
|
|
||||||
throw new Error("song is already playing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isPlaying = true;
|
pause() {
|
||||||
};
|
this.isPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
Player.prototype.makeFavorite = function() {
|
resume() {
|
||||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
if (this.isPlaying) {
|
||||||
};
|
throw new Error('song is already playing');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isPlaying = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeFavorite() {
|
||||||
|
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
function Song() {
|
class Song {
|
||||||
|
persistFavoriteStatus(value) {
|
||||||
|
// something complicated
|
||||||
|
throw new Error('not yet implemented');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Song.prototype.persistFavoriteStatus = function(value) {
|
|
||||||
// something complicated
|
|
||||||
throw new Error("not yet implemented");
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -776,7 +776,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef SpecResult
|
* @typedef SpecResult
|
||||||
* @property {Int} id - The unique id of this spec.
|
* @property {String} id - The unique id of this spec.
|
||||||
* @property {String} description - The description passed to the {@link it} that created this spec.
|
* @property {String} description - The description passed to the {@link it} that created this spec.
|
||||||
* @property {String} fullName - The full description including all ancestors of this spec.
|
* @property {String} fullName - The full description including all ancestors of this spec.
|
||||||
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
||||||
@@ -1843,12 +1843,12 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
runner.currentSpec = spec;
|
runner.currentSpec = spec;
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reporter.specStarted(spec.result, next);
|
reporter.specStarted(spec.result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportSpecDone(spec, result, next) {
|
function reportSpecDone(spec, result, next) {
|
||||||
spec.reportedDone = true;
|
spec.reportedDone = true;
|
||||||
reporter.specDone(result, next);
|
reporter.specDone(result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
@@ -2789,8 +2789,32 @@ getJasmineRequireObj().CallTracker = function(j$) {
|
|||||||
getJasmineRequireObj().clearStack = function(j$) {
|
getJasmineRequireObj().clearStack = function(j$) {
|
||||||
const maxInlineCallCount = 10;
|
const maxInlineCallCount = 10;
|
||||||
|
|
||||||
function messageChannelImpl(global, setTimeout) {
|
function browserQueueMicrotaskImpl(global) {
|
||||||
const channel = new global.MessageChannel();
|
const { setTimeout, queueMicrotask } = global;
|
||||||
|
let currentCallCount = 0;
|
||||||
|
return function clearStack(fn) {
|
||||||
|
currentCallCount++;
|
||||||
|
|
||||||
|
if (currentCallCount < maxInlineCallCount) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
} else {
|
||||||
|
currentCallCount = 0;
|
||||||
|
setTimeout(fn);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeQueueMicrotaskImpl(global) {
|
||||||
|
const { queueMicrotask } = global;
|
||||||
|
|
||||||
|
return function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageChannelImpl(global) {
|
||||||
|
const { MessageChannel, setTimeout } = global;
|
||||||
|
const channel = new MessageChannel();
|
||||||
let head = {};
|
let head = {};
|
||||||
let tail = head;
|
let tail = head;
|
||||||
|
|
||||||
@@ -2801,7 +2825,7 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
delete head.task;
|
delete head.task;
|
||||||
|
|
||||||
if (taskRunning) {
|
if (taskRunning) {
|
||||||
global.setTimeout(task, 0);
|
setTimeout(task, 0);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
taskRunning = true;
|
taskRunning = true;
|
||||||
@@ -2827,29 +2851,32 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getClearStack(global) {
|
function getClearStack(global) {
|
||||||
let currentCallCount = 0;
|
const NODE_JS =
|
||||||
const realSetTimeout = global.setTimeout;
|
global.process &&
|
||||||
const setTimeoutImpl = function clearStack(fn) {
|
global.process.versions &&
|
||||||
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
|
typeof global.process.versions.node === 'string';
|
||||||
};
|
|
||||||
|
|
||||||
if (j$.isFunction_(global.setImmediate)) {
|
const SAFARI =
|
||||||
const realSetImmediate = global.setImmediate;
|
global.navigator &&
|
||||||
return function(fn) {
|
/^((?!chrome|android).)*safari/i.test(global.navigator.userAgent);
|
||||||
currentCallCount++;
|
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
if (NODE_JS) {
|
||||||
realSetImmediate(fn);
|
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||||
} else {
|
// so we avoid the overhead.
|
||||||
currentCallCount = 0;
|
return nodeQueueMicrotaskImpl(global);
|
||||||
|
} else if (
|
||||||
setTimeoutImpl(fn);
|
SAFARI ||
|
||||||
}
|
j$.util.isUndefined(global.MessageChannel) /* tests */
|
||||||
};
|
) {
|
||||||
} else if (!j$.util.isUndefined(global.MessageChannel)) {
|
// queueMicrotask is dramatically faster than MessageChannel in Safari,
|
||||||
return messageChannelImpl(global, setTimeoutImpl);
|
// at least through version 16.
|
||||||
|
// Some of our own integration tests provide a mock queueMicrotask in all
|
||||||
|
// environments because it's simpler to mock than MessageChannel.
|
||||||
|
return browserQueueMicrotaskImpl(global);
|
||||||
} else {
|
} else {
|
||||||
return setTimeoutImpl;
|
// MessageChannel is faster than queueMicrotask in supported browsers
|
||||||
|
// other than Safari.
|
||||||
|
return messageChannelImpl(global);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3468,18 +3495,38 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stackTrace = new j$.StackTrace(error);
|
const lines = this.stack_(error, {
|
||||||
const lines = filterJasmine(stackTrace);
|
messageHandling: omitMessage ? 'omit' : undefined
|
||||||
let result = '';
|
});
|
||||||
|
return lines.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
if (stackTrace.message && !omitMessage) {
|
// messageHandling can be falsy (unspecified), 'omit', or 'require'
|
||||||
|
this.stack_ = function(error, { messageHandling }) {
|
||||||
|
let lines = formatProperties(error).split('\n');
|
||||||
|
|
||||||
|
if (lines[lines.length - 1] === '') {
|
||||||
|
lines.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const stackTrace = new j$.StackTrace(error);
|
||||||
|
lines = lines.concat(filterJasmine(stackTrace));
|
||||||
|
|
||||||
|
if (messageHandling === 'require') {
|
||||||
|
lines.unshift(stackTrace.message || 'Error: ' + error.message);
|
||||||
|
} else if (messageHandling !== 'omit' && stackTrace.message) {
|
||||||
lines.unshift(stackTrace.message);
|
lines.unshift(stackTrace.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
result += formatProperties(error);
|
if (error.cause) {
|
||||||
result += lines.join('\n');
|
const substack = this.stack_(error.cause, {
|
||||||
|
messageHandling: 'require'
|
||||||
|
});
|
||||||
|
substack[0] = 'Caused by: ' + substack[0];
|
||||||
|
lines = lines.concat(substack);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
function filterJasmine(stackTrace) {
|
function filterJasmine(stackTrace) {
|
||||||
@@ -4055,21 +4102,14 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (global.addEventListener) {
|
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
||||||
global.addEventListener(
|
|
||||||
'unhandledrejection',
|
|
||||||
browserRejectionHandler
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.uninstall = function uninstall() {
|
this.uninstall = function uninstall() {
|
||||||
global.onerror = originalHandler;
|
global.onerror = originalHandler;
|
||||||
if (global.removeEventListener) {
|
global.removeEventListener(
|
||||||
global.removeEventListener(
|
'unhandledrejection',
|
||||||
'unhandledrejection',
|
browserRejectionHandler
|
||||||
browserRejectionHandler
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -5222,7 +5262,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
|||||||
* };
|
* };
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* var actual = {
|
* const actual = {
|
||||||
* n: 2,
|
* n: 2,
|
||||||
* otherFields: "don't care"
|
* otherFields: "don't care"
|
||||||
* };
|
* };
|
||||||
@@ -6368,7 +6408,7 @@ getJasmineRequireObj().toHaveClass = function(j$) {
|
|||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
* @param {Object} expected - The class name to test for
|
* @param {Object} expected - The class name to test for
|
||||||
* @example
|
* @example
|
||||||
* var el = document.createElement('div');
|
* const el = document.createElement('div');
|
||||||
* el.className = 'foo bar baz';
|
* el.className = 'foo bar baz';
|
||||||
* expect(el).toHaveClass('bar');
|
* expect(el).toHaveClass('bar');
|
||||||
*/
|
*/
|
||||||
@@ -7700,7 +7740,7 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
for (const method of dispatchedMethods) {
|
for (const method of dispatchedMethods) {
|
||||||
this[method] = (function(m) {
|
this[method] = (function(m) {
|
||||||
return function() {
|
return function() {
|
||||||
dispatch(m, arguments);
|
return dispatch(m, arguments);
|
||||||
};
|
};
|
||||||
})(method);
|
})(method);
|
||||||
}
|
}
|
||||||
@@ -7726,25 +7766,25 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
if (reporters.length === 0 && fallbackReporter !== null) {
|
if (reporters.length === 0 && fallbackReporter !== null) {
|
||||||
reporters.push(fallbackReporter);
|
reporters.push(fallbackReporter);
|
||||||
}
|
}
|
||||||
const onComplete = args[args.length - 1];
|
|
||||||
args = Array.from(args).splice(0, args.length - 1);
|
|
||||||
const fns = [];
|
const fns = [];
|
||||||
for (const reporter of reporters) {
|
for (const reporter of reporters) {
|
||||||
addFn(fns, reporter, method, args);
|
addFn(fns, reporter, method, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueRunnerFactory({
|
return new Promise(function(resolve) {
|
||||||
queueableFns: fns,
|
queueRunnerFactory({
|
||||||
onComplete: onComplete,
|
queueableFns: fns,
|
||||||
isReporter: true,
|
onComplete: resolve,
|
||||||
onMultipleDone: function() {
|
isReporter: true,
|
||||||
onLateError(
|
onMultipleDone: function() {
|
||||||
new Error(
|
onLateError(
|
||||||
"An asynchronous reporter callback called its 'done' callback " +
|
new Error(
|
||||||
'more than once.'
|
"An asynchronous reporter callback called its 'done' callback " +
|
||||||
)
|
'more than once.'
|
||||||
);
|
)
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8400,7 +8440,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
this.executedBefore_ = true;
|
this.executedBefore_ = true;
|
||||||
|
|
||||||
this.hasFailures = false;
|
this.hasFailures = false;
|
||||||
const totalSpecsDefined = this.totalSpecsDefined_();
|
|
||||||
const focusedRunables = this.focusedRunables_();
|
const focusedRunables = this.focusedRunables_();
|
||||||
const config = this.getConfig_();
|
const config = this.getConfig_();
|
||||||
|
|
||||||
@@ -8414,7 +8453,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
|
|
||||||
const order = new j$.Order({
|
const order = new j$.Order({
|
||||||
random: config.random,
|
random: config.random,
|
||||||
seed: config.seed
|
seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed
|
||||||
});
|
});
|
||||||
|
|
||||||
const processor = new j$.TreeProcessor({
|
const processor = new j$.TreeProcessor({
|
||||||
@@ -8439,7 +8478,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
nodeStart: (suite, next) => {
|
nodeStart: (suite, next) => {
|
||||||
this.currentlyExecutingSuites_.push(suite);
|
this.currentlyExecutingSuites_.push(suite);
|
||||||
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
this.reporter_.suiteStarted(suite.result, next);
|
this.reporter_.suiteStarted(suite.result).then(next);
|
||||||
suite.startTimer();
|
suite.startTimer();
|
||||||
},
|
},
|
||||||
nodeComplete: (suite, result, next) => {
|
nodeComplete: (suite, result, next) => {
|
||||||
@@ -8477,106 +8516,97 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.execute2_(runablesToRun, order, processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute2_(runablesToRun, order, processor) {
|
||||||
|
const totalSpecsDefined = this.totalSpecsDefined_();
|
||||||
|
|
||||||
this.runableResources_.initForRunable(this.topSuite_.id);
|
this.runableResources_.initForRunable(this.topSuite_.id);
|
||||||
const jasmineTimer = new j$.Timer();
|
const jasmineTimer = new j$.Timer();
|
||||||
jasmineTimer.start();
|
jasmineTimer.start();
|
||||||
|
|
||||||
return new Promise(resolve => {
|
/**
|
||||||
/**
|
* 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.
|
||||||
* @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.
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
* @since 2.0.0
|
||||||
* @since 2.0.0
|
*/
|
||||||
*/
|
await this.reporter_.jasmineStarted({
|
||||||
this.reporter_.jasmineStarted(
|
totalSpecsDefined,
|
||||||
{
|
order: order
|
||||||
totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.currentlyExecutingSuites_.push(this.topSuite_);
|
|
||||||
|
|
||||||
processor.execute(() => {
|
|
||||||
(async () => {
|
|
||||||
if (this.topSuite_.hadBeforeAllFailure) {
|
|
||||||
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.runableResources_.clearForRunable(this.topSuite_.id);
|
|
||||||
this.currentlyExecutingSuites_.pop();
|
|
||||||
let overallStatus, incompleteReason;
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.hasFailures ||
|
|
||||||
this.topSuite_.result.failedExpectations.length > 0
|
|
||||||
) {
|
|
||||||
overallStatus = 'failed';
|
|
||||||
} else if (focusedRunables.length > 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
|
||||||
} else if (totalSpecsDefined === 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'No specs found';
|
|
||||||
} else {
|
|
||||||
overallStatus = 'passed';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineDone} event.
|
|
||||||
* @typedef JasmineDoneInfo
|
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
|
||||||
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
|
||||||
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @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.
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
const jasmineDoneInfo = {
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: this.topSuite_.result.failedExpectations,
|
|
||||||
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
|
||||||
};
|
|
||||||
this.topSuite_.reportedDone = true;
|
|
||||||
this.reporter_.jasmineDone(jasmineDoneInfo, function() {
|
|
||||||
resolve(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
|
await processor.execute();
|
||||||
|
|
||||||
|
if (this.topSuite_.hadBeforeAllFailure) {
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
|
this.currentlyExecutingSuites_.pop();
|
||||||
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.hasFailures ||
|
||||||
|
this.topSuite_.result.failedExpectations.length > 0
|
||||||
|
) {
|
||||||
|
overallStatus = 'failed';
|
||||||
|
} else if (this.focusedRunables_().length > 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
|
} else if (totalSpecsDefined === 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'No specs found';
|
||||||
|
} else {
|
||||||
|
overallStatus = 'passed';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineDone} event.
|
||||||
|
* @typedef JasmineDoneInfo
|
||||||
|
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
||||||
|
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
||||||
|
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @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.
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
const jasmineDoneInfo = {
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
|
};
|
||||||
|
this.topSuite_.reportedDone = true;
|
||||||
|
await this.reporter_.jasmineDone(jasmineDoneInfo);
|
||||||
|
return jasmineDoneInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportSuiteDone_(suite, result, next) {
|
reportSuiteDone_(suite, result, next) {
|
||||||
suite.reportedDone = true;
|
suite.reportedDone = true;
|
||||||
this.reporter_.suiteDone(result, next);
|
this.reporter_.suiteDone(result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
async reportChildrenOfBeforeAllFailure_(suite) {
|
async reportChildrenOfBeforeAllFailure_(suite) {
|
||||||
for (const child of suite.children) {
|
for (const child of suite.children) {
|
||||||
if (child instanceof j$.Suite) {
|
if (child instanceof j$.Suite) {
|
||||||
await new Promise(resolve => {
|
await this.reporter_.suiteStarted(child.result);
|
||||||
this.reporter_.suiteStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
await this.reportChildrenOfBeforeAllFailure_(child);
|
await this.reportChildrenOfBeforeAllFailure_(child);
|
||||||
|
|
||||||
// Marking the suite passed is consistent with how suites that
|
// Marking the suite passed is consistent with how suites that
|
||||||
// contain failed specs but no suite-level failures are reported.
|
// contain failed specs but no suite-level failures are reported.
|
||||||
child.result.status = 'passed';
|
child.result.status = 'passed';
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await this.reporter_.suiteDone(child.result);
|
||||||
this.reporter_.suiteDone(child.result, resolve);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
/* a spec */
|
/* a spec */
|
||||||
await new Promise(resolve => {
|
await this.reporter_.specStarted(child.result);
|
||||||
this.reporter_.specStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.addExpectationResult(
|
child.addExpectationResult(
|
||||||
false,
|
false,
|
||||||
@@ -9602,7 +9632,7 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
Suite.prototype.reset = function() {
|
Suite.prototype.reset = function() {
|
||||||
/**
|
/**
|
||||||
* @typedef SuiteResult
|
* @typedef SuiteResult
|
||||||
* @property {Int} id - The unique id of this suite.
|
* @property {String} id - The unique id of this suite.
|
||||||
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
||||||
* @property {String} fullName - The full description including all ancestors of this suite.
|
* @property {String} fullName - The full description including all ancestors of this suite.
|
||||||
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
||||||
@@ -9853,11 +9883,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
suite.exclude();
|
suite.exclude();
|
||||||
}
|
}
|
||||||
this.addSpecsToSuite_(suite, definitionFn);
|
this.addSpecsToSuite_(suite, definitionFn);
|
||||||
if (suite.parentSuite && !suite.children.length) {
|
|
||||||
throw new Error(
|
|
||||||
`describe with no children (describe() or it()): ${suite.getFullName()}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10004,11 +10029,19 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
const parentSuite = this.currentDeclarationSuite_;
|
const parentSuite = this.currentDeclarationSuite_;
|
||||||
parentSuite.addChild(suite);
|
parentSuite.addChild(suite);
|
||||||
this.currentDeclarationSuite_ = suite;
|
this.currentDeclarationSuite_ = suite;
|
||||||
|
let threw = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
definitionFn();
|
definitionFn();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
suite.handleException(e);
|
suite.handleException(e);
|
||||||
|
threw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suite.parentSuite && !suite.children.length && !threw) {
|
||||||
|
throw new Error(
|
||||||
|
`describe with no children (describe() or it()): ${suite.getFullName()}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentDeclarationSuite_ = parentSuite;
|
this.currentDeclarationSuite_ = parentSuite;
|
||||||
@@ -10176,7 +10209,7 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
return stats;
|
return stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.execute = function(done) {
|
this.execute = async function() {
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
this.processTree();
|
this.processTree();
|
||||||
}
|
}
|
||||||
@@ -10187,16 +10220,18 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
|
|
||||||
const childFns = wrapChildren(tree, 0);
|
const childFns = wrapChildren(tree, 0);
|
||||||
|
|
||||||
queueRunnerFactory({
|
await new Promise(function(resolve) {
|
||||||
queueableFns: childFns,
|
queueRunnerFactory({
|
||||||
userContext: tree.sharedUserContext(),
|
queueableFns: childFns,
|
||||||
onException: function() {
|
userContext: tree.sharedUserContext(),
|
||||||
tree.handleException.apply(tree, arguments);
|
onException: function() {
|
||||||
},
|
tree.handleException.apply(tree, arguments);
|
||||||
onComplete: done,
|
},
|
||||||
onMultipleDone: tree.onMultipleDone
|
onComplete: resolve,
|
||||||
? tree.onMultipleDone.bind(tree)
|
onMultipleDone: tree.onMultipleDone
|
||||||
: null
|
? tree.onMultipleDone.bind(tree)
|
||||||
|
: null
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -10429,5 +10464,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().version = function() {
|
getJasmineRequireObj().version = function() {
|
||||||
return '4.3.0';
|
return '4.4.0';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jasmine-core",
|
"name": "jasmine-core",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "4.3.0",
|
"version": "4.5.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/jasmine/jasmine.git"
|
"url": "https://github.com/jasmine/jasmine.git"
|
||||||
|
|||||||
28
release_notes/4.4.0.md
Normal file
28
release_notes/4.4.0.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Jasmine 4.4.0 Release Notes
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
* Optimized the process of transitioning between specs in Node, Safari, and
|
||||||
|
Edge. This change reduces the run time of jasmine-core's own test suite by
|
||||||
|
50-70% in Node, about 20% in Edge, and 75-90% in Safari. Your results may
|
||||||
|
vary. In general, suites with many fast specs will see the greatest
|
||||||
|
performance improvement.
|
||||||
|
|
||||||
|
* Removed old code to support browsers that don't provide
|
||||||
|
addEventListener/removeEventListener.
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
jasmine-core 4.4.0 has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------------|--------------------|
|
||||||
|
| Node | 12.17+, 14, 16, 18 |
|
||||||
|
| Safari | 14-15 |
|
||||||
|
| Chrome | 105 |
|
||||||
|
| Firefox | 91, 102, 104 |
|
||||||
|
| Edge | 104 |
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
40
release_notes/4.5.0.md
Normal file
40
release_notes/4.5.0.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Jasmine 4.5.0 Release Notes
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
* Added Safari 16 to supported browsers
|
||||||
|
* Include inner exceptions in stack traces
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
* Report exceptions thrown by a describe before any it calls
|
||||||
|
* Coerce the random string to a seed before sending it to reporters
|
||||||
|
* This fixes an error in HTMLReporter when the configured seed is a
|
||||||
|
number rather than a string, which has been allowed since 3.8.0
|
||||||
|
|
||||||
|
## Documentation updates
|
||||||
|
|
||||||
|
* Fixed the jsdoc types of SuiteResult and SpecResult ids
|
||||||
|
* Replaced var with const in API doc examples
|
||||||
|
* Updated the style of the examples that are included in jasmine-core
|
||||||
|
|
||||||
|
## Internal improvements
|
||||||
|
|
||||||
|
* Converted TreeProcessor to async/await
|
||||||
|
* Converted ReportDispatcher to promises
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
jasmine-core 4.5.0 has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------------|--------------------|
|
||||||
|
| Node | 12.17+, 14, 16, 18 |
|
||||||
|
| Safari | 14-16 |
|
||||||
|
| Chrome | 107 |
|
||||||
|
| Firefox | 91, 102, 106 |
|
||||||
|
| Edge | 106 |
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
@@ -27,6 +27,7 @@ run_browser chrome latest
|
|||||||
run_browser firefox latest
|
run_browser firefox latest
|
||||||
run_browser firefox 102
|
run_browser firefox 102
|
||||||
run_browser firefox 91
|
run_browser firefox 91
|
||||||
|
run_browser safari 16
|
||||||
run_browser safari 15
|
run_browser safari 15
|
||||||
run_browser safari 14
|
run_browser safari 14
|
||||||
run_browser MicrosoftEdge latest
|
run_browser MicrosoftEdge latest
|
||||||
|
|||||||
@@ -9,160 +9,216 @@ describe('ClearStack', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses setImmediate when available', function() {
|
describe('in Safari', function() {
|
||||||
const setImmediate = jasmine
|
usesQueueMicrotaskWithSetTimeout(function() {
|
||||||
.createSpy('setImmediate')
|
return {
|
||||||
.and.callFake(function(fn) {
|
navigator: {
|
||||||
fn();
|
userAgent:
|
||||||
}),
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.0.8 (KHTML, like Gecko) Version/15.1 Safari/605.0.8'
|
||||||
global = { setImmediate: setImmediate },
|
},
|
||||||
clearStack = jasmineUnderTest.getClearStack(global);
|
// queueMicrotask should be used even though MessageChannel is present
|
||||||
let called = false;
|
MessageChannel: fakeMessageChannel
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
clearStack(function() {
|
describe('in browsers other than Safari', function() {
|
||||||
called = true;
|
usesMessageChannel(function() {
|
||||||
|
return {
|
||||||
|
navigator: {
|
||||||
|
// Chrome's user agent string contains "Safari" so it's a good test case
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(called).toBe(true);
|
describe('when MessageChannel is unavailable', function() {
|
||||||
expect(setImmediate).toHaveBeenCalled();
|
usesQueueMicrotaskWithSetTimeout(function() {
|
||||||
|
return {
|
||||||
|
navigator: {
|
||||||
|
userAgent: 'CERN-LineMode/2.15 libwww/2.17b3',
|
||||||
|
MessageChannel: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU', function() {
|
describe('in Node', function() {
|
||||||
const setImmediate = jasmine.createSpy('setImmediate'),
|
usesQueueMicrotaskWithoutSetTimeout(function() {
|
||||||
setTimeout = jasmine.createSpy('setTimeout'),
|
return {
|
||||||
global = { setImmediate: setImmediate, setTimeout: setTimeout },
|
process: {
|
||||||
clearStack = jasmineUnderTest.getClearStack(global);
|
versions: {
|
||||||
|
node: '3.1415927'
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
|
|
||||||
expect(setImmediate).toHaveBeenCalled();
|
|
||||||
expect(setTimeout).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
clearStack(function() {});
|
|
||||||
expect(setImmediate.calls.count()).toEqual(9);
|
|
||||||
expect(setTimeout.calls.count()).toEqual(1);
|
|
||||||
|
|
||||||
clearStack(function() {});
|
|
||||||
expect(setImmediate.calls.count()).toEqual(10);
|
|
||||||
expect(setTimeout.calls.count()).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses MessageChannels when available', function() {
|
|
||||||
const fakeChannel = {
|
|
||||||
port1: {},
|
|
||||||
port2: {
|
|
||||||
postMessage: function() {
|
|
||||||
fakeChannel.port1.onmessage();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
global = {
|
});
|
||||||
MessageChannel: function() {
|
});
|
||||||
return fakeChannel;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clearStack = jasmineUnderTest.getClearStack(global);
|
|
||||||
let called = false;
|
|
||||||
|
|
||||||
clearStack(function() {
|
function usesMessageChannel(makeGlobal) {
|
||||||
called = true;
|
it('uses MessageChannel', function() {
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
MessageChannel: fakeMessageChannel
|
||||||
|
};
|
||||||
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
|
let called = false;
|
||||||
|
|
||||||
|
clearStack(function() {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(called).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(called).toBe(true);
|
it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() {
|
||||||
});
|
const fakeChannel = fakeMessageChannel();
|
||||||
|
spyOn(fakeChannel.port2, 'postMessage');
|
||||||
it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() {
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
const fakeChannel = {
|
const global = {
|
||||||
port1: {},
|
...makeGlobal(),
|
||||||
port2: {
|
setTimeout,
|
||||||
postMessage: jasmine
|
|
||||||
.createSpy('postMessage')
|
|
||||||
.and.callFake(function() {
|
|
||||||
fakeChannel.port1.onmessage();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setTimeout = jasmine.createSpy('setTimeout'),
|
|
||||||
global = {
|
|
||||||
MessageChannel: function() {
|
MessageChannel: function() {
|
||||||
return fakeChannel;
|
return fakeChannel;
|
||||||
},
|
|
||||||
setTimeout: setTimeout
|
|
||||||
},
|
|
||||||
clearStack = jasmineUnderTest.getClearStack(global);
|
|
||||||
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
clearStack(function() {});
|
|
||||||
|
|
||||||
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
|
|
||||||
expect(setTimeout).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
clearStack(function() {});
|
|
||||||
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9);
|
|
||||||
expect(setTimeout.calls.count()).toEqual(1);
|
|
||||||
|
|
||||||
clearStack(function() {});
|
|
||||||
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10);
|
|
||||||
expect(setTimeout.calls.count()).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls setTimeout when onmessage is called recursively', function() {
|
|
||||||
const fakeChannel = {
|
|
||||||
port1: {},
|
|
||||||
port2: {
|
|
||||||
postMessage: function() {
|
|
||||||
fakeChannel.port1.onmessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
setTimeout = jasmine.createSpy('setTimeout'),
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
global = {
|
|
||||||
MessageChannel: function() {
|
|
||||||
return fakeChannel;
|
|
||||||
},
|
|
||||||
setTimeout: setTimeout
|
|
||||||
},
|
|
||||||
clearStack = jasmineUnderTest.getClearStack(global),
|
|
||||||
fn = jasmine.createSpy('second clearStack function');
|
|
||||||
|
|
||||||
clearStack(function() {
|
for (let i = 0; i < 9; i++) {
|
||||||
clearStack(fn);
|
clearStack(function() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
|
||||||
|
expect(setTimeout).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
clearStack(function() {});
|
||||||
|
expect(fakeChannel.port2.postMessage).toHaveBeenCalledTimes(9);
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
clearStack(function() {});
|
||||||
|
expect(fakeChannel.port2.postMessage).toHaveBeenCalledTimes(10);
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fn).not.toHaveBeenCalled();
|
it('calls setTimeout when onmessage is called recursively', function() {
|
||||||
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
});
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
setTimeout,
|
||||||
|
MessageChannel: fakeMessageChannel
|
||||||
|
};
|
||||||
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
|
const fn = jasmine.createSpy('second clearStack function');
|
||||||
|
|
||||||
it('falls back to setTimeout', function() {
|
clearStack(function() {
|
||||||
const setTimeout = jasmine
|
clearStack(fn);
|
||||||
.createSpy('setTimeout')
|
});
|
||||||
.and.callFake(function(fn) {
|
|
||||||
|
expect(fn).not.toHaveBeenCalled();
|
||||||
|
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function usesQueueMicrotaskWithSetTimeout(makeGlobal) {
|
||||||
|
it('uses queueMicrotask', function() {
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
fn();
|
fn();
|
||||||
}),
|
}
|
||||||
global = { setTimeout: setTimeout },
|
};
|
||||||
clearStack = jasmineUnderTest.getClearStack(global);
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
||||||
clearStack(function() {
|
clearStack(function() {
|
||||||
called = true;
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(called).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(called).toBe(true);
|
it('uses setTimeout instead of queueMicrotask every 10 calls to make sure we release the CPU', function() {
|
||||||
expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 0);
|
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
||||||
});
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
queueMicrotask,
|
||||||
|
setTimeout
|
||||||
|
};
|
||||||
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
|
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
clearStack(function() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(queueMicrotask).toHaveBeenCalled();
|
||||||
|
expect(setTimeout).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
clearStack(function() {});
|
||||||
|
expect(queueMicrotask).toHaveBeenCalledTimes(9);
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
clearStack(function() {});
|
||||||
|
expect(queueMicrotask).toHaveBeenCalledTimes(10);
|
||||||
|
expect(setTimeout).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function usesQueueMicrotaskWithoutSetTimeout(makeGlobal) {
|
||||||
|
it('uses queueMicrotask', function() {
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
|
let called = false;
|
||||||
|
|
||||||
|
clearStack(function() {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(called).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not use setTimeout', function() {
|
||||||
|
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
||||||
|
const setTimeout = jasmine.createSpy('setTimeout');
|
||||||
|
const global = {
|
||||||
|
...makeGlobal(),
|
||||||
|
queueMicrotask,
|
||||||
|
setTimeout
|
||||||
|
};
|
||||||
|
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||||
|
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
clearStack(function() {});
|
||||||
|
|
||||||
|
expect(queueMicrotask).toHaveBeenCalledTimes(10);
|
||||||
|
expect(setTimeout).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fakeMessageChannel() {
|
||||||
|
const channel = {
|
||||||
|
port1: {},
|
||||||
|
port2: {
|
||||||
|
postMessage: function() {
|
||||||
|
channel.port1.onmessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -256,5 +256,51 @@ describe('ExceptionFormatter', function() {
|
|||||||
expect(result).not.toContain('an error');
|
expect(result).not.toContain('an error');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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() {
|
||||||
|
const subject = new jasmineUnderTest.ExceptionFormatter();
|
||||||
|
const rootCause = new Error('root cause');
|
||||||
|
const proximateCause = new Error('proximate cause', {
|
||||||
|
cause: rootCause
|
||||||
|
});
|
||||||
|
const symptom = new Error('symptom', { cause: proximateCause });
|
||||||
|
|
||||||
|
const lines = subject.stack(symptom).split('\n');
|
||||||
|
// Not all environments include the message in the stack trace.
|
||||||
|
const hasRootMessage = lines[0].indexOf('symptom') !== -1;
|
||||||
|
const firstSymptomStackIx = hasRootMessage ? 1 : 0;
|
||||||
|
|
||||||
|
expect(lines[firstSymptomStackIx])
|
||||||
|
.withContext('first symptom stack frame')
|
||||||
|
.toContain('ExceptionFormatterSpec.js');
|
||||||
|
const proximateCauseMsgIx = lines.indexOf(
|
||||||
|
'Caused by: Error: proximate cause'
|
||||||
|
);
|
||||||
|
expect(proximateCauseMsgIx)
|
||||||
|
.withContext('index of proximate cause message')
|
||||||
|
.toBeGreaterThan(firstSymptomStackIx);
|
||||||
|
expect(lines[proximateCauseMsgIx + 1])
|
||||||
|
.withContext('first proximate cause stack frame')
|
||||||
|
.toContain('ExceptionFormatterSpec.js');
|
||||||
|
const rootCauseMsgIx = lines.indexOf('Caused by: Error: root cause');
|
||||||
|
expect(rootCauseMsgIx)
|
||||||
|
.withContext('index of root cause message')
|
||||||
|
.toBeGreaterThan(proximateCauseMsgIx + 1);
|
||||||
|
expect(lines[rootCauseMsgIx + 1])
|
||||||
|
.withContext('first root cause stack frame')
|
||||||
|
.toContain('ExceptionFormatterSpec.js');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
describe('GlobalErrors', function() {
|
describe('GlobalErrors', function() {
|
||||||
it('calls the added handler on error', function() {
|
it('calls the added handler on error', function() {
|
||||||
const fakeGlobal = { onerror: null },
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
handler = jasmine.createSpy('errorHandler'),
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
@@ -13,10 +13,10 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('enables external interception of error by overriding global.onerror', function() {
|
it('enables external interception of error by overriding global.onerror', function() {
|
||||||
const fakeGlobal = { onerror: null },
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
handler = jasmine.createSpy('errorHandler'),
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
hijackHandler = jasmine.createSpy('hijackErrorHandler'),
|
const hijackHandler = jasmine.createSpy('hijackErrorHandler');
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
@@ -30,10 +30,10 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls the global error handler with all parameters', function() {
|
it('calls the global error handler with all parameters', function() {
|
||||||
const fakeGlobal = { onerror: null },
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
handler = jasmine.createSpy('errorHandler'),
|
const handler = jasmine.createSpy('errorHandler');
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
fooError = new Error('foo');
|
const fooError = new Error('foo');
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
@@ -50,10 +50,10 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('only calls the most recent handler', function() {
|
it('only calls the most recent handler', function() {
|
||||||
const fakeGlobal = { onerror: null },
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
handler1 = jasmine.createSpy('errorHandler1'),
|
const handler1 = jasmine.createSpy('errorHandler1');
|
||||||
handler2 = jasmine.createSpy('errorHandler2'),
|
const handler2 = jasmine.createSpy('errorHandler2');
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler1);
|
errors.pushListener(handler1);
|
||||||
@@ -66,10 +66,10 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls previous handlers when one is removed', function() {
|
it('calls previous handlers when one is removed', function() {
|
||||||
const fakeGlobal = { onerror: null },
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
handler1 = jasmine.createSpy('errorHandler1'),
|
const handler1 = jasmine.createSpy('errorHandler1');
|
||||||
handler2 = jasmine.createSpy('errorHandler2'),
|
const handler2 = jasmine.createSpy('errorHandler2');
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler1);
|
errors.pushListener(handler1);
|
||||||
@@ -91,9 +91,12 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('uninstalls itself, putting back a previous callback', function() {
|
it('uninstalls itself, putting back a previous callback', function() {
|
||||||
const originalCallback = jasmine.createSpy('error'),
|
const originalCallback = jasmine.createSpy('error');
|
||||||
fakeGlobal = { onerror: originalCallback },
|
const fakeGlobal = {
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
...minimalBrowserGlobal(),
|
||||||
|
onerror: originalCallback
|
||||||
|
};
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
expect(fakeGlobal.onerror).toBe(originalCallback);
|
expect(fakeGlobal.onerror).toBe(originalCallback);
|
||||||
|
|
||||||
@@ -107,9 +110,9 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('rethrows the original error when there is no handler', function() {
|
it('rethrows the original error when there is no handler', function() {
|
||||||
const fakeGlobal = {},
|
const fakeGlobal = minimalBrowserGlobal();
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
originalError = new Error('nope');
|
const originalError = new Error('nope');
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
|
|
||||||
@@ -407,7 +410,7 @@ describe('GlobalErrors', function() {
|
|||||||
|
|
||||||
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 = { onerror: null };
|
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');
|
||||||
@@ -529,8 +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 fakeGlobal = { onerror: null };
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
|
||||||
|
|
||||||
errors.setOverrideListener(() => {}, () => {});
|
errors.setOverrideListener(() => {}, () => {});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
@@ -541,9 +543,8 @@ 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 fakeGlobal = { onerror: null };
|
|
||||||
const onRemove = jasmine.createSpy('onRemove');
|
const onRemove = jasmine.createSpy('onRemove');
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
|
|
||||||
errors.setOverrideListener(() => {}, onRemove);
|
errors.setOverrideListener(() => {}, onRemove);
|
||||||
errors.removeOverrideListener();
|
errors.removeOverrideListener();
|
||||||
@@ -552,10 +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 fakeGlobal = { onerror: null };
|
const errors = new jasmineUnderTest.GlobalErrors(minimalBrowserGlobal());
|
||||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
|
||||||
|
|
||||||
expect(() => errors.removeOverrideListener()).not.toThrow();
|
expect(() => errors.removeOverrideListener()).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function minimalBrowserGlobal() {
|
||||||
|
return {
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {},
|
||||||
|
onerror: null
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,13 +18,12 @@ describe('ReportDispatcher', function() {
|
|||||||
queueRunnerFactory
|
queueRunnerFactory
|
||||||
),
|
),
|
||||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||||
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
|
||||||
completeCallback = jasmine.createSpy('complete');
|
|
||||||
|
|
||||||
dispatcher.addReporter(reporter);
|
dispatcher.addReporter(reporter);
|
||||||
dispatcher.addReporter(anotherReporter);
|
dispatcher.addReporter(anotherReporter);
|
||||||
|
|
||||||
dispatcher.foo(123, 456, completeCallback);
|
dispatcher.foo(123, 456);
|
||||||
|
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
@@ -47,7 +46,7 @@ describe('ReportDispatcher', function() {
|
|||||||
|
|
||||||
queueRunnerFactory.calls.reset();
|
queueRunnerFactory.calls.reset();
|
||||||
|
|
||||||
dispatcher.bar('a', 'b', completeCallback);
|
dispatcher.bar('a', 'b');
|
||||||
|
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
@@ -91,11 +90,10 @@ describe('ReportDispatcher', function() {
|
|||||||
['foo', 'bar'],
|
['foo', 'bar'],
|
||||||
queueRunnerFactory
|
queueRunnerFactory
|
||||||
),
|
),
|
||||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
|
||||||
completeCallback = jasmine.createSpy('complete');
|
|
||||||
|
|
||||||
dispatcher.provideFallbackReporter(reporter);
|
dispatcher.provideFallbackReporter(reporter);
|
||||||
dispatcher.foo(123, 456, completeCallback);
|
dispatcher.foo(123, 456);
|
||||||
|
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
@@ -116,12 +114,11 @@ describe('ReportDispatcher', function() {
|
|||||||
queueRunnerFactory
|
queueRunnerFactory
|
||||||
),
|
),
|
||||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||||
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']),
|
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']);
|
||||||
completeCallback = jasmine.createSpy('complete');
|
|
||||||
|
|
||||||
dispatcher.provideFallbackReporter(fallbackReporter);
|
dispatcher.provideFallbackReporter(fallbackReporter);
|
||||||
dispatcher.addReporter(reporter);
|
dispatcher.addReporter(reporter);
|
||||||
dispatcher.foo(123, 456, completeCallback);
|
dispatcher.foo(123, 456);
|
||||||
|
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
@@ -143,11 +140,10 @@ describe('ReportDispatcher', function() {
|
|||||||
queueRunnerFactory
|
queueRunnerFactory
|
||||||
),
|
),
|
||||||
reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']),
|
reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']),
|
||||||
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']),
|
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']);
|
||||||
completeCallback = jasmine.createSpy('complete');
|
|
||||||
|
|
||||||
dispatcher.addReporter(reporter1);
|
dispatcher.addReporter(reporter1);
|
||||||
dispatcher.foo(123, completeCallback);
|
dispatcher.foo(123);
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||||
@@ -161,7 +157,7 @@ describe('ReportDispatcher', function() {
|
|||||||
|
|
||||||
dispatcher.clearReporters();
|
dispatcher.clearReporters();
|
||||||
dispatcher.addReporter(reporter2);
|
dispatcher.addReporter(reporter2);
|
||||||
dispatcher.bar(456, completeCallback);
|
dispatcher.bar(456);
|
||||||
|
|
||||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ describe('TreeProcessor', function() {
|
|||||||
expect(result.valid).toBe(true);
|
expect(result.valid).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs a single leaf', function() {
|
it('runs a single leaf', async function() {
|
||||||
const leaf = new Leaf(),
|
const leaf = new Leaf(),
|
||||||
node = new Node({ children: [leaf], userContext: { root: 'context' } }),
|
node = new Node({ children: [leaf], userContext: { root: 'context' } }),
|
||||||
queueRunner = jasmine.createSpy('queueRunner'),
|
queueRunner = jasmine.createSpy('queueRunner'),
|
||||||
@@ -282,25 +282,27 @@ describe('TreeProcessor', function() {
|
|||||||
tree: node,
|
tree: node,
|
||||||
runnableIds: [leaf.id],
|
runnableIds: [leaf.id],
|
||||||
queueRunnerFactory: queueRunner
|
queueRunnerFactory: queueRunner
|
||||||
}),
|
});
|
||||||
treeComplete = jasmine.createSpy('treeComplete');
|
|
||||||
|
|
||||||
processor.execute(treeComplete);
|
const promise = processor.execute();
|
||||||
|
|
||||||
expect(queueRunner).toHaveBeenCalledWith({
|
expect(queueRunner).toHaveBeenCalledWith({
|
||||||
onComplete: treeComplete,
|
onComplete: jasmine.any(Function),
|
||||||
onException: jasmine.any(Function),
|
onException: jasmine.any(Function),
|
||||||
userContext: { root: 'context' },
|
userContext: { root: 'context' },
|
||||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||||
onMultipleDone: null
|
onMultipleDone: null
|
||||||
});
|
});
|
||||||
|
|
||||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');
|
const queueRunnerArgs = queueRunner.calls.mostRecent().args[0];
|
||||||
|
queueRunnerArgs.queueableFns[0].fn('foo');
|
||||||
expect(leaf.execute).toHaveBeenCalledWith(queueRunner, 'foo', false, false);
|
expect(leaf.execute).toHaveBeenCalledWith(queueRunner, 'foo', false, false);
|
||||||
|
|
||||||
|
queueRunnerArgs.onComplete();
|
||||||
|
await expectAsync(promise).toBeResolvedTo(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs a node with no children', function() {
|
it('runs a node with no children', async function() {
|
||||||
const node = new Node({ userContext: { node: 'context' } }),
|
const node = new Node({ userContext: { node: 'context' } }),
|
||||||
root = new Node({ children: [node], userContext: { root: 'context' } }),
|
root = new Node({ children: [node], userContext: { root: 'context' } }),
|
||||||
nodeStart = jasmine.createSpy('nodeStart'),
|
nodeStart = jasmine.createSpy('nodeStart'),
|
||||||
@@ -313,21 +315,20 @@ describe('TreeProcessor', function() {
|
|||||||
nodeComplete: nodeComplete,
|
nodeComplete: nodeComplete,
|
||||||
queueRunnerFactory: queueRunner
|
queueRunnerFactory: queueRunner
|
||||||
}),
|
}),
|
||||||
treeComplete = jasmine.createSpy('treeComplete'),
|
|
||||||
nodeDone = jasmine.createSpy('nodeDone');
|
nodeDone = jasmine.createSpy('nodeDone');
|
||||||
|
|
||||||
processor.execute(treeComplete);
|
const promise = processor.execute();
|
||||||
|
|
||||||
expect(queueRunner).toHaveBeenCalledWith({
|
expect(queueRunner).toHaveBeenCalledWith({
|
||||||
onComplete: treeComplete,
|
onComplete: jasmine.any(Function),
|
||||||
onException: jasmine.any(Function),
|
onException: jasmine.any(Function),
|
||||||
userContext: { root: 'context' },
|
userContext: { root: 'context' },
|
||||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||||
onMultipleDone: null
|
onMultipleDone: null
|
||||||
});
|
});
|
||||||
|
|
||||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn(nodeDone);
|
const queueRunnerArgs = queueRunner.calls.mostRecent().args[0];
|
||||||
|
queueRunnerArgs.queueableFns[0].fn(nodeDone);
|
||||||
expect(queueRunner).toHaveBeenCalledWith({
|
expect(queueRunner).toHaveBeenCalledWith({
|
||||||
onComplete: jasmine.any(Function),
|
onComplete: jasmine.any(Function),
|
||||||
onMultipleDone: null,
|
onMultipleDone: null,
|
||||||
@@ -348,6 +349,9 @@ describe('TreeProcessor', function() {
|
|||||||
{ my: 'result' },
|
{ my: 'result' },
|
||||||
jasmine.any(Function)
|
jasmine.any(Function)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
queueRunnerArgs.onComplete();
|
||||||
|
await expectAsync(promise).toBeResolvedTo(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs a node with children', function() {
|
it('runs a node with children', function() {
|
||||||
|
|||||||
@@ -431,11 +431,15 @@ describe('Env integration', function() {
|
|||||||
describe('Handling async errors', function() {
|
describe('Handling async errors', function() {
|
||||||
it('routes async errors to a running spec', async function() {
|
it('routes async errors to a running spec', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -468,11 +472,15 @@ describe('Env integration', function() {
|
|||||||
describe('When the running spec has reported specDone', function() {
|
describe('When the running spec has reported specDone', function() {
|
||||||
it('routes async errors to an ancestor suite', async function() {
|
it('routes async errors to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn) {
|
clearTimeout: function(fn) {
|
||||||
clearTimeout(fn);
|
clearTimeout(fn);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -524,11 +532,15 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
it('routes async errors to a running suite', async function() {
|
it('routes async errors to a running suite', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -545,8 +557,8 @@ describe('Env integration', function() {
|
|||||||
env.it('fails', function(specDone) {
|
env.it('fails', function(specDone) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
specDone();
|
specDone();
|
||||||
setTimeout(function() {
|
queueMicrotask(function() {
|
||||||
setTimeout(function() {
|
queueMicrotask(function() {
|
||||||
global.onerror('fail');
|
global.onerror('fail');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -573,11 +585,15 @@ describe('Env integration', function() {
|
|||||||
describe('When the running suite has reported suiteDone', function() {
|
describe('When the running suite has reported suiteDone', function() {
|
||||||
it('routes async errors to an ancestor suite', async function() {
|
it('routes async errors to an ancestor suite', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -633,11 +649,15 @@ describe('Env integration', function() {
|
|||||||
describe('When the env has started reporting jasmineDone', function() {
|
describe('When the env has started reporting jasmineDone', function() {
|
||||||
it('logs the error to the console', async function() {
|
it('logs the error to the console', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -672,11 +692,15 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
it('routes all errors that occur during stack clearing somewhere', async function() {
|
it('routes all errors that occur during stack clearing somewhere', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn) {
|
clearTimeout: function(fn) {
|
||||||
clearTimeout(fn);
|
clearTimeout(fn);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -1427,8 +1451,8 @@ describe('Env integration', function() {
|
|||||||
global: {
|
global: {
|
||||||
setTimeout: globalSetTimeout,
|
setTimeout: globalSetTimeout,
|
||||||
clearTimeout: clearTimeout,
|
clearTimeout: clearTimeout,
|
||||||
setImmediate: function(cb) {
|
queueMicrotask: function(fn) {
|
||||||
return setTimeout(cb, 0);
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1501,8 +1525,8 @@ describe('Env integration', function() {
|
|||||||
clearTimeout: clearTimeout,
|
clearTimeout: clearTimeout,
|
||||||
setInterval: setInterval,
|
setInterval: setInterval,
|
||||||
clearInterval: clearInterval,
|
clearInterval: clearInterval,
|
||||||
setImmediate: function(cb) {
|
queueMicrotask: function(fn) {
|
||||||
return realSetTimeout(cb, 0);
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2002,6 +2026,29 @@ describe('Env integration', function() {
|
|||||||
expect(doneArg.order.seed).toEqual('123456');
|
expect(doneArg.order.seed).toEqual('123456');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('coerces the random seed to a string if it is a number', async function() {
|
||||||
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
||||||
|
'jasmineStarted',
|
||||||
|
'jasmineDone',
|
||||||
|
'suiteStarted',
|
||||||
|
'suiteDone',
|
||||||
|
'specStarted',
|
||||||
|
'specDone'
|
||||||
|
]);
|
||||||
|
env.configure({ random: true, seed: 123456 });
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
env.configure({ random: true });
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
expect(reporter.jasmineStarted).toHaveBeenCalled();
|
||||||
|
const startedArg = reporter.jasmineStarted.calls.argsFor(0)[0];
|
||||||
|
expect(startedArg.order.seed).toEqual('123456');
|
||||||
|
|
||||||
|
const doneArg = reporter.jasmineDone.calls.argsFor(0)[0];
|
||||||
|
expect(doneArg.order.seed).toEqual('123456');
|
||||||
|
});
|
||||||
|
|
||||||
it('should report pending spec messages', async function() {
|
it('should report pending spec messages', async function() {
|
||||||
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
||||||
|
|
||||||
@@ -2619,12 +2666,16 @@ describe('Env integration', function() {
|
|||||||
|
|
||||||
it('reports errors that occur during loading', async function() {
|
it('reports errors that occur during loading', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
onerror: function() {}
|
onerror: function() {}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -2674,12 +2725,16 @@ describe('Env integration', function() {
|
|||||||
it('does not install a global error handler during loading', async function() {
|
it('does not install a global error handler during loading', async function() {
|
||||||
const originalOnerror = jasmine.createSpy('original onerror');
|
const originalOnerror = jasmine.createSpy('original onerror');
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
clearTimeout(fn, delay);
|
clearTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
},
|
||||||
onerror: originalOnerror
|
onerror: originalOnerror
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -2864,11 +2919,15 @@ describe('Env integration', function() {
|
|||||||
describe('When there are load errors', function() {
|
describe('When there are load errors', function() {
|
||||||
it('is "failed"', async function() {
|
it('is "failed"', async function() {
|
||||||
const global = {
|
const global = {
|
||||||
|
...browserEventMethods(),
|
||||||
setTimeout: function(fn, delay) {
|
setTimeout: function(fn, delay) {
|
||||||
return setTimeout(fn, delay);
|
return setTimeout(fn, delay);
|
||||||
},
|
},
|
||||||
clearTimeout: function(fn, delay) {
|
clearTimeout: function(fn, delay) {
|
||||||
return clearTimeout(fn, delay);
|
return clearTimeout(fn, delay);
|
||||||
|
},
|
||||||
|
queueMicrotask: function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||||
@@ -3906,4 +3965,49 @@ describe('Env integration', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reports a suite level error when a describe fn throws', async function() {
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
|
||||||
|
env.describe('throws before defining specs', function() {
|
||||||
|
throw new Error('nope');
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('throws after defining specs', function() {
|
||||||
|
env.it('is a spec');
|
||||||
|
throw new Error('nope');
|
||||||
|
});
|
||||||
|
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
||||||
|
jasmine.objectContaining({
|
||||||
|
fullName: 'throws after defining specs',
|
||||||
|
failedExpectations: [
|
||||||
|
jasmine.objectContaining({
|
||||||
|
message: jasmine.stringContaining('Error: nope')
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
||||||
|
jasmine.objectContaining({
|
||||||
|
fullName: 'throws after defining specs',
|
||||||
|
failedExpectations: [
|
||||||
|
jasmine.objectContaining({
|
||||||
|
message: jasmine.stringContaining('Error: nope')
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function browserEventMethods() {
|
||||||
|
return {
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,32 @@
|
|||||||
getJasmineRequireObj().clearStack = function(j$) {
|
getJasmineRequireObj().clearStack = function(j$) {
|
||||||
const maxInlineCallCount = 10;
|
const maxInlineCallCount = 10;
|
||||||
|
|
||||||
function messageChannelImpl(global, setTimeout) {
|
function browserQueueMicrotaskImpl(global) {
|
||||||
const channel = new global.MessageChannel();
|
const { setTimeout, queueMicrotask } = global;
|
||||||
|
let currentCallCount = 0;
|
||||||
|
return function clearStack(fn) {
|
||||||
|
currentCallCount++;
|
||||||
|
|
||||||
|
if (currentCallCount < maxInlineCallCount) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
} else {
|
||||||
|
currentCallCount = 0;
|
||||||
|
setTimeout(fn);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeQueueMicrotaskImpl(global) {
|
||||||
|
const { queueMicrotask } = global;
|
||||||
|
|
||||||
|
return function(fn) {
|
||||||
|
queueMicrotask(fn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageChannelImpl(global) {
|
||||||
|
const { MessageChannel, setTimeout } = global;
|
||||||
|
const channel = new MessageChannel();
|
||||||
let head = {};
|
let head = {};
|
||||||
let tail = head;
|
let tail = head;
|
||||||
|
|
||||||
@@ -13,7 +37,7 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
delete head.task;
|
delete head.task;
|
||||||
|
|
||||||
if (taskRunning) {
|
if (taskRunning) {
|
||||||
global.setTimeout(task, 0);
|
setTimeout(task, 0);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
taskRunning = true;
|
taskRunning = true;
|
||||||
@@ -39,29 +63,32 @@ getJasmineRequireObj().clearStack = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getClearStack(global) {
|
function getClearStack(global) {
|
||||||
let currentCallCount = 0;
|
const NODE_JS =
|
||||||
const realSetTimeout = global.setTimeout;
|
global.process &&
|
||||||
const setTimeoutImpl = function clearStack(fn) {
|
global.process.versions &&
|
||||||
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
|
typeof global.process.versions.node === 'string';
|
||||||
};
|
|
||||||
|
|
||||||
if (j$.isFunction_(global.setImmediate)) {
|
const SAFARI =
|
||||||
const realSetImmediate = global.setImmediate;
|
global.navigator &&
|
||||||
return function(fn) {
|
/^((?!chrome|android).)*safari/i.test(global.navigator.userAgent);
|
||||||
currentCallCount++;
|
|
||||||
|
|
||||||
if (currentCallCount < maxInlineCallCount) {
|
if (NODE_JS) {
|
||||||
realSetImmediate(fn);
|
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||||
} else {
|
// so we avoid the overhead.
|
||||||
currentCallCount = 0;
|
return nodeQueueMicrotaskImpl(global);
|
||||||
|
} else if (
|
||||||
setTimeoutImpl(fn);
|
SAFARI ||
|
||||||
}
|
j$.util.isUndefined(global.MessageChannel) /* tests */
|
||||||
};
|
) {
|
||||||
} else if (!j$.util.isUndefined(global.MessageChannel)) {
|
// queueMicrotask is dramatically faster than MessageChannel in Safari,
|
||||||
return messageChannelImpl(global, setTimeoutImpl);
|
// at least through version 16.
|
||||||
|
// Some of our own integration tests provide a mock queueMicrotask in all
|
||||||
|
// environments because it's simpler to mock than MessageChannel.
|
||||||
|
return browserQueueMicrotaskImpl(global);
|
||||||
} else {
|
} else {
|
||||||
return setTimeoutImpl;
|
// MessageChannel is faster than queueMicrotask in supported browsers
|
||||||
|
// other than Safari.
|
||||||
|
return messageChannelImpl(global);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -701,12 +701,12 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
runner.currentSpec = spec;
|
runner.currentSpec = spec;
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reporter.specStarted(spec.result, next);
|
reporter.specStarted(spec.result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportSpecDone(spec, result, next) {
|
function reportSpecDone(spec, result, next) {
|
||||||
spec.reportedDone = true;
|
spec.reportedDone = true;
|
||||||
reporter.specDone(result, next);
|
reporter.specDone(result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
|
|||||||
@@ -44,18 +44,38 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stackTrace = new j$.StackTrace(error);
|
const lines = this.stack_(error, {
|
||||||
const lines = filterJasmine(stackTrace);
|
messageHandling: omitMessage ? 'omit' : undefined
|
||||||
let result = '';
|
});
|
||||||
|
return lines.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
if (stackTrace.message && !omitMessage) {
|
// messageHandling can be falsy (unspecified), 'omit', or 'require'
|
||||||
|
this.stack_ = function(error, { messageHandling }) {
|
||||||
|
let lines = formatProperties(error).split('\n');
|
||||||
|
|
||||||
|
if (lines[lines.length - 1] === '') {
|
||||||
|
lines.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const stackTrace = new j$.StackTrace(error);
|
||||||
|
lines = lines.concat(filterJasmine(stackTrace));
|
||||||
|
|
||||||
|
if (messageHandling === 'require') {
|
||||||
|
lines.unshift(stackTrace.message || 'Error: ' + error.message);
|
||||||
|
} else if (messageHandling !== 'omit' && stackTrace.message) {
|
||||||
lines.unshift(stackTrace.message);
|
lines.unshift(stackTrace.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
result += formatProperties(error);
|
if (error.cause) {
|
||||||
result += lines.join('\n');
|
const substack = this.stack_(error.cause, {
|
||||||
|
messageHandling: 'require'
|
||||||
|
});
|
||||||
|
substack[0] = 'Caused by: ' + substack[0];
|
||||||
|
lines = lines.concat(substack);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
function filterJasmine(stackTrace) {
|
function filterJasmine(stackTrace) {
|
||||||
|
|||||||
@@ -109,21 +109,14 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (global.addEventListener) {
|
global.addEventListener('unhandledrejection', browserRejectionHandler);
|
||||||
global.addEventListener(
|
|
||||||
'unhandledrejection',
|
|
||||||
browserRejectionHandler
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.uninstall = function uninstall() {
|
this.uninstall = function uninstall() {
|
||||||
global.onerror = originalHandler;
|
global.onerror = originalHandler;
|
||||||
if (global.removeEventListener) {
|
global.removeEventListener(
|
||||||
global.removeEventListener(
|
'unhandledrejection',
|
||||||
'unhandledrejection',
|
browserRejectionHandler
|
||||||
browserRejectionHandler
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
for (const method of dispatchedMethods) {
|
for (const method of dispatchedMethods) {
|
||||||
this[method] = (function(m) {
|
this[method] = (function(m) {
|
||||||
return function() {
|
return function() {
|
||||||
dispatch(m, arguments);
|
return dispatch(m, arguments);
|
||||||
};
|
};
|
||||||
})(method);
|
})(method);
|
||||||
}
|
}
|
||||||
@@ -31,25 +31,25 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
if (reporters.length === 0 && fallbackReporter !== null) {
|
if (reporters.length === 0 && fallbackReporter !== null) {
|
||||||
reporters.push(fallbackReporter);
|
reporters.push(fallbackReporter);
|
||||||
}
|
}
|
||||||
const onComplete = args[args.length - 1];
|
|
||||||
args = Array.from(args).splice(0, args.length - 1);
|
|
||||||
const fns = [];
|
const fns = [];
|
||||||
for (const reporter of reporters) {
|
for (const reporter of reporters) {
|
||||||
addFn(fns, reporter, method, args);
|
addFn(fns, reporter, method, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueRunnerFactory({
|
return new Promise(function(resolve) {
|
||||||
queueableFns: fns,
|
queueRunnerFactory({
|
||||||
onComplete: onComplete,
|
queueableFns: fns,
|
||||||
isReporter: true,
|
onComplete: resolve,
|
||||||
onMultipleDone: function() {
|
isReporter: true,
|
||||||
onLateError(
|
onMultipleDone: function() {
|
||||||
new Error(
|
onLateError(
|
||||||
"An asynchronous reporter callback called its 'done' callback " +
|
new Error(
|
||||||
'more than once.'
|
"An asynchronous reporter callback called its 'done' callback " +
|
||||||
)
|
'more than once.'
|
||||||
);
|
)
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
this.executedBefore_ = true;
|
this.executedBefore_ = true;
|
||||||
|
|
||||||
this.hasFailures = false;
|
this.hasFailures = false;
|
||||||
const totalSpecsDefined = this.totalSpecsDefined_();
|
|
||||||
const focusedRunables = this.focusedRunables_();
|
const focusedRunables = this.focusedRunables_();
|
||||||
const config = this.getConfig_();
|
const config = this.getConfig_();
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
|
|
||||||
const order = new j$.Order({
|
const order = new j$.Order({
|
||||||
random: config.random,
|
random: config.random,
|
||||||
seed: config.seed
|
seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed
|
||||||
});
|
});
|
||||||
|
|
||||||
const processor = new j$.TreeProcessor({
|
const processor = new j$.TreeProcessor({
|
||||||
@@ -76,7 +75,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
nodeStart: (suite, next) => {
|
nodeStart: (suite, next) => {
|
||||||
this.currentlyExecutingSuites_.push(suite);
|
this.currentlyExecutingSuites_.push(suite);
|
||||||
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
this.reporter_.suiteStarted(suite.result, next);
|
this.reporter_.suiteStarted(suite.result).then(next);
|
||||||
suite.startTimer();
|
suite.startTimer();
|
||||||
},
|
},
|
||||||
nodeComplete: (suite, result, next) => {
|
nodeComplete: (suite, result, next) => {
|
||||||
@@ -114,106 +113,97 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.execute2_(runablesToRun, order, processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute2_(runablesToRun, order, processor) {
|
||||||
|
const totalSpecsDefined = this.totalSpecsDefined_();
|
||||||
|
|
||||||
this.runableResources_.initForRunable(this.topSuite_.id);
|
this.runableResources_.initForRunable(this.topSuite_.id);
|
||||||
const jasmineTimer = new j$.Timer();
|
const jasmineTimer = new j$.Timer();
|
||||||
jasmineTimer.start();
|
jasmineTimer.start();
|
||||||
|
|
||||||
return new Promise(resolve => {
|
/**
|
||||||
/**
|
* 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.
|
||||||
* @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.
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
* @since 2.0.0
|
||||||
* @since 2.0.0
|
*/
|
||||||
*/
|
await this.reporter_.jasmineStarted({
|
||||||
this.reporter_.jasmineStarted(
|
totalSpecsDefined,
|
||||||
{
|
order: order
|
||||||
totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.currentlyExecutingSuites_.push(this.topSuite_);
|
|
||||||
|
|
||||||
processor.execute(() => {
|
|
||||||
(async () => {
|
|
||||||
if (this.topSuite_.hadBeforeAllFailure) {
|
|
||||||
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.runableResources_.clearForRunable(this.topSuite_.id);
|
|
||||||
this.currentlyExecutingSuites_.pop();
|
|
||||||
let overallStatus, incompleteReason;
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.hasFailures ||
|
|
||||||
this.topSuite_.result.failedExpectations.length > 0
|
|
||||||
) {
|
|
||||||
overallStatus = 'failed';
|
|
||||||
} else if (focusedRunables.length > 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
|
||||||
} else if (totalSpecsDefined === 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'No specs found';
|
|
||||||
} else {
|
|
||||||
overallStatus = 'passed';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineDone} event.
|
|
||||||
* @typedef JasmineDoneInfo
|
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
|
||||||
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
|
||||||
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @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.
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
const jasmineDoneInfo = {
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: this.topSuite_.result.failedExpectations,
|
|
||||||
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
|
||||||
};
|
|
||||||
this.topSuite_.reportedDone = true;
|
|
||||||
this.reporter_.jasmineDone(jasmineDoneInfo, function() {
|
|
||||||
resolve(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
|
await processor.execute();
|
||||||
|
|
||||||
|
if (this.topSuite_.hadBeforeAllFailure) {
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
|
this.currentlyExecutingSuites_.pop();
|
||||||
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.hasFailures ||
|
||||||
|
this.topSuite_.result.failedExpectations.length > 0
|
||||||
|
) {
|
||||||
|
overallStatus = 'failed';
|
||||||
|
} else if (this.focusedRunables_().length > 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
|
} else if (totalSpecsDefined === 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'No specs found';
|
||||||
|
} else {
|
||||||
|
overallStatus = 'passed';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineDone} event.
|
||||||
|
* @typedef JasmineDoneInfo
|
||||||
|
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
||||||
|
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
||||||
|
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @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.
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
const jasmineDoneInfo = {
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
|
};
|
||||||
|
this.topSuite_.reportedDone = true;
|
||||||
|
await this.reporter_.jasmineDone(jasmineDoneInfo);
|
||||||
|
return jasmineDoneInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportSuiteDone_(suite, result, next) {
|
reportSuiteDone_(suite, result, next) {
|
||||||
suite.reportedDone = true;
|
suite.reportedDone = true;
|
||||||
this.reporter_.suiteDone(result, next);
|
this.reporter_.suiteDone(result).then(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
async reportChildrenOfBeforeAllFailure_(suite) {
|
async reportChildrenOfBeforeAllFailure_(suite) {
|
||||||
for (const child of suite.children) {
|
for (const child of suite.children) {
|
||||||
if (child instanceof j$.Suite) {
|
if (child instanceof j$.Suite) {
|
||||||
await new Promise(resolve => {
|
await this.reporter_.suiteStarted(child.result);
|
||||||
this.reporter_.suiteStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
await this.reportChildrenOfBeforeAllFailure_(child);
|
await this.reportChildrenOfBeforeAllFailure_(child);
|
||||||
|
|
||||||
// Marking the suite passed is consistent with how suites that
|
// Marking the suite passed is consistent with how suites that
|
||||||
// contain failed specs but no suite-level failures are reported.
|
// contain failed specs but no suite-level failures are reported.
|
||||||
child.result.status = 'passed';
|
child.result.status = 'passed';
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await this.reporter_.suiteDone(child.result);
|
||||||
this.reporter_.suiteDone(child.result, resolve);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
/* a spec */
|
/* a spec */
|
||||||
await new Promise(resolve => {
|
await this.reporter_.specStarted(child.result);
|
||||||
this.reporter_.specStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.addExpectationResult(
|
child.addExpectationResult(
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef SpecResult
|
* @typedef SpecResult
|
||||||
* @property {Int} id - The unique id of this spec.
|
* @property {String} id - The unique id of this spec.
|
||||||
* @property {String} description - The description passed to the {@link it} that created this spec.
|
* @property {String} description - The description passed to the {@link it} that created this spec.
|
||||||
* @property {String} fullName - The full description including all ancestors of this spec.
|
* @property {String} fullName - The full description including all ancestors of this spec.
|
||||||
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
Suite.prototype.reset = function() {
|
Suite.prototype.reset = function() {
|
||||||
/**
|
/**
|
||||||
* @typedef SuiteResult
|
* @typedef SuiteResult
|
||||||
* @property {Int} id - The unique id of this suite.
|
* @property {String} id - The unique id of this suite.
|
||||||
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
* @property {String} description - The description text passed to the {@link describe} that made this suite.
|
||||||
* @property {String} fullName - The full description including all ancestors of this suite.
|
* @property {String} fullName - The full description including all ancestors of this suite.
|
||||||
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
suite.exclude();
|
suite.exclude();
|
||||||
}
|
}
|
||||||
this.addSpecsToSuite_(suite, definitionFn);
|
this.addSpecsToSuite_(suite, definitionFn);
|
||||||
if (suite.parentSuite && !suite.children.length) {
|
|
||||||
throw new Error(
|
|
||||||
`describe with no children (describe() or it()): ${suite.getFullName()}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,11 +178,19 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
|
|||||||
const parentSuite = this.currentDeclarationSuite_;
|
const parentSuite = this.currentDeclarationSuite_;
|
||||||
parentSuite.addChild(suite);
|
parentSuite.addChild(suite);
|
||||||
this.currentDeclarationSuite_ = suite;
|
this.currentDeclarationSuite_ = suite;
|
||||||
|
let threw = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
definitionFn();
|
definitionFn();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
suite.handleException(e);
|
suite.handleException(e);
|
||||||
|
threw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suite.parentSuite && !suite.children.length && !threw) {
|
||||||
|
throw new Error(
|
||||||
|
`describe with no children (describe() or it()): ${suite.getFullName()}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentDeclarationSuite_ = parentSuite;
|
this.currentDeclarationSuite_ = parentSuite;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
return stats;
|
return stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.execute = function(done) {
|
this.execute = async function() {
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
this.processTree();
|
this.processTree();
|
||||||
}
|
}
|
||||||
@@ -38,16 +38,18 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
|
|
||||||
const childFns = wrapChildren(tree, 0);
|
const childFns = wrapChildren(tree, 0);
|
||||||
|
|
||||||
queueRunnerFactory({
|
await new Promise(function(resolve) {
|
||||||
queueableFns: childFns,
|
queueRunnerFactory({
|
||||||
userContext: tree.sharedUserContext(),
|
queueableFns: childFns,
|
||||||
onException: function() {
|
userContext: tree.sharedUserContext(),
|
||||||
tree.handleException.apply(tree, arguments);
|
onException: function() {
|
||||||
},
|
tree.handleException.apply(tree, arguments);
|
||||||
onComplete: done,
|
},
|
||||||
onMultipleDone: tree.onMultipleDone
|
onComplete: resolve,
|
||||||
? tree.onMultipleDone.bind(tree)
|
onMultipleDone: tree.onMultipleDone
|
||||||
: null
|
? tree.onMultipleDone.bind(tree)
|
||||||
|
: null
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -652,7 +652,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
|
|||||||
* };
|
* };
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* var actual = {
|
* const actual = {
|
||||||
* n: 2,
|
* n: 2,
|
||||||
* otherFields: "don't care"
|
* otherFields: "don't care"
|
||||||
* };
|
* };
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ getJasmineRequireObj().toHaveClass = function(j$) {
|
|||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
* @param {Object} expected - The class name to test for
|
* @param {Object} expected - The class name to test for
|
||||||
* @example
|
* @example
|
||||||
* var el = document.createElement('div');
|
* const el = document.createElement('div');
|
||||||
* el.className = 'foo bar baz';
|
* el.className = 'foo bar baz';
|
||||||
* expect(el).toHaveClass('bar');
|
* expect(el).toHaveClass('bar');
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user