Merge branch 'main' into parallel
This commit is contained in:
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.
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -2,17 +2,12 @@
|
|||||||
|
|
||||||
[](https://circleci.com/gh/jasmine/jasmine)
|
[](https://circleci.com/gh/jasmine/jasmine)
|
||||||
[](https://www.codetriage.com/jasmine/jasmine)
|
[](https://www.codetriage.com/jasmine/jasmine)
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_shield)
|
|
||||||
|
|
||||||
# A JavaScript Testing Framework
|
# A JavaScript Testing Framework
|
||||||
|
|
||||||
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
|
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
|
||||||
|
|
||||||
Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/)
|
Upgrading from Jasmine 3.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0).
|
||||||
For a quick start guide of Jasmine, see the beginning of [http://jasmine.github.io/edge/introduction.html](http://jasmine.github.io/edge/introduction.html).
|
|
||||||
|
|
||||||
Upgrading from Jasmine 3.x? Check out the 4.0 release notes for a list of
|
|
||||||
what's new (including breaking changes). You can also read the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0).
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@@ -28,7 +23,7 @@ for details.
|
|||||||
|
|
||||||
See the [documentation site](https://jasmine.github.io/pages/docs_home.html),
|
See the [documentation site](https://jasmine.github.io/pages/docs_home.html),
|
||||||
particularly the [Your First Suite tutorial](https://jasmine.github.io/tutorials/your_first_suite)
|
particularly the [Your First Suite tutorial](https://jasmine.github.io/tutorials/your_first_suite)
|
||||||
for information on writing specs.
|
for information on writing specs, and [the FAQ](https://jasmine.github.io/pages/faq.html).
|
||||||
|
|
||||||
## Supported environments
|
## Supported environments
|
||||||
|
|
||||||
@@ -47,15 +42,7 @@ For evergreen browsers, each version of Jasmine is tested against the version of
|
|||||||
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
|
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
|
||||||
However, Jasmine isn't tested against them and they aren't actively supported.
|
However, Jasmine isn't tested against them and they aren't actively supported.
|
||||||
|
|
||||||
See the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes)
|
To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
|
||||||
for the supported environments for each Jasmine release.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
* Search past discussions: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js).
|
|
||||||
* Send an email to the list: [jasmine-js@googlegroups.com](mailto:jasmine-js@googlegroups.com).
|
|
||||||
* View the project backlog at Pivotal Tracker: [http://www.pivotaltracker.com/projects/10606](http://www.pivotaltracker.com/projects/10606).
|
|
||||||
* Follow us on Twitter: [@JasmineBDD](http://twitter.com/JasmineBDD).
|
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
|
|
||||||
@@ -71,8 +58,4 @@ for the supported environments for each Jasmine release.
|
|||||||
* [Christian Williams](mailto:antixian666@gmail.com)
|
* [Christian Williams](mailto:antixian666@gmail.com)
|
||||||
* Sheel Choksi
|
* Sheel Choksi
|
||||||
|
|
||||||
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the MIT License.
|
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/MIT.LICENSE).
|
||||||
|
|
||||||
|
|
||||||
## License
|
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_large)
|
|
||||||
|
|||||||
14
RELEASE.md
14
RELEASE.md
@@ -35,11 +35,10 @@ When ready to release - specs are all green and the stories are done:
|
|||||||
|
|
||||||
### Commit and push core changes
|
### Commit and push core changes
|
||||||
|
|
||||||
1. Run the browser tests using `scripts/run-all-browsers`.
|
1. Commit release notes and version changes (jasmine.js, package.json)
|
||||||
2. Commit release notes and version changes (jasmine.js, package.json)
|
2. Push
|
||||||
3. Push
|
3. Tag the release and push the tag.
|
||||||
4. Tag the release and push the tag.
|
4. Wait for Circle CI to go green
|
||||||
5. Wait for Circle CI to go green
|
|
||||||
|
|
||||||
### Build standalone distribution
|
### Build standalone distribution
|
||||||
|
|
||||||
@@ -53,7 +52,9 @@ When ready to release - specs are all green and the stories are done:
|
|||||||
|
|
||||||
### Release the docs
|
### Release the docs
|
||||||
|
|
||||||
Probably only need to do this when releasing a minor version, and not a patch version.
|
Probably only need to do this when releasing a minor version, and not a patch
|
||||||
|
version. See [the README file in the docs repo](https://github.com/jasmine/jasmine.github.io/blob/master/README.md)
|
||||||
|
for instructions.
|
||||||
|
|
||||||
1. `rake update_edge_jasmine`
|
1. `rake update_edge_jasmine`
|
||||||
1. `npm run jsdoc`
|
1. `npm run jsdoc`
|
||||||
@@ -68,7 +69,6 @@ Probably only need to do this when releasing a minor version, and not a patch ve
|
|||||||
1. In `package.json`, update both the package version and the jasmine-core dependency version
|
1. In `package.json`, update both the package version and the jasmine-core dependency version
|
||||||
1. Commit and push.
|
1. Commit and push.
|
||||||
1. Wait for Circle CI to go green again.
|
1. Wait for Circle CI to go green again.
|
||||||
1. Run the tests on Windows locally.
|
|
||||||
1. `grunt release `. (Note: This will publish the package by running `npm publish`.)
|
1. `grunt release `. (Note: This will publish the package by running `npm publish`.)
|
||||||
|
|
||||||
### Finally
|
### Finally
|
||||||
|
|||||||
@@ -2793,8 +2793,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;
|
||||||
|
|
||||||
@@ -2805,7 +2829,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;
|
||||||
@@ -2831,29 +2855,31 @@ 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);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4059,21 +4085,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
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
40
release_notes/4.3.0.md
Normal file
40
release_notes/4.3.0.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Jasmine 4.3.0 Release Notes
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
* Added [`jasmine.spyOnGlobalErrorsAsync`](https://jasmine.github.io/api/4.3/jasmine.html#.spyOnGlobalErrorsAsync),
|
||||||
|
to better support testing code that's
|
||||||
|
expected to produce unhandled exceptions or unhandled promise rejections
|
||||||
|
* Fixes [#1843](https://github.com/jasmine/jasmine/issues/1843)
|
||||||
|
* Fixes [#1453](https://github.com/jasmine/jasmine/issues/1453)
|
||||||
|
|
||||||
|
## Documentation updates
|
||||||
|
|
||||||
|
* Updated the README to reduce redundancy and update support links
|
||||||
|
|
||||||
|
## Internal improvements
|
||||||
|
|
||||||
|
* Split `Env` into several smaller classes
|
||||||
|
* Replaced uses of `var` with `const`/`let`
|
||||||
|
* Replaced most uses of `self = this` with arrow fns
|
||||||
|
* Removed obsolete and unused utility fns
|
||||||
|
* Separated reporter- and runable-specific queue runner configuration
|
||||||
|
* Added more test coverage for default spy strategies
|
||||||
|
* Converted integration specs to `async`/`await`
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
jasmine-core 4.3.0 has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------------|--------------------|
|
||||||
|
| Node | 12.17+, 14, 16, 18 |
|
||||||
|
| Safari | 14-15 |
|
||||||
|
| Chrome | 103 |
|
||||||
|
| Firefox | 91, 102 |
|
||||||
|
| Edge | 103 |
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
@@ -25,6 +25,7 @@ passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
|||||||
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||||
run_browser chrome latest
|
run_browser chrome latest
|
||||||
run_browser firefox latest
|
run_browser firefox latest
|
||||||
|
run_browser firefox 102
|
||||||
run_browser firefox 91
|
run_browser firefox 91
|
||||||
run_browser safari 15
|
run_browser safari 15
|
||||||
run_browser safari 14
|
run_browser safari 14
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2619,12 +2643,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 +2702,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 +2896,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);
|
||||||
@@ -3910,4 +3946,11 @@ describe('Env integration', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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,31 @@ 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);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user