Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cd7d47f72 | ||
|
|
d0fe5c4712 | ||
|
|
f602c4911c | ||
|
|
7aaf7eaf30 | ||
|
|
35f16e8125 | ||
|
|
acc777c267 | ||
|
|
1c74356691 | ||
|
|
bbebea0fa5 | ||
|
|
66eb27b0af | ||
|
|
7a63c06a65 | ||
|
|
554dfd4923 | ||
|
|
36a6e2aa1d | ||
|
|
3c4b73f136 | ||
|
|
bc3ed74336 | ||
|
|
97b6f33cc2 | ||
|
|
a9889ddb31 | ||
|
|
cd1b7ce9c7 | ||
|
|
3653d6e0ef | ||
|
|
c3387f8dbf | ||
|
|
3d54184c7f | ||
|
|
6f23e706d7 | ||
|
|
cc69edf92c | ||
|
|
ba7560f65e | ||
|
|
c3960c4a96 | ||
|
|
5c21f94bb1 | ||
|
|
8cd7c94490 | ||
|
|
6a6fa7b29a | ||
|
|
4984548cab | ||
|
|
6941bde7e2 | ||
|
|
1504f25ced | ||
|
|
99e350ac85 | ||
|
|
1624b07589 | ||
|
|
d06dce4614 | ||
|
|
03098e81f8 | ||
|
|
726c152f6e | ||
|
|
409d2e29e5 | ||
|
|
01e2bd5050 | ||
|
|
96033e38ea | ||
|
|
ed75290ef7 | ||
|
|
a14dbf012a | ||
|
|
17c11ba7b9 | ||
|
|
2a1daca1ca | ||
|
|
f0db5ce350 | ||
|
|
39f9c2e1a0 | ||
|
|
bff612a169 | ||
|
|
4ba42f3746 | ||
|
|
58bee05c36 | ||
|
|
c1871b0f0c | ||
|
|
c16974b091 | ||
|
|
bfedda9764 |
@@ -4,6 +4,10 @@
|
||||
version: 2.1
|
||||
|
||||
executors:
|
||||
node22:
|
||||
docker:
|
||||
- image: cimg/node:22.0.0
|
||||
working_directory: ~/workspace
|
||||
node20:
|
||||
docker:
|
||||
- image: cimg/node:20.0.0
|
||||
@@ -94,12 +98,20 @@ workflows:
|
||||
|
||||
push:
|
||||
jobs:
|
||||
- build:
|
||||
executor: node22
|
||||
name: build_node_22
|
||||
- build:
|
||||
executor: node20
|
||||
name: build_node_20
|
||||
- build:
|
||||
executor: node18
|
||||
name: build_node_18
|
||||
- test_node:
|
||||
executor: node22
|
||||
name: test_node_22
|
||||
requires:
|
||||
- build_node_22
|
||||
- test_node:
|
||||
executor: node20
|
||||
name: test_node_20
|
||||
@@ -115,6 +127,11 @@ workflows:
|
||||
name: test_parallel_node_18
|
||||
requires:
|
||||
- build_node_18
|
||||
- test_parallel:
|
||||
executor: node22
|
||||
name: test_parallel_node_22
|
||||
requires:
|
||||
- build_node_22
|
||||
- test_parallel:
|
||||
executor: node20
|
||||
name: test_parallel_node_20
|
||||
|
||||
47
.eslintrc
Normal file
47
.eslintrc
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:compat/recommended"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es2017": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"curly": "error",
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"no-implicit-globals": "error",
|
||||
"block-spacing": "error",
|
||||
"func-call-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"key-spacing": "error",
|
||||
"no-tabs": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"space-before-blocks": "error",
|
||||
"no-eval": "error",
|
||||
"no-var": "error",
|
||||
"no-debugger": "error"
|
||||
}
|
||||
}
|
||||
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2023 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
15
README.md
15
README.md
@@ -1,13 +1,10 @@
|
||||
<a name="README">[<img src="https://rawgithub.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" />](http://jasmine.github.io)</a>
|
||||
|
||||
[](https://circleci.com/gh/jasmine/jasmine)
|
||||
[](https://www.codetriage.com/jasmine/jasmine)
|
||||
|
||||
# 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.
|
||||
|
||||
Upgrading from Jasmine 3.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0).
|
||||
Upgrading from Jasmine 4.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -32,10 +29,10 @@ Microsoft Edge) as well as Node.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|---------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | Evergreen |
|
||||
| Firefox | Evergreen, 102 |
|
||||
| Firefox | Evergreen, 102, 115 |
|
||||
| Edge | Evergreen |
|
||||
|
||||
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
|
||||
@@ -58,4 +55,6 @@ To find out what environments work with a particular Jasmine release, see the [r
|
||||
* [Christian Williams](mailto:antixian666@gmail.com)
|
||||
* Sheel Choksi
|
||||
|
||||
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/MIT.LICENSE).
|
||||
Copyright (c) 2008-2019 Pivotal Labs<br>
|
||||
Copyright (c) 2008-2023 The Jasmine developers<br>
|
||||
This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE).
|
||||
|
||||
@@ -11,7 +11,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
files: [
|
||||
{ src: [ root("MIT.LICENSE") ] },
|
||||
{ src: [ root("LICENSE") ] },
|
||||
{
|
||||
src: [ "jasmine_favicon.png"],
|
||||
dest: standaloneLibDir,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-<%= currentYear %> Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-<%= currentYear %> The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -462,7 +463,11 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
'tr',
|
||||
{},
|
||||
createDom('td', {}, entry.timestamp.toString()),
|
||||
createDom('td', {}, entry.message)
|
||||
createDom(
|
||||
'td',
|
||||
{ className: 'jasmine-debug-log-msg' },
|
||||
entry.message
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -295,4 +295,7 @@ body {
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-debug-log table, .jasmine_html-reporter .jasmine-debug-log th, .jasmine_html-reporter .jasmine-debug-log td {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-debug-log .jasmine-debug-log-msg {
|
||||
white-space: pre;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -399,9 +400,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is an instance of the specified class/constructor.
|
||||
* @name jasmine.any
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is an instance of the specified class/constructor.
|
||||
* @name asymmetricEqualityTesters.any
|
||||
* @emittedName jasmine.any
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {Constructor} clazz - The constructor to check against.
|
||||
@@ -411,9 +413,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is not `null` and not `undefined`.
|
||||
* @name jasmine.anything
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is not `null` and not `undefined`.
|
||||
* @name asymmetricEqualityTesters.anything
|
||||
* @emittedName jasmine.anything
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
*/
|
||||
@@ -422,9 +425,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is `true` or anything truthy.
|
||||
* @name jasmine.truthy
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is `true` or anything truthy.
|
||||
* @name asymmetricEqualityTesters.truthy
|
||||
* @emittedName jasmine.truthy
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -433,9 +437,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
|
||||
* @name jasmine.falsy
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is `null`, `undefined`, `0`, `false` or anything
|
||||
* falsy.
|
||||
* @name asymmetricEqualityTesters.falsy
|
||||
* @emittedName jasmine.falsy
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -444,9 +450,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is empty.
|
||||
* @name jasmine.empty
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is empty.
|
||||
* @name asymmetricEqualityTesters.empty
|
||||
* @emittedName jasmine.empty
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -455,10 +462,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher}
|
||||
* that passes if the actual value is the same as the sample as determined
|
||||
* by the `===` operator.
|
||||
* @name jasmine.is
|
||||
* Get an {@link AsymmetricEqualityTester} that passes if the actual value is
|
||||
* the same as the sample as determined by the `===` operator.
|
||||
* @name asymmetricEqualityTesters.is
|
||||
* @emittedName jasmine.is
|
||||
* @function
|
||||
* @param {Object} sample - The value to compare the actual to.
|
||||
*/
|
||||
@@ -467,9 +474,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is not empty.
|
||||
* @name jasmine.notEmpty
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is not empty.
|
||||
* @name asymmetricEqualityTesters.notEmpty
|
||||
* @emittedName jasmine.notEmpty
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -478,9 +486,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared contains at least the keys and values.
|
||||
* @name jasmine.objectContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared contains at least the specified keys and values.
|
||||
* @name asymmetricEqualityTesters.objectContaining
|
||||
* @emittedName jasmine.objectContaining
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {Object} sample - The subset of properties that _must_ be in the actual.
|
||||
@@ -490,9 +499,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
|
||||
* @name jasmine.stringMatching
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is a `String` that matches the `RegExp` or `String`.
|
||||
* @name asymmetricEqualityTesters.stringMatching
|
||||
* @emittedName jasmine.stringMatching
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
* @param {RegExp|String} expected
|
||||
@@ -502,9 +512,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is a `String` that contains the specified `String`.
|
||||
* @name jasmine.stringContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is a `String` that contains the specified `String`.
|
||||
* @name asymmetricEqualityTesters.stringContaining
|
||||
* @emittedName jasmine.stringContaining
|
||||
* @since 3.10.0
|
||||
* @function
|
||||
* @param {String} expected
|
||||
@@ -514,9 +525,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
|
||||
* @name jasmine.arrayContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is an `Array` that contains at least the elements in the sample.
|
||||
* @name asymmetricEqualityTesters.arrayContaining
|
||||
* @emittedName jasmine.arrayContaining
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
* @param {Array} sample
|
||||
@@ -526,9 +538,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
|
||||
* @name jasmine.arrayWithExactContents
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is an `Array` that contains all of the elements in the sample in
|
||||
* any order.
|
||||
* @name asymmetricEqualityTesters.arrayWithExactContents
|
||||
* @emittedName jasmine.arrayWithExactContents
|
||||
* @since 2.8.0
|
||||
* @function
|
||||
* @param {Array} sample
|
||||
@@ -538,10 +552,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if every key/value pair in the sample passes the deep equality comparison
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if every
|
||||
* key/value pair in the sample passes the deep equality comparison
|
||||
* with at least one key/value pair in the actual value being compared
|
||||
* @name jasmine.mapContaining
|
||||
* @name asymmetricEqualityTesters.mapContaining
|
||||
* @emittedName jasmine.mapContaining
|
||||
* @since 3.5.0
|
||||
* @function
|
||||
* @param {Map} sample - The subset of items that _must_ be in the actual.
|
||||
@@ -551,10 +566,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if every item in the sample passes the deep equality comparison
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if every item
|
||||
* in the sample passes the deep equality comparison
|
||||
* with at least one item in the actual value being compared
|
||||
* @name jasmine.setContaining
|
||||
* @name asymmetricEqualityTesters.setContaining
|
||||
* @emittedName jasmine.setContaining
|
||||
* @since 3.5.0
|
||||
* @function
|
||||
* @param {Set} sample - The subset of items that _must_ be in the actual.
|
||||
@@ -610,14 +626,26 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
* handling will be restored when the promise returned from the callback is
|
||||
* settled.
|
||||
*
|
||||
* When the JavaScript runtime reports an uncaught error or unhandled rejection,
|
||||
* the spy will be called with a single parameter representing Jasmine's best
|
||||
* effort at describing the error. This parameter may be of any type, because
|
||||
* JavaScript allows anything to be thrown or used as the reason for a
|
||||
* rejected promise, but Error instances and strings are most common.
|
||||
*
|
||||
* Note: The JavaScript runtime may deliver uncaught error events and unhandled
|
||||
* rejection events asynchronously, especially in browsers. If the event
|
||||
* occurs after the promise returned from the callback is settled, it won't
|
||||
* be routed to the spy even if the underlying error occurred previously.
|
||||
* It's up to you to ensure that the returned promise isn't resolved until
|
||||
* all of the error/rejection events that you want to handle have occurred.
|
||||
* It's up to you to ensure that all of the error/rejection events that you
|
||||
* want to handle have occurred before you resolve the promise returned from
|
||||
* the callback.
|
||||
*
|
||||
* You must await the return value of spyOnGlobalErrorsAsync.
|
||||
* You must ensure that the `it`/`beforeEach`/etc fn that called
|
||||
* `spyOnGlobalErrorsAsync` does not signal completion until after the
|
||||
* promise returned by `spyOnGlobalErrorsAsync` is resolved. Normally this is
|
||||
* done by `await`ing the returned promise. Leaving the global error spy
|
||||
* installed after the `it`/`beforeEach`/etc fn that installed it signals
|
||||
* completion is likely to cause problems and is not supported.
|
||||
* @name jasmine.spyOnGlobalErrorsAsync
|
||||
* @function
|
||||
* @async
|
||||
@@ -2402,7 +2430,9 @@ getJasmineRequireObj().MapContaining = function(j$) {
|
||||
}
|
||||
|
||||
MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||
if (!j$.isMap(other)) return false;
|
||||
if (!j$.isMap(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const [key, value] of this.sample) {
|
||||
// for each key/value pair in `sample`
|
||||
@@ -2541,7 +2571,9 @@ getJasmineRequireObj().SetContaining = function(j$) {
|
||||
}
|
||||
|
||||
SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||
if (!j$.isSet(other)) return false;
|
||||
if (!j$.isSet(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const item of this.sample) {
|
||||
// for each item in `sample` there should be at least one matching item in `other`
|
||||
@@ -2700,11 +2732,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
||||
} else if (options.stack) {
|
||||
error = options;
|
||||
} else {
|
||||
try {
|
||||
throw new Error(message());
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
error = new Error(message());
|
||||
}
|
||||
}
|
||||
// Omit the message from the stack trace because it will be
|
||||
@@ -2852,7 +2880,8 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
const maxInlineCallCount = 10;
|
||||
|
||||
function browserQueueMicrotaskImpl(global) {
|
||||
const { setTimeout, queueMicrotask } = global;
|
||||
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
||||
const { queueMicrotask } = global;
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
@@ -2861,7 +2890,7 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
queueMicrotask(fn);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
unclampedSetTimeout(fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2875,6 +2904,37 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
}
|
||||
|
||||
function messageChannelImpl(global) {
|
||||
const { setTimeout } = global;
|
||||
const postMessage = getPostMessage(global);
|
||||
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
postMessage(fn);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getUnclampedSetTimeout(global) {
|
||||
const { setTimeout } = global;
|
||||
if (j$.util.isUndefined(global.MessageChannel)) {
|
||||
return setTimeout;
|
||||
}
|
||||
|
||||
const postMessage = getPostMessage(global);
|
||||
return function unclampedSetTimeout(fn) {
|
||||
postMessage(function() {
|
||||
setTimeout(fn);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getPostMessage(global) {
|
||||
const { MessageChannel, setTimeout } = global;
|
||||
const channel = new MessageChannel();
|
||||
let head = {};
|
||||
@@ -2898,17 +2958,9 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
tail = tail.next = { task: fn };
|
||||
channel.port2.postMessage(0);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
}
|
||||
return function postMessage(fn) {
|
||||
tail = tail.next = { task: fn };
|
||||
channel.port2.postMessage(0);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2918,20 +2970,25 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
global.process.versions &&
|
||||
typeof global.process.versions.node === 'string';
|
||||
|
||||
const SAFARI =
|
||||
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
|
||||
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
|
||||
const SAFARI_OR_WIN_WEBKIT =
|
||||
global.navigator &&
|
||||
/^((?!chrome|android).)*safari/i.test(global.navigator.userAgent);
|
||||
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
|
||||
global.navigator.userAgent
|
||||
);
|
||||
|
||||
if (NODE_JS) {
|
||||
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||
// so we avoid the overhead.
|
||||
return nodeQueueMicrotaskImpl(global);
|
||||
} else if (
|
||||
SAFARI ||
|
||||
SAFARI_OR_WIN_WEBKIT ||
|
||||
j$.util.isUndefined(global.MessageChannel) /* tests */
|
||||
) {
|
||||
// queueMicrotask is dramatically faster than MessageChannel in Safari,
|
||||
// at least through version 16.
|
||||
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
||||
// and other WebKit-based browsers, such as the one distributed by Playwright
|
||||
// to test Safari-like behavior on Windows.
|
||||
// Some of our own integration tests provide a mock queueMicrotask in all
|
||||
// environments because it's simpler to mock than MessageChannel.
|
||||
return browserQueueMicrotaskImpl(global);
|
||||
@@ -3228,6 +3285,9 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) {
|
||||
return CompleteOnFirstErrorSkipPolicy;
|
||||
};
|
||||
|
||||
// Warning: don't add "use strict" to this file. Doing so potentially changes
|
||||
// the behavior of user code that does things like setTimeout("var x = 1;")
|
||||
// while the mock clock is installed.
|
||||
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
function DelayedFunctionScheduler() {
|
||||
this.scheduledLookup_ = [];
|
||||
@@ -3253,6 +3313,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
) {
|
||||
let f;
|
||||
if (typeof funcToCall === 'string') {
|
||||
// setTimeout("some code") and setInterval("some code") are legal, if
|
||||
// not recommended. We don't do that ourselves, but user code might.
|
||||
// This allows such code to work when the mock clock is installed.
|
||||
f = function() {
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(funcToCall);
|
||||
@@ -3652,19 +3715,24 @@ getJasmineRequireObj().Expectation = function(j$) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some context for an {@link expect}
|
||||
* Add some context to be included in matcher failures for an
|
||||
* {@link expect|expectation}, so that it can be more easily distinguished
|
||||
* from similar expectations.
|
||||
* @function
|
||||
* @name matchers#withContext
|
||||
* @since 3.3.0
|
||||
* @param {String} message - Additional context to show when the matcher fails
|
||||
* @return {matchers}
|
||||
* @example
|
||||
* expect(things[0]).withContext('thing 0').toEqual('a');
|
||||
* expect(things[1]).withContext('thing 1').toEqual('b');
|
||||
*/
|
||||
Expectation.prototype.withContext = function withContext(message) {
|
||||
return addFilter(this, new ContextAddingFilter(message));
|
||||
};
|
||||
|
||||
/**
|
||||
* Invert the matcher following this {@link expect}
|
||||
* Invert the matcher following this {@link expect|expectation}
|
||||
* @member
|
||||
* @name matchers#not
|
||||
* @since 1.3.0
|
||||
@@ -4067,6 +4135,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||
|
||||
function dispatchBrowserError(error, event) {
|
||||
if (overrideHandler) {
|
||||
// See discussion of spyOnGlobalErrorsAsync in base.js
|
||||
overrideHandler(error);
|
||||
return;
|
||||
}
|
||||
@@ -4110,6 +4179,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||
const handler = handlers[handlers.length - 1];
|
||||
|
||||
if (overrideHandler) {
|
||||
// See discussion of spyOnGlobalErrorsAsync in base.js
|
||||
overrideHandler(error);
|
||||
return;
|
||||
}
|
||||
@@ -6521,7 +6591,7 @@ getJasmineRequireObj().toHaveSize = function(j$) {
|
||||
* array = [1,2];
|
||||
* expect(array).toHaveSize(2);
|
||||
*/
|
||||
function toHaveSize() {
|
||||
function toHaveSize(matchersUtil) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
const result = {
|
||||
@@ -6536,12 +6606,29 @@ getJasmineRequireObj().toHaveSize = function(j$) {
|
||||
throw new Error('Cannot get size of ' + actual + '.');
|
||||
}
|
||||
|
||||
let actualSize;
|
||||
if (j$.isSet(actual) || j$.isMap(actual)) {
|
||||
result.pass = actual.size === expected;
|
||||
actualSize = actual.size;
|
||||
} else if (isLength(actual.length)) {
|
||||
result.pass = actual.length === expected;
|
||||
actualSize = actual.length;
|
||||
} else {
|
||||
result.pass = Object.keys(actual).length === expected;
|
||||
actualSize = Object.keys(actual).length;
|
||||
}
|
||||
|
||||
result.pass = actualSize === expected;
|
||||
|
||||
if (!result.pass) {
|
||||
result.message = function() {
|
||||
return (
|
||||
'Expected ' +
|
||||
matchersUtil.pp(actual) +
|
||||
' with size ' +
|
||||
actualSize +
|
||||
' to have size ' +
|
||||
expected +
|
||||
'.'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -6596,7 +6683,10 @@ getJasmineRequireObj().toHaveSpyInteractions = function(j$) {
|
||||
let hasSpy = false;
|
||||
const calledSpies = [];
|
||||
for (const spy of Object.values(actual)) {
|
||||
if (!j$.isSpy(spy)) continue;
|
||||
if (!j$.isSpy(spy)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasSpy = true;
|
||||
|
||||
if (spy.calls.any()) {
|
||||
@@ -7159,6 +7249,8 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @class ParallelReportDispatcher
|
||||
* @implements Reporter
|
||||
@@ -7177,7 +7269,7 @@ getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||
const dispatcher = ReportDispatcher(
|
||||
const dispatcher = new ReportDispatcher(
|
||||
j$.reporterEvents,
|
||||
function(queueRunnerOptions) {
|
||||
queueRunnerOptions = {
|
||||
@@ -7679,8 +7771,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
}
|
||||
|
||||
QueueRunner.prototype.execute = function() {
|
||||
this.handleFinalError = error => {
|
||||
this.onException(error);
|
||||
this.handleFinalError = (error, event) => {
|
||||
this.onException(errorOrMsgForGlobalError(error, event));
|
||||
};
|
||||
this.globalErrors.pushListener(this.handleFinalError);
|
||||
this.run(0);
|
||||
@@ -7710,10 +7802,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
this.recordError_(iterativeIndex);
|
||||
};
|
||||
|
||||
function handleError(error) {
|
||||
// TODO probably shouldn't next() right away here.
|
||||
// That makes debugging async failures much more confusing.
|
||||
onException(error);
|
||||
function handleError(error, event) {
|
||||
onException(errorOrMsgForGlobalError(error, event));
|
||||
}
|
||||
const cleanup = once(() => {
|
||||
if (timeoutId !== void 0) {
|
||||
@@ -7899,10 +7989,23 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
};
|
||||
}
|
||||
|
||||
function errorOrMsgForGlobalError(error, event) {
|
||||
// TODO: In cases where error is a string or undefined, the error message
|
||||
// that gets sent to reporters will be `${message} thrown`, which could
|
||||
// be improved to not say "thrown" when the cause wasn't necessarily
|
||||
// an exception or to provide hints about throwing Errors rather than
|
||||
// strings.
|
||||
return (
|
||||
error || (event && event.message) || 'Global error event with no message'
|
||||
);
|
||||
}
|
||||
|
||||
return QueueRunner;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().ReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
function ReportDispatcher(methods, queueRunnerFactory, onLateError) {
|
||||
const dispatchedMethods = methods || [];
|
||||
|
||||
@@ -7984,6 +8087,32 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().reporterEvents = function() {
|
||||
/**
|
||||
* Used to tell Jasmine what optional or uncommonly implemented features
|
||||
* the reporter supports. If not specified, the defaults described in
|
||||
* {@link ReporterCapabilities} will apply.
|
||||
* @name Reporter#reporterCapabilities
|
||||
* @type ReporterCapabilities | undefined
|
||||
* @since 5.0
|
||||
*/
|
||||
/**
|
||||
* Used to tell Jasmine what optional or uncommonly implemented features
|
||||
* the reporter supports.
|
||||
* @interface ReporterCapabilities
|
||||
* @see Reporter#reporterCapabilities
|
||||
* @since 5.0
|
||||
*/
|
||||
/**
|
||||
* Indicates whether the reporter supports parallel execution. Jasmine will
|
||||
* not allow parallel execution unless all reporters that are in use set this
|
||||
* capability to true.
|
||||
* @name ReporterCapabilities#parallel
|
||||
* @type boolean | undefined
|
||||
* @default false
|
||||
* @see running_specs_in_parallel
|
||||
* @since 5.0
|
||||
*/
|
||||
|
||||
const events = [
|
||||
/**
|
||||
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
||||
@@ -8302,7 +8431,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnlessAsync: function(actual) {
|
||||
return env.throwUnless(actual);
|
||||
return env.throwUnlessAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -8401,6 +8530,12 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
}),
|
||||
|
||||
/**
|
||||
* <p>Members of the jasmine global.</p>
|
||||
* <p>Note: The members of the
|
||||
* {@link asymmetricEqualityTesters|asymmetricEqualityTesters namespace}
|
||||
* are also accessed via the jasmine global, but due to jsdoc limitations
|
||||
* they are not listed here.</p>
|
||||
*
|
||||
* @namespace jasmine
|
||||
*/
|
||||
jasmine: jasmine
|
||||
@@ -8479,7 +8614,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @param {Function} [originalFn] - The "real" function. This will
|
||||
* be used for subsequent calls to the spy after you call
|
||||
* `mySpy.and.callThrough()`. In most cases you should omit this parameter.
|
||||
* The usual way to supply an original function is to call {@link spyOn}
|
||||
* instead of createSpy.
|
||||
* @return {Spy}
|
||||
*/
|
||||
jasmine.createSpy = function(name, originalFn) {
|
||||
@@ -8530,6 +8669,28 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.setDefaultSpyStrategy(defaultStrategyFn);
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link AsymmetricEqualityTester|Asymmetric equality testers} allow for
|
||||
* non-exact matching in matchers that use Jasmine's deep value equality
|
||||
* semantics, such as {@link matchers#toEqual|toEqual},
|
||||
* {@link matchers#toContain|toContain}, and
|
||||
* {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}.
|
||||
*
|
||||
* @example
|
||||
* const someComplexObject = {
|
||||
* foo: 'bar',
|
||||
* baz: 'a string that contains "something"',
|
||||
* qux: 'whatever'
|
||||
* };
|
||||
* // Passes.
|
||||
* expect(someComplexObject).toEqual(jasmine.objectContaining({
|
||||
* foo: 'bar',
|
||||
* baz: jasmine.stringContaining('something')
|
||||
* });
|
||||
*
|
||||
* @namespace asymmetricEqualityTesters
|
||||
*/
|
||||
|
||||
return jasmineInterface;
|
||||
};
|
||||
|
||||
@@ -9350,6 +9511,16 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
|
||||
obj[methodName] = spiedMethod;
|
||||
|
||||
// Check if setting the property actually worked. Some objects, such as
|
||||
// localStorage in Firefox and later Safari versions, have no-op setters.
|
||||
if (obj[methodName] !== spiedMethod) {
|
||||
throw new Error(
|
||||
j$.formatErrorMsg('<spyOn>')(
|
||||
`Can't spy on ${methodName} because assigning to it had no effect`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return spiedMethod;
|
||||
};
|
||||
|
||||
@@ -9735,7 +9906,7 @@ getJasmineRequireObj().StackTrace = function(j$) {
|
||||
// e.g. " at /some/path:4320:20
|
||||
{ re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' },
|
||||
|
||||
// PhantomJS on OS X, Safari, Firefox
|
||||
// Safari, most Firefox stack frames
|
||||
// e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
|
||||
// or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
|
||||
{
|
||||
@@ -9743,6 +9914,15 @@ getJasmineRequireObj().StackTrace = function(j$) {
|
||||
fnIx: 2,
|
||||
fileLineColIx: 3,
|
||||
style: 'webkit'
|
||||
},
|
||||
|
||||
// Some Firefox stack frames when the developer tools are open
|
||||
// e.g. "promise callback*specStarted@http://localhost:8888/__jasmine__/jasmine.js:1880:41"
|
||||
{
|
||||
re: /^^(?:((?:promise callback|[^\s]+ handler)\*([^@\s]+)@)|@)?([^\s]+)$/,
|
||||
fnIx: 2,
|
||||
fileLineColIx: 3,
|
||||
style: 'webkit'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -10802,5 +10982,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().version = function() {
|
||||
return '5.1.0';
|
||||
return '5.3.0';
|
||||
};
|
||||
|
||||
53
package.json
53
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "5.1.0",
|
||||
"version": "5.3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
@@ -27,7 +27,7 @@
|
||||
"homepage": "https://jasmine.github.io",
|
||||
"main": "./lib/jasmine-core.js",
|
||||
"files": [
|
||||
"MIT.LICENSE",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"images/*.{png,svg}",
|
||||
"lib/**/*.{js,css}",
|
||||
@@ -52,55 +52,6 @@
|
||||
"shelljs": "^0.8.3",
|
||||
"temp": "^0.9.0"
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"plugin:compat/recommended"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es2017": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"no-implicit-globals": "error",
|
||||
"block-spacing": "error",
|
||||
"func-call-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"key-spacing": "error",
|
||||
"no-tabs": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"space-before-blocks": "error",
|
||||
"no-eval": "error",
|
||||
"no-var": "error",
|
||||
"no-debugger": "error"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"Safari >= 15",
|
||||
"Firefox >= 102",
|
||||
|
||||
51
release_notes/4.6.1.md
Normal file
51
release_notes/4.6.1.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Jasmine Core 4.6.1 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a one-time backport of bug fixes from 5.x, for the benefit of Karma
|
||||
users who may not be aware that they're still using 4.x.
|
||||
|
||||
No further 4.x releases are planned. If possible, you should upgrade to the
|
||||
latest 5.x instead of 4.6.1. If you're using Karma, you can do this by
|
||||
installing jasmine-core 5.x and adding an override to package.json:
|
||||
|
||||
```
|
||||
{
|
||||
// ...
|
||||
"overrides": {
|
||||
"karma-jasmine": {
|
||||
"jasmine-core": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Removed unnecessary throw when building stack trace
|
||||
|
||||
* Fixed error when formatting Error object with non-Error cause property
|
||||
|
||||
Merges [#2013](https://github.com/jasmine/jasmine/pull/2013) from @angrycat9000.
|
||||
|
||||
Fixes [#2011](https://github.com/jasmine/jasmine/issues/2011).
|
||||
|
||||
* Accessibility: Always provide a non-color indication that a spec is pending
|
||||
|
||||
* Accessibility: Improved contrast of version number and inactive tab links
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 4.6.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 12.17+, 14, 16, 18 |
|
||||
| Safari | 14-16 |
|
||||
| Chrome | 125 |
|
||||
| Firefox | 91, 102, 126 |
|
||||
| Edge | 124 |
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
28
release_notes/5.1.1.md
Normal file
28
release_notes/5.1.1.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Jasmine Core 5.1.1 Release Notes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fixed global variable leak in the main process when running in parallel mode
|
||||
* Removed unnecessary throw when building expectation results
|
||||
|
||||
## Documentation Improvements
|
||||
|
||||
* Improved jsdocs for originalFn argument to createSpy
|
||||
* Link to 5.0 upgrade guide in README, not 4.0
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.1.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 116 |
|
||||
| Firefox | 102, 116 |
|
||||
| Edge | 115 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
27
release_notes/5.1.2.md
Normal file
27
release_notes/5.1.2.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Jasmine Core 5.1.2 Release Notes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fixed `throwUnlessAsync`
|
||||
* Fixes [#2026](https://github.com/jasmine/jasmine/issues/2026)
|
||||
|
||||
# Documentation improvements
|
||||
|
||||
* Added Safari 17 to supported browsers
|
||||
* Added Firefox 115 (current ESR) to supported browsers
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 121 |
|
||||
| Firefox | 102, 115, 122 |
|
||||
| Edge | 121 |
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
35
release_notes/5.2.0.md
Normal file
35
release_notes/5.2.0.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Jasmine Core 5.2.0 Release Notes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fixed stack trace filtering in FF when the developer tools are open
|
||||
* Fixed handling of browser `error` events with message but no error
|
||||
|
||||
## New Features
|
||||
|
||||
* Improved the error message of the toHaveSize matcher.
|
||||
* Merges [#2033](https://github.com/jasmine/jasmine/pull/2033) from @stephanreiter
|
||||
* HTML reporter: show debug logs with white-space: pre
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* Improved discoverability of asymmetric equality testers
|
||||
* Added an example for withContext()
|
||||
* Clarified spyOnGlobalErrorsAsync API docs
|
||||
* Added Node 22 to supported environments
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 126 |
|
||||
| Firefox | 102, 115, 128 |
|
||||
| Edge | 126 |
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
35
release_notes/5.3.0.md
Normal file
35
release_notes/5.3.0.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Jasmine Core 5.3.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Improved performance in Safari
|
||||
* Merges [#2040](https://github.com/jasmine/jasmine/pull/2040) from @dcsaszar
|
||||
* Fixes [#2008](https://github.com/jasmine/jasmine/issues/2008)
|
||||
|
||||
* Improved performance in Playwright Webkit on Windows
|
||||
* Merges [#2034](https://github.com/jasmine/jasmine/pull/2034) from @m-akinc
|
||||
|
||||
* Throw if spying has no effect, as when spying on localStorage methods in Firefox and Safari 17
|
||||
* See [#2036](https://github.com/jasmine/jasmine/issues/2036) and [#2007](https://github.com/jasmine/jasmine/issues/2007)
|
||||
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* Added API reference for reporter capabilities
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 128 |
|
||||
| Firefox | 102, 115, 130 |
|
||||
| Edge | 128 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
@@ -3,6 +3,7 @@
|
||||
run_browser() {
|
||||
browser=$1
|
||||
version=$2
|
||||
os="$3"
|
||||
description="$browser $version"
|
||||
if [ $version = "latest" ]; then
|
||||
version=""
|
||||
@@ -12,7 +13,7 @@ run_browser() {
|
||||
echo
|
||||
echo "Running $description"
|
||||
echo
|
||||
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version npm run ci
|
||||
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version SAUCE_OS="$os" npm run ci
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "PASS: $description" >> "$passfile"
|
||||
@@ -23,9 +24,21 @@ run_browser() {
|
||||
|
||||
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
run_browser chrome latest
|
||||
|
||||
# As of 2023-09-30, Sauce Connect doesn't work with the latest Chrome version
|
||||
# on the default Linux. Run on Mac OS instead. The OS specification may need to
|
||||
# be updated or removed when new Chrome versions stop being available on Mac OS
|
||||
# 12, although historically this has taken several major OS versions.
|
||||
# See <https://saucelabs.com/products/supported-browsers-devices>.
|
||||
# On Saucelabs, the test suite frequently runs ~30s slower on Mac OS than it
|
||||
# does on Linux, so it's probably worth removing the OS specification once Sauce
|
||||
# Connect works with Chrome latest on Linux again.
|
||||
run_browser chrome latest "macOS 12"
|
||||
|
||||
run_browser firefox latest
|
||||
run_browser firefox 115
|
||||
run_browser firefox 102
|
||||
run_browser safari 17
|
||||
run_browser safari 16
|
||||
run_browser safari 15
|
||||
run_browser MicrosoftEdge latest
|
||||
|
||||
@@ -20,6 +20,47 @@ describe('ClearStack', function() {
|
||||
MessageChannel: fakeMessageChannel
|
||||
};
|
||||
});
|
||||
|
||||
it('uses MessageChannel to reduce setTimeout clamping', function() {
|
||||
const fakeChannel = fakeMessageChannel();
|
||||
spyOn(fakeChannel.port2, 'postMessage');
|
||||
const queueMicrotask = jasmine.createSpy('queueMicrotask');
|
||||
const global = {
|
||||
navigator: {
|
||||
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'
|
||||
},
|
||||
MessageChannel: function() {
|
||||
return fakeChannel;
|
||||
},
|
||||
queueMicrotask
|
||||
};
|
||||
|
||||
const clearStack = jasmineUnderTest.getClearStack(global);
|
||||
|
||||
for (let i = 0; i < 9; i++) {
|
||||
clearStack(function() {});
|
||||
}
|
||||
|
||||
expect(fakeChannel.port2.postMessage).not.toHaveBeenCalled();
|
||||
|
||||
clearStack(function() {});
|
||||
|
||||
expect(fakeChannel.port2.postMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("in WebKit (Playwright's build for Windows)", function() {
|
||||
usesQueueMicrotaskWithSetTimeout(function() {
|
||||
return {
|
||||
navigator: {
|
||||
userAgent:
|
||||
'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)'
|
||||
},
|
||||
// queueMicrotask should be used even though MessageChannel is present
|
||||
MessageChannel: fakeMessageChannel
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('in browsers other than Safari', function() {
|
||||
|
||||
@@ -153,12 +153,33 @@ describe('ExceptionFormatter', function() {
|
||||
);
|
||||
});
|
||||
|
||||
it('filters Jasmine stack frames with Firefox async annotations', function() {
|
||||
const error = {
|
||||
stack:
|
||||
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
|
||||
'promise callback*fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
|
||||
'setTimeout handler*fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' +
|
||||
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28'
|
||||
};
|
||||
const subject = new jasmineUnderTest.ExceptionFormatter({
|
||||
jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js'
|
||||
});
|
||||
const result = subject.stack(error);
|
||||
expect(result).toEqual(
|
||||
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
|
||||
'<Jasmine>\n' +
|
||||
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28'
|
||||
);
|
||||
});
|
||||
|
||||
it('filters Jasmine stack frames in this environment', function() {
|
||||
const error = new Error('an error');
|
||||
const subject = new jasmineUnderTest.ExceptionFormatter({
|
||||
jasmineFile: jasmine.util.jasmineFile()
|
||||
});
|
||||
const result = subject.stack(error);
|
||||
jasmine.debugLog('Original stack trace: ' + error.stack);
|
||||
jasmine.debugLog('Filtered stack trace: ' + result);
|
||||
const lines = result.split('\n');
|
||||
|
||||
if (lines[0].match(/an error/)) {
|
||||
|
||||
@@ -328,6 +328,62 @@ describe('GlobalErrors', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Reporting uncaught exceptions in node.js', function() {
|
||||
it('prepends a descriptive message when the error is not an `Error`', function() {
|
||||
const fakeGlobal = {
|
||||
process: {
|
||||
on: jasmine.createSpy('process.on'),
|
||||
removeListener: function() {},
|
||||
listeners: function() {
|
||||
return [];
|
||||
},
|
||||
removeAllListeners: function() {}
|
||||
}
|
||||
};
|
||||
const handler = jasmine.createSpy('errorHandler');
|
||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
errors.pushListener(handler);
|
||||
|
||||
uncaughtExceptionListener(fakeGlobal)(17);
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(new Error('Uncaught exception: 17'));
|
||||
});
|
||||
|
||||
it('substitutes a descriptive message when the error is falsy', function() {
|
||||
const fakeGlobal = {
|
||||
process: {
|
||||
on: jasmine.createSpy('process.on'),
|
||||
removeListener: function() {},
|
||||
listeners: function() {
|
||||
return [];
|
||||
},
|
||||
removeAllListeners: function() {}
|
||||
}
|
||||
};
|
||||
const handler = jasmine.createSpy('errorHandler');
|
||||
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
errors.pushListener(handler);
|
||||
|
||||
uncaughtExceptionListener(fakeGlobal)();
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
new Error('Uncaught exception with no error or message')
|
||||
);
|
||||
});
|
||||
|
||||
function uncaughtExceptionListener(global) {
|
||||
// Grab the right listener
|
||||
expect(global.process.on.calls.argsFor(0)[0]).toEqual(
|
||||
'uncaughtException'
|
||||
);
|
||||
return global.process.on.calls.argsFor(0)[1];
|
||||
}
|
||||
});
|
||||
|
||||
describe('#setOverrideListener', function() {
|
||||
it('overrides the existing handlers in browsers until removed', function() {
|
||||
const fakeGlobal = browserGlobal();
|
||||
|
||||
@@ -459,6 +459,32 @@ describe('QueueRunner', function() {
|
||||
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles a global error event with a message but no error', function() {
|
||||
const queueableFn = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
fn: function(done) {
|
||||
const currentHandler = globalErrors.pushListener.calls.mostRecent()
|
||||
.args[0];
|
||||
currentHandler(undefined, { message: 'nope' });
|
||||
},
|
||||
timeout: 1
|
||||
};
|
||||
const onException = jasmine.createSpy('onException');
|
||||
const globalErrors = {
|
||||
pushListener: jasmine.createSpy('pushListener'),
|
||||
popListener: jasmine.createSpy('popListener')
|
||||
};
|
||||
const queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn],
|
||||
onException: onException,
|
||||
globalErrors: globalErrors
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
expect(onException).toHaveBeenCalledWith('nope');
|
||||
});
|
||||
|
||||
it('handles exceptions thrown while waiting for the stack to clear', function() {
|
||||
const queueableFn = {
|
||||
fn: function(done) {
|
||||
@@ -492,6 +518,40 @@ describe('QueueRunner', function() {
|
||||
clearStack.calls.argsFor(0)[0]();
|
||||
expect(onException).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('handles a global error event with no error while waiting for the stack to clear', function() {
|
||||
const queueableFn = {
|
||||
fn: function(done) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
const errorListeners = [];
|
||||
const globalErrors = {
|
||||
pushListener: function(f) {
|
||||
errorListeners.push(f);
|
||||
},
|
||||
popListener: function() {
|
||||
errorListeners.pop();
|
||||
}
|
||||
};
|
||||
const clearStack = jasmine.createSpy('clearStack');
|
||||
const onException = jasmine.createSpy('onException');
|
||||
const queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn],
|
||||
globalErrors: globalErrors,
|
||||
clearStack: clearStack,
|
||||
onException: onException
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick();
|
||||
expect(clearStack).toHaveBeenCalled();
|
||||
expect(errorListeners.length).toEqual(1);
|
||||
errorListeners[0](undefined, { message: 'nope' });
|
||||
|
||||
clearStack.calls.argsFor(0)[0]();
|
||||
expect(onException).toHaveBeenCalledWith('nope');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a function that returns a promise', function() {
|
||||
|
||||
@@ -94,6 +94,30 @@ describe('SpyRegistry', function() {
|
||||
}).not.toThrowError(/is not declared writable or has no setter/);
|
||||
});
|
||||
|
||||
it('throws if assigning to the property is a no-op', function() {
|
||||
const scope = {};
|
||||
|
||||
function original() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Object.defineProperty(scope, 'myFunc', {
|
||||
get() {
|
||||
return original;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
const spyRegistry = new jasmineUnderTest.SpyRegistry({
|
||||
createSpy: createSpy
|
||||
});
|
||||
expect(function() {
|
||||
spyRegistry.spyOn(scope, 'myFunc');
|
||||
}).toThrowError(
|
||||
"<spyOn> : Can't spy on myFunc because assigning to it had no effect"
|
||||
);
|
||||
});
|
||||
|
||||
it('overrides the method on the object and returns the spy', function() {
|
||||
const originalFunctionWasCalled = false,
|
||||
spyRegistry = new jasmineUnderTest.SpyRegistry({
|
||||
|
||||
@@ -179,7 +179,10 @@ describe('base helpers', function() {
|
||||
f2 = jasmine.createSpy('setTimeout callback for ' + (max + 1));
|
||||
|
||||
// Suppress printing of TimeoutOverflowWarning in node
|
||||
spyOn(console, 'error');
|
||||
if (typeof process !== 'undefined' && process.emitWarning) {
|
||||
spyOn(process, 'emitWarning'); // Node 22
|
||||
}
|
||||
spyOn(console, 'error'); // Node <22
|
||||
|
||||
let id = setTimeout(f1, max);
|
||||
setTimeout(function() {
|
||||
|
||||
@@ -3,7 +3,7 @@ describe('Env integration', function() {
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.getEnv().registerIntegrationMatchers();
|
||||
specHelpers.registerIntegrationMatchers();
|
||||
env = new jasmineUnderTest.Env();
|
||||
});
|
||||
|
||||
@@ -1315,8 +1315,9 @@ describe('Env integration', function() {
|
||||
'works with constructors when using callThrough spy strategy',
|
||||
function() {
|
||||
function MyClass(foo) {
|
||||
if (!(this instanceof MyClass))
|
||||
if (!(this instanceof MyClass)) {
|
||||
throw new Error('You must use the new keyword.');
|
||||
}
|
||||
this.foo = foo;
|
||||
}
|
||||
const subject = { MyClass: MyClass };
|
||||
|
||||
@@ -610,19 +610,13 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
|
||||
describe('toHaveClass', function() {
|
||||
beforeEach(function() {
|
||||
this.domHelpers = jasmine.getEnv().domHelpers();
|
||||
});
|
||||
|
||||
verifyPasses(function(env) {
|
||||
const domHelpers = jasmine.getEnv().domHelpers();
|
||||
const el = domHelpers.createElementWithClassName('foo');
|
||||
const el = specHelpers.domHelpers.createElementWithClassName('foo');
|
||||
env.expect(el).toHaveClass('foo');
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
const domHelpers = jasmine.getEnv().domHelpers();
|
||||
const el = domHelpers.createElementWithClassName('foo');
|
||||
const el = specHelpers.domHelpers.createElementWithClassName('foo');
|
||||
env.expect(el).toHaveClass('bar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ describe('spec running', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.getEnv().registerIntegrationMatchers();
|
||||
specHelpers.registerIntegrationMatchers();
|
||||
env = new jasmineUnderTest.Env();
|
||||
env.configure({ random: false });
|
||||
});
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
describe('toHaveClass', function() {
|
||||
beforeEach(function() {
|
||||
this.domHelpers = jasmine.getEnv().domHelpers();
|
||||
});
|
||||
|
||||
it('fails for a DOM element that lacks the expected class', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
result = matcher.compare(
|
||||
this.domHelpers.createElementWithClassName(''),
|
||||
specHelpers.domHelpers.createElementWithClassName(''),
|
||||
'foo'
|
||||
);
|
||||
|
||||
@@ -15,7 +11,7 @@ describe('toHaveClass', function() {
|
||||
|
||||
it('passes for a DOM element that has the expected class', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
el = this.domHelpers.createElementWithClassName('foo bar baz');
|
||||
el = specHelpers.domHelpers.createElementWithClassName('foo bar baz');
|
||||
|
||||
expect(matcher.compare(el, 'foo').pass).toBe(true);
|
||||
expect(matcher.compare(el, 'bar').pass).toBe(true);
|
||||
@@ -24,7 +20,7 @@ describe('toHaveClass', function() {
|
||||
|
||||
it('fails for a DOM element that only has other classes', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
el = this.domHelpers.createElementWithClassName('foo bar');
|
||||
el = specHelpers.domHelpers.createElementWithClassName('foo bar');
|
||||
|
||||
expect(matcher.compare(el, 'fo').pass).toBe(false);
|
||||
});
|
||||
@@ -42,7 +38,7 @@ describe('toHaveClass', function() {
|
||||
matcher.compare(undefined, 'foo');
|
||||
}).toThrowError('undefined is not a DOM element');
|
||||
|
||||
const textNode = this.domHelpers.document.createTextNode('');
|
||||
const textNode = specHelpers.domHelpers.document.createTextNode('');
|
||||
expect(function() {
|
||||
matcher.compare(textNode, 'foo');
|
||||
}).toThrowError('HTMLNode is not a DOM element');
|
||||
|
||||
@@ -15,6 +15,17 @@ describe('toHaveSize', function() {
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('informs about the size of an array whose length does not match', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveSize({
|
||||
pp: jasmineUnderTest.makePrettyPrinter()
|
||||
}),
|
||||
result = matcher.compare([1, 2, 3], 2);
|
||||
|
||||
expect(result.message()).toEqual(
|
||||
'Expected [ 1, 2, 3 ] with size 3 to have size 2.'
|
||||
);
|
||||
});
|
||||
|
||||
it('passes for an object with the proper number of keys', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveSize(),
|
||||
result = matcher.compare({ a: 1, b: 2 }, 2);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function(env) {
|
||||
(function() {
|
||||
function browserVersion(matchFn) {
|
||||
const userAgent = jasmine.getGlobal().navigator.userAgent;
|
||||
if (!userAgent) {
|
||||
@@ -10,7 +10,7 @@
|
||||
return match ? parseFloat(match[1]) : void 0;
|
||||
}
|
||||
|
||||
env.firefoxVersion = browserVersion(function(userAgent) {
|
||||
specHelpers.firefoxVersion = browserVersion(function(userAgent) {
|
||||
return /Firefox\/([0-9]{0,})/.exec(userAgent);
|
||||
});
|
||||
})(jasmine.getEnv());
|
||||
})();
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
(function(env) {
|
||||
function domHelpers() {
|
||||
let doc;
|
||||
(function() {
|
||||
let doc;
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
doc = document;
|
||||
} else {
|
||||
const JSDOM = require('jsdom').JSDOM;
|
||||
const dom = new JSDOM();
|
||||
doc = dom.window.document;
|
||||
}
|
||||
|
||||
return {
|
||||
document: doc,
|
||||
createElementWithClassName: function(className) {
|
||||
const el = this.document.createElement('div');
|
||||
el.className = className;
|
||||
return el;
|
||||
}
|
||||
};
|
||||
if (typeof document !== 'undefined') {
|
||||
doc = document;
|
||||
} else {
|
||||
const JSDOM = require('jsdom').JSDOM;
|
||||
const dom = new JSDOM();
|
||||
doc = dom.window.document;
|
||||
}
|
||||
|
||||
env.domHelpers = domHelpers;
|
||||
})(jasmine.getEnv());
|
||||
specHelpers.domHelpers = {
|
||||
document: doc,
|
||||
createElementWithClassName(className) {
|
||||
const el = this.document.createElement('div');
|
||||
el.className = className;
|
||||
return el;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
1
spec/helpers/init.js
Normal file
1
spec/helpers/init.js
Normal file
@@ -0,0 +1 @@
|
||||
globalThis.specHelpers = {};
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(env) {
|
||||
env.registerIntegrationMatchers = function() {
|
||||
(function() {
|
||||
specHelpers.registerIntegrationMatchers = function() {
|
||||
jasmine.addMatchers({
|
||||
toHaveFailedExpectationsForRunnable: function() {
|
||||
return {
|
||||
@@ -51,4 +51,4 @@
|
||||
}
|
||||
});
|
||||
};
|
||||
})(jasmine.getEnv());
|
||||
})();
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
};
|
||||
|
||||
function getSourceFiles() {
|
||||
const src_files = ['core/**/*.js', 'version.js'].map(function(file) {
|
||||
return path.join(__dirname, '../../', 'src/', file);
|
||||
});
|
||||
const globs = ['../../src/core/**/*.js', '../../src/version.js'];
|
||||
const srcFiles = globs.flatMap(g => glob.sync(g, { cwd: __dirname }));
|
||||
|
||||
const files = src_files.flatMap(g => glob.sync(g));
|
||||
files.forEach(function(resolvedFile) {
|
||||
require(resolvedFile);
|
||||
});
|
||||
for (const file of srcFiles) {
|
||||
require(file);
|
||||
}
|
||||
}
|
||||
|
||||
getSourceFiles();
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('PrettyPrinter (HTML Dependent)', function() {
|
||||
});
|
||||
|
||||
it("should print Firefox's wrapped native objects correctly", function() {
|
||||
if (jasmine.getEnv().firefoxVersion) {
|
||||
if (specHelpers.firefoxVersion) {
|
||||
const pp = jasmineUnderTest.makePrettyPrinter();
|
||||
let err;
|
||||
try {
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('npm package', function() {
|
||||
const files = fs.readdirSync(path.resolve(this.tmpDir, 'package'));
|
||||
files.sort();
|
||||
expect(files).toEqual([
|
||||
'MIT.LICENSE',
|
||||
'LICENSE',
|
||||
'README.md',
|
||||
'images',
|
||||
'lib',
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
specDir: 'spec',
|
||||
specFiles: ['**/*[Ss]pec.js', '!npmPackage/**/*'],
|
||||
helpers: [
|
||||
'helpers/init.js',
|
||||
'helpers/generator.js',
|
||||
'helpers/BrowserFlags.js',
|
||||
'helpers/domHelpers.js',
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"npmPackage/**/*[Ss]pec.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/init.js",
|
||||
"helpers/domHelpers.js",
|
||||
"helpers/integrationMatchers.js",
|
||||
"helpers/overrideConsoleLogForCircleCi.js",
|
||||
|
||||
@@ -2,7 +2,8 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
const maxInlineCallCount = 10;
|
||||
|
||||
function browserQueueMicrotaskImpl(global) {
|
||||
const { setTimeout, queueMicrotask } = global;
|
||||
const unclampedSetTimeout = getUnclampedSetTimeout(global);
|
||||
const { queueMicrotask } = global;
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
@@ -11,7 +12,7 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
queueMicrotask(fn);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
unclampedSetTimeout(fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -25,6 +26,37 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
}
|
||||
|
||||
function messageChannelImpl(global) {
|
||||
const { setTimeout } = global;
|
||||
const postMessage = getPostMessage(global);
|
||||
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
postMessage(fn);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getUnclampedSetTimeout(global) {
|
||||
const { setTimeout } = global;
|
||||
if (j$.util.isUndefined(global.MessageChannel)) {
|
||||
return setTimeout;
|
||||
}
|
||||
|
||||
const postMessage = getPostMessage(global);
|
||||
return function unclampedSetTimeout(fn) {
|
||||
postMessage(function() {
|
||||
setTimeout(fn);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getPostMessage(global) {
|
||||
const { MessageChannel, setTimeout } = global;
|
||||
const channel = new MessageChannel();
|
||||
let head = {};
|
||||
@@ -48,17 +80,9 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
let currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
tail = tail.next = { task: fn };
|
||||
channel.port2.postMessage(0);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
}
|
||||
return function postMessage(fn) {
|
||||
tail = tail.next = { task: fn };
|
||||
channel.port2.postMessage(0);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,20 +92,25 @@ getJasmineRequireObj().clearStack = function(j$) {
|
||||
global.process.versions &&
|
||||
typeof global.process.versions.node === 'string';
|
||||
|
||||
const SAFARI =
|
||||
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
|
||||
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
|
||||
const SAFARI_OR_WIN_WEBKIT =
|
||||
global.navigator &&
|
||||
/^((?!chrome|android).)*safari/i.test(global.navigator.userAgent);
|
||||
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
|
||||
global.navigator.userAgent
|
||||
);
|
||||
|
||||
if (NODE_JS) {
|
||||
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
|
||||
// so we avoid the overhead.
|
||||
return nodeQueueMicrotaskImpl(global);
|
||||
} else if (
|
||||
SAFARI ||
|
||||
SAFARI_OR_WIN_WEBKIT ||
|
||||
j$.util.isUndefined(global.MessageChannel) /* tests */
|
||||
) {
|
||||
// queueMicrotask is dramatically faster than MessageChannel in Safari,
|
||||
// at least through version 16.
|
||||
// queueMicrotask is dramatically faster than MessageChannel in Safari
|
||||
// and other WebKit-based browsers, such as the one distributed by Playwright
|
||||
// to test Safari-like behavior on Windows.
|
||||
// Some of our own integration tests provide a mock queueMicrotask in all
|
||||
// environments because it's simpler to mock than MessageChannel.
|
||||
return browserQueueMicrotaskImpl(global);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Warning: don't add "use strict" to this file. Doing so potentially changes
|
||||
// the behavior of user code that does things like setTimeout("var x = 1;")
|
||||
// while the mock clock is installed.
|
||||
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
function DelayedFunctionScheduler() {
|
||||
this.scheduledLookup_ = [];
|
||||
@@ -23,6 +26,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
) {
|
||||
let f;
|
||||
if (typeof funcToCall === 'string') {
|
||||
// setTimeout("some code") and setInterval("some code") are legal, if
|
||||
// not recommended. We don't do that ourselves, but user code might.
|
||||
// This allows such code to work when the mock clock is installed.
|
||||
f = function() {
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(funcToCall);
|
||||
|
||||
@@ -16,19 +16,24 @@ getJasmineRequireObj().Expectation = function(j$) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some context for an {@link expect}
|
||||
* Add some context to be included in matcher failures for an
|
||||
* {@link expect|expectation}, so that it can be more easily distinguished
|
||||
* from similar expectations.
|
||||
* @function
|
||||
* @name matchers#withContext
|
||||
* @since 3.3.0
|
||||
* @param {String} message - Additional context to show when the matcher fails
|
||||
* @return {matchers}
|
||||
* @example
|
||||
* expect(things[0]).withContext('thing 0').toEqual('a');
|
||||
* expect(things[1]).withContext('thing 1').toEqual('b');
|
||||
*/
|
||||
Expectation.prototype.withContext = function withContext(message) {
|
||||
return addFilter(this, new ContextAddingFilter(message));
|
||||
};
|
||||
|
||||
/**
|
||||
* Invert the matcher following this {@link expect}
|
||||
* Invert the matcher following this {@link expect|expectation}
|
||||
* @member
|
||||
* @name matchers#not
|
||||
* @since 1.3.0
|
||||
|
||||
@@ -12,6 +12,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||
|
||||
function dispatchBrowserError(error, event) {
|
||||
if (overrideHandler) {
|
||||
// See discussion of spyOnGlobalErrorsAsync in base.js
|
||||
overrideHandler(error);
|
||||
return;
|
||||
}
|
||||
@@ -55,6 +56,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||
const handler = handlers[handlers.length - 1];
|
||||
|
||||
if (overrideHandler) {
|
||||
// See discussion of spyOnGlobalErrorsAsync in base.js
|
||||
overrideHandler(error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @class ParallelReportDispatcher
|
||||
* @implements Reporter
|
||||
@@ -17,7 +19,7 @@ getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||
const dispatcher = ReportDispatcher(
|
||||
const dispatcher = new ReportDispatcher(
|
||||
j$.reporterEvents,
|
||||
function(queueRunnerOptions) {
|
||||
queueRunnerOptions = {
|
||||
|
||||
@@ -65,8 +65,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
}
|
||||
|
||||
QueueRunner.prototype.execute = function() {
|
||||
this.handleFinalError = error => {
|
||||
this.onException(error);
|
||||
this.handleFinalError = (error, event) => {
|
||||
this.onException(errorOrMsgForGlobalError(error, event));
|
||||
};
|
||||
this.globalErrors.pushListener(this.handleFinalError);
|
||||
this.run(0);
|
||||
@@ -96,10 +96,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
this.recordError_(iterativeIndex);
|
||||
};
|
||||
|
||||
function handleError(error) {
|
||||
// TODO probably shouldn't next() right away here.
|
||||
// That makes debugging async failures much more confusing.
|
||||
onException(error);
|
||||
function handleError(error, event) {
|
||||
onException(errorOrMsgForGlobalError(error, event));
|
||||
}
|
||||
const cleanup = once(() => {
|
||||
if (timeoutId !== void 0) {
|
||||
@@ -285,5 +283,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
};
|
||||
}
|
||||
|
||||
function errorOrMsgForGlobalError(error, event) {
|
||||
// TODO: In cases where error is a string or undefined, the error message
|
||||
// that gets sent to reporters will be `${message} thrown`, which could
|
||||
// be improved to not say "thrown" when the cause wasn't necessarily
|
||||
// an exception or to provide hints about throwing Errors rather than
|
||||
// strings.
|
||||
return (
|
||||
error || (event && event.message) || 'Global error event with no message'
|
||||
);
|
||||
}
|
||||
|
||||
return QueueRunner;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
getJasmineRequireObj().ReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
function ReportDispatcher(methods, queueRunnerFactory, onLateError) {
|
||||
const dispatchedMethods = methods || [];
|
||||
|
||||
|
||||
@@ -84,6 +84,16 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
|
||||
obj[methodName] = spiedMethod;
|
||||
|
||||
// Check if setting the property actually worked. Some objects, such as
|
||||
// localStorage in Firefox and later Safari versions, have no-op setters.
|
||||
if (obj[methodName] !== spiedMethod) {
|
||||
throw new Error(
|
||||
j$.formatErrorMsg('<spyOn>')(
|
||||
`Can't spy on ${methodName} because assigning to it had no effect`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return spiedMethod;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ getJasmineRequireObj().StackTrace = function(j$) {
|
||||
// e.g. " at /some/path:4320:20
|
||||
{ re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' },
|
||||
|
||||
// PhantomJS on OS X, Safari, Firefox
|
||||
// Safari, most Firefox stack frames
|
||||
// e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
|
||||
// or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
|
||||
{
|
||||
@@ -40,6 +40,15 @@ getJasmineRequireObj().StackTrace = function(j$) {
|
||||
fnIx: 2,
|
||||
fileLineColIx: 3,
|
||||
style: 'webkit'
|
||||
},
|
||||
|
||||
// Some Firefox stack frames when the developer tools are open
|
||||
// e.g. "promise callback*specStarted@http://localhost:8888/__jasmine__/jasmine.js:1880:41"
|
||||
{
|
||||
re: /^^(?:((?:promise callback|[^\s]+ handler)\*([^@\s]+)@)|@)?([^\s]+)$/,
|
||||
fnIx: 2,
|
||||
fileLineColIx: 3,
|
||||
style: 'webkit'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ getJasmineRequireObj().MapContaining = function(j$) {
|
||||
}
|
||||
|
||||
MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||
if (!j$.isMap(other)) return false;
|
||||
if (!j$.isMap(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const [key, value] of this.sample) {
|
||||
// for each key/value pair in `sample`
|
||||
|
||||
@@ -11,7 +11,9 @@ getJasmineRequireObj().SetContaining = function(j$) {
|
||||
}
|
||||
|
||||
SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
|
||||
if (!j$.isSet(other)) return false;
|
||||
if (!j$.isSet(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const item of this.sample) {
|
||||
// for each item in `sample` there should be at least one matching item in `other`
|
||||
|
||||
119
src/core/base.js
119
src/core/base.js
@@ -224,9 +224,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is an instance of the specified class/constructor.
|
||||
* @name jasmine.any
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is an instance of the specified class/constructor.
|
||||
* @name asymmetricEqualityTesters.any
|
||||
* @emittedName jasmine.any
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {Constructor} clazz - The constructor to check against.
|
||||
@@ -236,9 +237,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is not `null` and not `undefined`.
|
||||
* @name jasmine.anything
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is not `null` and not `undefined`.
|
||||
* @name asymmetricEqualityTesters.anything
|
||||
* @emittedName jasmine.anything
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
*/
|
||||
@@ -247,9 +249,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is `true` or anything truthy.
|
||||
* @name jasmine.truthy
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is `true` or anything truthy.
|
||||
* @name asymmetricEqualityTesters.truthy
|
||||
* @emittedName jasmine.truthy
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -258,9 +261,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
|
||||
* @name jasmine.falsy
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is `null`, `undefined`, `0`, `false` or anything
|
||||
* falsy.
|
||||
* @name asymmetricEqualityTesters.falsy
|
||||
* @emittedName jasmine.falsy
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -269,9 +274,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is empty.
|
||||
* @name jasmine.empty
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is empty.
|
||||
* @name asymmetricEqualityTesters.empty
|
||||
* @emittedName jasmine.empty
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -280,10 +286,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher}
|
||||
* that passes if the actual value is the same as the sample as determined
|
||||
* by the `===` operator.
|
||||
* @name jasmine.is
|
||||
* Get an {@link AsymmetricEqualityTester} that passes if the actual value is
|
||||
* the same as the sample as determined by the `===` operator.
|
||||
* @name asymmetricEqualityTesters.is
|
||||
* @emittedName jasmine.is
|
||||
* @function
|
||||
* @param {Object} sample - The value to compare the actual to.
|
||||
*/
|
||||
@@ -292,9 +298,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is not empty.
|
||||
* @name jasmine.notEmpty
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared is not empty.
|
||||
* @name asymmetricEqualityTesters.notEmpty
|
||||
* @emittedName jasmine.notEmpty
|
||||
* @since 3.1.0
|
||||
* @function
|
||||
*/
|
||||
@@ -303,9 +310,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared contains at least the keys and values.
|
||||
* @name jasmine.objectContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value being compared contains at least the specified keys and values.
|
||||
* @name asymmetricEqualityTesters.objectContaining
|
||||
* @emittedName jasmine.objectContaining
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {Object} sample - The subset of properties that _must_ be in the actual.
|
||||
@@ -315,9 +323,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
|
||||
* @name jasmine.stringMatching
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is a `String` that matches the `RegExp` or `String`.
|
||||
* @name asymmetricEqualityTesters.stringMatching
|
||||
* @emittedName jasmine.stringMatching
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
* @param {RegExp|String} expected
|
||||
@@ -327,9 +336,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is a `String` that contains the specified `String`.
|
||||
* @name jasmine.stringContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is a `String` that contains the specified `String`.
|
||||
* @name asymmetricEqualityTesters.stringContaining
|
||||
* @emittedName jasmine.stringContaining
|
||||
* @since 3.10.0
|
||||
* @function
|
||||
* @param {String} expected
|
||||
@@ -339,9 +349,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
|
||||
* @name jasmine.arrayContaining
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is an `Array` that contains at least the elements in the sample.
|
||||
* @name asymmetricEqualityTesters.arrayContaining
|
||||
* @emittedName jasmine.arrayContaining
|
||||
* @since 2.2.0
|
||||
* @function
|
||||
* @param {Array} sample
|
||||
@@ -351,9 +362,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
|
||||
* @name jasmine.arrayWithExactContents
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if the actual
|
||||
* value is an `Array` that contains all of the elements in the sample in
|
||||
* any order.
|
||||
* @name asymmetricEqualityTesters.arrayWithExactContents
|
||||
* @emittedName jasmine.arrayWithExactContents
|
||||
* @since 2.8.0
|
||||
* @function
|
||||
* @param {Array} sample
|
||||
@@ -363,10 +376,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if every key/value pair in the sample passes the deep equality comparison
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if every
|
||||
* key/value pair in the sample passes the deep equality comparison
|
||||
* with at least one key/value pair in the actual value being compared
|
||||
* @name jasmine.mapContaining
|
||||
* @name asymmetricEqualityTesters.mapContaining
|
||||
* @emittedName jasmine.mapContaining
|
||||
* @since 3.5.0
|
||||
* @function
|
||||
* @param {Map} sample - The subset of items that _must_ be in the actual.
|
||||
@@ -376,10 +390,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if every item in the sample passes the deep equality comparison
|
||||
* Get an {@link AsymmetricEqualityTester} that will succeed if every item
|
||||
* in the sample passes the deep equality comparison
|
||||
* with at least one item in the actual value being compared
|
||||
* @name jasmine.setContaining
|
||||
* @name asymmetricEqualityTesters.setContaining
|
||||
* @emittedName jasmine.setContaining
|
||||
* @since 3.5.0
|
||||
* @function
|
||||
* @param {Set} sample - The subset of items that _must_ be in the actual.
|
||||
@@ -435,14 +450,26 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
* handling will be restored when the promise returned from the callback is
|
||||
* settled.
|
||||
*
|
||||
* When the JavaScript runtime reports an uncaught error or unhandled rejection,
|
||||
* the spy will be called with a single parameter representing Jasmine's best
|
||||
* effort at describing the error. This parameter may be of any type, because
|
||||
* JavaScript allows anything to be thrown or used as the reason for a
|
||||
* rejected promise, but Error instances and strings are most common.
|
||||
*
|
||||
* Note: The JavaScript runtime may deliver uncaught error events and unhandled
|
||||
* rejection events asynchronously, especially in browsers. If the event
|
||||
* occurs after the promise returned from the callback is settled, it won't
|
||||
* be routed to the spy even if the underlying error occurred previously.
|
||||
* It's up to you to ensure that the returned promise isn't resolved until
|
||||
* all of the error/rejection events that you want to handle have occurred.
|
||||
* It's up to you to ensure that all of the error/rejection events that you
|
||||
* want to handle have occurred before you resolve the promise returned from
|
||||
* the callback.
|
||||
*
|
||||
* You must await the return value of spyOnGlobalErrorsAsync.
|
||||
* You must ensure that the `it`/`beforeEach`/etc fn that called
|
||||
* `spyOnGlobalErrorsAsync` does not signal completion until after the
|
||||
* promise returned by `spyOnGlobalErrorsAsync` is resolved. Normally this is
|
||||
* done by `await`ing the returned promise. Leaving the global error spy
|
||||
* installed after the `it`/`beforeEach`/etc fn that installed it signals
|
||||
* completion is likely to cause problems and is not supported.
|
||||
* @name jasmine.spyOnGlobalErrorsAsync
|
||||
* @function
|
||||
* @async
|
||||
|
||||
@@ -69,11 +69,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
||||
} else if (options.stack) {
|
||||
error = options;
|
||||
} else {
|
||||
try {
|
||||
throw new Error(message());
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
error = new Error(message());
|
||||
}
|
||||
}
|
||||
// Omit the message from the stack trace because it will be
|
||||
|
||||
@@ -9,7 +9,7 @@ getJasmineRequireObj().toHaveSize = function(j$) {
|
||||
* array = [1,2];
|
||||
* expect(array).toHaveSize(2);
|
||||
*/
|
||||
function toHaveSize() {
|
||||
function toHaveSize(matchersUtil) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
const result = {
|
||||
@@ -24,12 +24,29 @@ getJasmineRequireObj().toHaveSize = function(j$) {
|
||||
throw new Error('Cannot get size of ' + actual + '.');
|
||||
}
|
||||
|
||||
let actualSize;
|
||||
if (j$.isSet(actual) || j$.isMap(actual)) {
|
||||
result.pass = actual.size === expected;
|
||||
actualSize = actual.size;
|
||||
} else if (isLength(actual.length)) {
|
||||
result.pass = actual.length === expected;
|
||||
actualSize = actual.length;
|
||||
} else {
|
||||
result.pass = Object.keys(actual).length === expected;
|
||||
actualSize = Object.keys(actual).length;
|
||||
}
|
||||
|
||||
result.pass = actualSize === expected;
|
||||
|
||||
if (!result.pass) {
|
||||
result.message = function() {
|
||||
return (
|
||||
'Expected ' +
|
||||
matchersUtil.pp(actual) +
|
||||
' with size ' +
|
||||
actualSize +
|
||||
' to have size ' +
|
||||
expected +
|
||||
'.'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -32,7 +32,10 @@ getJasmineRequireObj().toHaveSpyInteractions = function(j$) {
|
||||
let hasSpy = false;
|
||||
const calledSpies = [];
|
||||
for (const spy of Object.values(actual)) {
|
||||
if (!j$.isSpy(spy)) continue;
|
||||
if (!j$.isSpy(spy)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasSpy = true;
|
||||
|
||||
if (spy.calls.any()) {
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
getJasmineRequireObj().reporterEvents = function() {
|
||||
/**
|
||||
* Used to tell Jasmine what optional or uncommonly implemented features
|
||||
* the reporter supports. If not specified, the defaults described in
|
||||
* {@link ReporterCapabilities} will apply.
|
||||
* @name Reporter#reporterCapabilities
|
||||
* @type ReporterCapabilities | undefined
|
||||
* @since 5.0
|
||||
*/
|
||||
/**
|
||||
* Used to tell Jasmine what optional or uncommonly implemented features
|
||||
* the reporter supports.
|
||||
* @interface ReporterCapabilities
|
||||
* @see Reporter#reporterCapabilities
|
||||
* @since 5.0
|
||||
*/
|
||||
/**
|
||||
* Indicates whether the reporter supports parallel execution. Jasmine will
|
||||
* not allow parallel execution unless all reporters that are in use set this
|
||||
* capability to true.
|
||||
* @name ReporterCapabilities#parallel
|
||||
* @type boolean | undefined
|
||||
* @default false
|
||||
* @see running_specs_in_parallel
|
||||
* @since 5.0
|
||||
*/
|
||||
|
||||
const events = [
|
||||
/**
|
||||
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
||||
|
||||
@@ -246,7 +246,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnlessAsync: function(actual) {
|
||||
return env.throwUnless(actual);
|
||||
return env.throwUnlessAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -345,6 +345,12 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
}),
|
||||
|
||||
/**
|
||||
* <p>Members of the jasmine global.</p>
|
||||
* <p>Note: The members of the
|
||||
* {@link asymmetricEqualityTesters|asymmetricEqualityTesters namespace}
|
||||
* are also accessed via the jasmine global, but due to jsdoc limitations
|
||||
* they are not listed here.</p>
|
||||
*
|
||||
* @namespace jasmine
|
||||
*/
|
||||
jasmine: jasmine
|
||||
@@ -423,7 +429,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @param {Function} [originalFn] - The "real" function. This will
|
||||
* be used for subsequent calls to the spy after you call
|
||||
* `mySpy.and.callThrough()`. In most cases you should omit this parameter.
|
||||
* The usual way to supply an original function is to call {@link spyOn}
|
||||
* instead of createSpy.
|
||||
* @return {Spy}
|
||||
*/
|
||||
jasmine.createSpy = function(name, originalFn) {
|
||||
@@ -474,5 +484,27 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.setDefaultSpyStrategy(defaultStrategyFn);
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link AsymmetricEqualityTester|Asymmetric equality testers} allow for
|
||||
* non-exact matching in matchers that use Jasmine's deep value equality
|
||||
* semantics, such as {@link matchers#toEqual|toEqual},
|
||||
* {@link matchers#toContain|toContain}, and
|
||||
* {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}.
|
||||
*
|
||||
* @example
|
||||
* const someComplexObject = {
|
||||
* foo: 'bar',
|
||||
* baz: 'a string that contains "something"',
|
||||
* qux: 'whatever'
|
||||
* };
|
||||
* // Passes.
|
||||
* expect(someComplexObject).toEqual(jasmine.objectContaining({
|
||||
* foo: 'bar',
|
||||
* baz: jasmine.stringContaining('something')
|
||||
* });
|
||||
*
|
||||
* @namespace asymmetricEqualityTesters
|
||||
*/
|
||||
|
||||
return jasmineInterface;
|
||||
};
|
||||
|
||||
@@ -430,7 +430,11 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
'tr',
|
||||
{},
|
||||
createDom('td', {}, entry.timestamp.toString()),
|
||||
createDom('td', {}, entry.message)
|
||||
createDom(
|
||||
'td',
|
||||
{ className: 'jasmine-debug-log-msg' },
|
||||
entry.message
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -424,5 +424,9 @@ body {
|
||||
table, th, td {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.jasmine-debug-log-msg {
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user