Compare commits
294 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7978ad9889 | ||
|
|
af4662ad31 | ||
|
|
15c38c7728 | ||
|
|
b597975c7e | ||
|
|
09ce3a30b6 | ||
|
|
3bcbc2e3af | ||
|
|
fbaba902dc | ||
|
|
bf2e8e759e | ||
|
|
50e566bd67 | ||
|
|
4b7d5e3623 | ||
|
|
6449832e7e | ||
|
|
c6266b24b7 | ||
|
|
f16b81d4ef | ||
|
|
7feec406d9 | ||
|
|
f822ffea21 | ||
|
|
db65c3b131 | ||
|
|
fd37a7eac0 | ||
|
|
12219e80c1 | ||
|
|
a980ae6bf2 | ||
|
|
56ac8f5505 | ||
|
|
3780fe0b35 | ||
|
|
164a393932 | ||
|
|
759a867094 | ||
|
|
f94d0ceda9 | ||
|
|
8d99f27be8 | ||
|
|
63774597f0 | ||
|
|
a3e1abfa12 | ||
|
|
b89a870a59 | ||
|
|
ea3fc88803 | ||
|
|
d5884e33c6 | ||
|
|
138bf9be4b | ||
|
|
98d5284c19 | ||
|
|
2299c85751 | ||
|
|
8e3ec25f6d | ||
|
|
b009cd2922 | ||
|
|
8eee6ebb91 | ||
|
|
c15a1aaa6d | ||
|
|
5b06531cac | ||
|
|
42cca93926 | ||
|
|
395ef85954 | ||
|
|
5e88fde655 | ||
|
|
bb777e93e5 | ||
|
|
9d3fb167a2 | ||
|
|
3176eaf1d8 | ||
|
|
d31a431d1f | ||
|
|
84f78c1435 | ||
|
|
ff476b1982 | ||
|
|
d53d2ff3eb | ||
|
|
adfbd00c75 | ||
|
|
495e5fcd50 | ||
|
|
bc2aa7be25 | ||
|
|
af04599bb5 | ||
|
|
21db6ec0e3 | ||
|
|
2d07b3e6d7 | ||
|
|
6891789ed2 | ||
|
|
7a3d3c9360 | ||
|
|
1b2922e008 | ||
|
|
bd8d23f2a7 | ||
|
|
de26763868 | ||
|
|
f4be08b657 | ||
|
|
50ef882a1a | ||
|
|
c1cd5c6291 | ||
|
|
63ed2b3948 | ||
|
|
0183acc682 | ||
|
|
e15819c0dd | ||
|
|
f694194b2b | ||
|
|
94c00886a6 | ||
|
|
f5915d7963 | ||
|
|
15587f3ce3 | ||
|
|
3ecddc2555 | ||
|
|
6a7c0e6368 | ||
|
|
84daa0f5dc | ||
|
|
c6b3e947e9 | ||
|
|
0e604de0db | ||
|
|
e7ca9c5765 | ||
|
|
cbff6f95cb | ||
|
|
361640f52e | ||
|
|
e5d46e8624 | ||
|
|
8f6b3c49cc | ||
|
|
df6ab05280 | ||
|
|
9ea027dbff | ||
|
|
7cc7da4abc | ||
|
|
8be98e73ca | ||
|
|
52aaf63d22 | ||
|
|
a09fdd3284 | ||
|
|
89f3e9449d | ||
|
|
ba033c520d | ||
|
|
fc935e89c6 | ||
|
|
4bd2feda7d | ||
|
|
bcf699f145 | ||
|
|
d4f29491c9 | ||
|
|
5b1c932f89 | ||
|
|
7a8d6e44e3 | ||
|
|
dac349397e | ||
|
|
5ff7e7f9a1 | ||
|
|
7b2ab822c6 | ||
|
|
033260300a | ||
|
|
cb66b54f8b | ||
|
|
f4a8102a80 | ||
|
|
8f539f17b2 | ||
|
|
e5c543a0a1 | ||
|
|
7d697faf95 | ||
|
|
6f23151a5e | ||
|
|
e53c7ed8d1 | ||
|
|
dcd44a0edf | ||
|
|
f0a5ea9d0f | ||
|
|
491b513aa3 | ||
|
|
d5872bba66 | ||
|
|
c4f4edda1b | ||
|
|
cf057b6631 | ||
|
|
2a7a157713 | ||
|
|
7463fe511b | ||
|
|
1b724daa10 | ||
|
|
888d3b6250 | ||
|
|
289afbf0a6 | ||
|
|
9b89bee4f5 | ||
|
|
3f8f488a58 | ||
|
|
592d47e971 | ||
|
|
4732012f1c | ||
|
|
7683325d68 | ||
|
|
03d665e243 | ||
|
|
a1591da25d | ||
|
|
1f1e1209d2 | ||
|
|
a389905a38 | ||
|
|
36dd6b07d1 | ||
|
|
2f3689713b | ||
|
|
819fab7b58 | ||
|
|
e5ca1f37f1 | ||
|
|
c3650ea7c7 | ||
|
|
1805337424 | ||
|
|
27bb6ebac1 | ||
|
|
580323c221 | ||
|
|
d9286c549f | ||
|
|
26dfa6d257 | ||
|
|
483d4ab3c3 | ||
|
|
663dfe5932 | ||
|
|
ce9c752899 | ||
|
|
d5e7bc9fd6 | ||
|
|
744e765d6f | ||
|
|
29551ba4f3 | ||
|
|
bd9a3b2305 | ||
|
|
c8c3325b56 | ||
|
|
84c7e2b21b | ||
|
|
dda25bb29e | ||
|
|
9ccf2ef96b | ||
|
|
c6fa55bfc8 | ||
|
|
06bcf1c2e1 | ||
|
|
40f402d117 | ||
|
|
71f6a95ce5 | ||
|
|
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 | ||
|
|
a67b7276be | ||
|
|
47f3105ef0 | ||
|
|
aeb56539c9 | ||
|
|
75d45efa16 | ||
|
|
59d1c5bebb | ||
|
|
040983c979 | ||
|
|
2ddb344bac | ||
|
|
e56bd3918b | ||
|
|
59600a1c29 | ||
|
|
f8e4ea868f | ||
|
|
0ff56c53b1 | ||
|
|
b617d983de | ||
|
|
8e0f0e8e8c | ||
|
|
d745d6b5f0 | ||
|
|
fc2c2a477d | ||
|
|
ff93277c0f | ||
|
|
90741b3cee | ||
|
|
d1de59f0ed | ||
|
|
73f8e001ad | ||
|
|
390cc45af2 | ||
|
|
33118ac6e2 | ||
|
|
31ff9a300c | ||
|
|
5cc739d879 | ||
|
|
1e7f07259e | ||
|
|
c36a5cfd96 | ||
|
|
299fd1f770 | ||
|
|
656427d328 | ||
|
|
621522fdd4 | ||
|
|
6e3589bf52 | ||
|
|
df2d9b282e | ||
|
|
726d35c5c5 | ||
|
|
f509078020 | ||
|
|
8308515210 | ||
|
|
ed838b3cbf | ||
|
|
04fac300e8 | ||
|
|
ff237f4b66 | ||
|
|
e42e3d9e00 | ||
|
|
61505f4c59 | ||
|
|
86eddb05b4 | ||
|
|
8af5509581 | ||
|
|
166e5f4d6c | ||
|
|
6ad8d20694 | ||
|
|
cbc03feb52 | ||
|
|
bc3a495160 | ||
|
|
b323631611 | ||
|
|
e8767ba660 | ||
|
|
af9a4114f4 | ||
|
|
75f97961f5 | ||
|
|
25a7168286 | ||
|
|
494e81f436 | ||
|
|
169a2a8ad2 | ||
|
|
b267029301 | ||
|
|
cf574634b8 | ||
|
|
f8c01574e6 | ||
|
|
481f1e7c5c | ||
|
|
5e650953cd | ||
|
|
ed5e902106 | ||
|
|
87f9ab29df | ||
|
|
47c64a86d5 | ||
|
|
bb497beeff | ||
|
|
e14d9c4be3 | ||
|
|
89e0b35c53 | ||
|
|
1e7b68236b | ||
|
|
394068f863 | ||
|
|
b831e81074 | ||
|
|
4c13c2b00b | ||
|
|
dd98a45003 | ||
|
|
fe6762b470 | ||
|
|
fa16b74500 | ||
|
|
4cd190b232 | ||
|
|
6ada55ff77 | ||
|
|
735ce6f758 | ||
|
|
430324885b | ||
|
|
7c2e8ce7ca | ||
|
|
d4025999b7 | ||
|
|
871111424d | ||
|
|
44f331f43d | ||
|
|
213144413f | ||
|
|
2272f9aead | ||
|
|
59848ca151 | ||
|
|
c14bfe3e5f | ||
|
|
4c8d57e14c | ||
|
|
543689e206 | ||
|
|
ee524831f4 | ||
|
|
b3d9435dbb | ||
|
|
fec8dd37b0 | ||
|
|
0690500a0d | ||
|
|
0bfbda720d | ||
|
|
4fcdbd39fb | ||
|
|
2e80ec0c22 | ||
|
|
588283cfe5 | ||
|
|
3a43871901 | ||
|
|
fcbab02b2d | ||
|
|
5f3475342e | ||
|
|
21f25972bb |
@@ -4,25 +4,21 @@
|
||||
version: 2.1
|
||||
|
||||
executors:
|
||||
node24:
|
||||
docker:
|
||||
- image: cimg/node:24.0.0
|
||||
working_directory: ~/workspace
|
||||
node22:
|
||||
docker:
|
||||
- image: cimg/node:22.0.0
|
||||
working_directory: ~/workspace
|
||||
node20:
|
||||
docker:
|
||||
- image: cimg/node:20.0.0
|
||||
working_directory: ~/workspace
|
||||
node18:
|
||||
docker:
|
||||
- image: cimg/node:18.0.0 # Latest 18.x
|
||||
working_directory: ~/workspace
|
||||
node16:
|
||||
docker:
|
||||
- image: cimg/node:16.14.2 # Latest 16.x
|
||||
working_directory: ~/workspace
|
||||
node14:
|
||||
docker:
|
||||
- image: cimg/node:14.17.4 # Latest 14.x
|
||||
working_directory: ~/workspace
|
||||
node12_latest:
|
||||
docker:
|
||||
- image: cimg/node:12.22.10 # Latest 12.x
|
||||
working_directory: ~/workspace
|
||||
node12_17:
|
||||
docker:
|
||||
- image: cimg/node:12.17.0 # Oldest version supported by Jasmine
|
||||
- image: cimg/node:18.20.5
|
||||
working_directory: ~/workspace
|
||||
|
||||
jobs:
|
||||
@@ -59,20 +55,34 @@ jobs:
|
||||
name: Run tests
|
||||
command: npm test
|
||||
|
||||
test_parallel: &test_parallel
|
||||
parameters:
|
||||
executor:
|
||||
type: executor
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Run tests in parallel
|
||||
command: npm run test:parallel
|
||||
|
||||
test_browsers: &test_browsers
|
||||
executor: node14
|
||||
executor: node18
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Install Sauce Connect
|
||||
command: |
|
||||
cd /tmp
|
||||
curl https://saucelabs.com/downloads/sc-4.7.1-linux.tar.gz | tar zxf -
|
||||
chmod +x sc-4.7.1-linux/bin/sc
|
||||
tmpdir=$(mktemp -d)
|
||||
cd "$tmpdir"
|
||||
curl https://saucelabs.com/downloads/sauce-connect/5.2.2/sauce-connect-5.2.2_linux.x86_64.tar.gz | tar zxf -
|
||||
chmod +x sc
|
||||
mkdir ~/workspace/bin
|
||||
cp sc-4.7.1-linux/bin/sc ~/workspace/bin
|
||||
~/workspace/bin/sc --version
|
||||
cp sc ~/workspace/bin
|
||||
echo "Sauce Connect version info:"
|
||||
~/workspace/bin/sc version
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
@@ -80,13 +90,13 @@ jobs:
|
||||
# cleanly if we kill it from a different step than it started in.
|
||||
|
||||
export PATH=$PATH:$HOME/workspace/bin
|
||||
export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_BUILD_NUM
|
||||
scripts/start-sauce-connect sauce-pidfile
|
||||
export SAUCE_TUNNEL_NAME=$CIRCLE_WORKFLOW_JOB_ID
|
||||
scripts/start-sauce-connect
|
||||
set +o errexit
|
||||
scripts/run-all-browsers
|
||||
exitcode=$?
|
||||
set -o errexit
|
||||
scripts/stop-sauce-connect $(cat sauce-pidfile)
|
||||
scripts/stop-sauce-connect
|
||||
exit $exitcode
|
||||
|
||||
workflows:
|
||||
@@ -94,49 +104,56 @@ workflows:
|
||||
|
||||
push:
|
||||
jobs:
|
||||
- build:
|
||||
executor: node24
|
||||
name: build_node_24
|
||||
- build:
|
||||
executor: node22
|
||||
name: build_node_22
|
||||
- build:
|
||||
executor: node20
|
||||
name: build_node_20
|
||||
- build:
|
||||
executor: node18
|
||||
name: build_node_18
|
||||
- build:
|
||||
executor: node16
|
||||
name: build_node_16
|
||||
- build:
|
||||
executor: node14
|
||||
name: build_node_14
|
||||
- build:
|
||||
executor: node12_latest
|
||||
name: build_node_12_latest
|
||||
- build:
|
||||
executor: node12_17
|
||||
name: build_node_12_17
|
||||
- test_node:
|
||||
executor: node22
|
||||
name: test_node_22
|
||||
requires:
|
||||
- build_node_22
|
||||
- test_node:
|
||||
executor: node20
|
||||
name: test_node_20
|
||||
requires:
|
||||
- build_node_20
|
||||
- test_node:
|
||||
executor: node18
|
||||
name: test_node_18
|
||||
requires:
|
||||
- build_node_18
|
||||
- test_node:
|
||||
executor: node16
|
||||
name: test_node_16
|
||||
- build_node_18
|
||||
- test_parallel:
|
||||
executor: node24
|
||||
name: test_parallel_node_24
|
||||
requires:
|
||||
- build_node_16
|
||||
- test_node:
|
||||
executor: node14
|
||||
name: test_node_14
|
||||
- build_node_24
|
||||
- test_parallel:
|
||||
executor: node22
|
||||
name: test_parallel_node_22
|
||||
requires:
|
||||
- build_node_14
|
||||
- test_node:
|
||||
executor: node12_latest
|
||||
name: test_node_12_latest
|
||||
- build_node_22
|
||||
- test_parallel:
|
||||
executor: node20
|
||||
name: test_parallel_node_20
|
||||
requires:
|
||||
- build_node_12_latest
|
||||
- test_node:
|
||||
executor: node12_17
|
||||
name: test_node_12_17
|
||||
- build_node_20
|
||||
- test_parallel:
|
||||
executor: node18
|
||||
name: test_parallel_node_18
|
||||
requires:
|
||||
- build_node_12_17
|
||||
- build_node_18
|
||||
- test_browsers:
|
||||
requires:
|
||||
- build_node_14
|
||||
- build_node_18
|
||||
filters:
|
||||
branches:
|
||||
ignore: /pull\/.*/ # Don't run on pull requests.
|
||||
|
||||
@@ -3,6 +3,6 @@ charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{js, json, sh, yml}]
|
||||
[*.{js,mjs,json,sh,yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
47
.github/ISSUE_TEMPLATE.md
vendored
47
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,47 +0,0 @@
|
||||
## Are you creating an issue in the correct repository?
|
||||
|
||||
- When in doubt, create an issue here.
|
||||
- If you have an issue with the Jasmine docs, file an issue in the docs repo
|
||||
here: https://github.com/jasmine/jasmine.github.io
|
||||
- If you have an issue with TypeScript typings, start a discussion at
|
||||
[DefinitelyTpyed](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/new?category=issues-with-a-types-package)
|
||||
- This repository is for the core Jasmine framework
|
||||
- If you are using a test runner that wraps Jasmine, consider filing an issue with that library if appropriate:
|
||||
- [Jasmine npm](https://github.com/jasmine/jasmine-npm/issues)
|
||||
- [Jasmine browser runner](https://github.com/jasmine/jasmine-browser/issues)
|
||||
- [Jasmine gem](https://github.com/jasmine/jasmine-gem/issues)
|
||||
- [Jasmine py](https://github.com/jasmine/jasmine-py/issues)
|
||||
- [Gulp Jasmine Browser](https://github.com/jasmine/gulp-jasmine-browser/issues)
|
||||
- [Karma](https://github.com/karma-runner/karma/issues)
|
||||
- [Grunt Contrib Jasmine](https://github.com/gruntjs/grunt-contrib-jasmine/issues)
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
## Suite that reproduces the behavior (for bugs)
|
||||
<!--- Provide a sample suite that reproduces the bug. -->
|
||||
```javascript
|
||||
describe("sample", function() {
|
||||
});
|
||||
```
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* Version used:
|
||||
* Environment name and version (e.g. Chrome 39, node.js 5.4):
|
||||
* Operating System and version (desktop or mobile):
|
||||
* Link to your project:
|
||||
95
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
95
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: Bug Report
|
||||
description: I think I've found a bug in Jasmine
|
||||
labels: ["bug report"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to report a bug. Please follow these steps first.
|
||||
|
||||
## Troubleshooting
|
||||
Please take the time to rule out issues with your code or third party libraries before filing a bug report. If you are reporting an error, try to determine whether the error is coming from Jasmine, another library, or your own code.
|
||||
|
||||
Check the [FAQ](https://jasmine.github.io/pages/faq.html) and any other relevant [documentation](https://jasmine.github.io/pages/docs_home.html) to see if your issue has already been addressed.
|
||||
|
||||
## Special troubleshooting steps for asynchronous scenarios
|
||||
If the issue has to do with testing asynchronous code, please read the [async tutorial](https://jasmine.github.io/tutorials/async) and the [async section of the FAQ](https://jasmine.github.io/pages/faq.html#async). In particular, check for the following common errors:
|
||||
|
||||
* Are you trying to write a synchronous test for asynchronous code?
|
||||
* Does the test signal completion before the code under test finishes?
|
||||
* Do expectations run before the code that they're trying to verify?
|
||||
|
||||
## Try the latest version of Jasmine
|
||||
If at all possible, upgrade to the latest versions of `jasmine-core` and any other relevant packages (e.g. `jasmine`, `jasmine-browser-runner`). If you can't do that, please check the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes) for all newer versions to make sure that the bug hasn't already been fixed.
|
||||
|
||||
## Explain how to reproduce the bug
|
||||
|
||||
**Working steps to reproduce are required for all bug reports.** Please help us help you by creating complete but minimal instructions for reproducing the bug.
|
||||
|
||||
The steps to reproduce could be:
|
||||
|
||||
* A code snippet that reproduces the problem when run by itself in a newly generated empty `jasmine` or `jasmine-browser-runner` project, or in the standalone distribution.
|
||||
* A set of steps that reproduce the problem when followed exactly as they're written in an empty directory.
|
||||
* A link to a Git repository or zip/tar file containing a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). This option is required for all bugs that can only be reproduced with third-party libraries, including Angular and Karma.
|
||||
|
||||
Please **test your steps** by starting with an empty directory and following them exactly as they're written. Bug reports with steps to reproduce that are unclear, don't work, or include an unreasonable amount of extraneous code will likely be closed.
|
||||
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What do you think should have happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
description: What happened instead?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: possible-solution
|
||||
attributes:
|
||||
label: Possible Solution
|
||||
description: This is optional, but if you have an idea for how to fix the bug we'd like to hear it.
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: How has this issue affected you? What are you trying to accomplish? By providing context, you can help us come up with a solution that is most useful in the real world.
|
||||
- type: input
|
||||
id: jasmine-core-version
|
||||
attributes:
|
||||
label: jasmine-core version
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: other-versions
|
||||
attributes:
|
||||
label: Versions of other relevant packages
|
||||
placeholder: |
|
||||
jasmine-browser-runner 1.2.0
|
||||
fancy-reporter 132.4.8
|
||||
|
||||
- type: input
|
||||
id: browser-or-node-version
|
||||
attributes:
|
||||
label: Node.js and/or browser version
|
||||
placeholder: E.g. "node 16.2.0" or "Safari 15"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
placeholder: E.g. "Windows 10", "MacOS 12.5", "MCC Interim Linux 0.99.p8"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions, requests for help, etc
|
||||
url: https://github.com/jasmine/jasmine/discussions/new/choose
|
||||
about: Please start a discussion.
|
||||
- name: Issues with the `jasmine` CLI
|
||||
url: https://github.com/jasmine/jasmine-npm/issues
|
||||
about: Please create issues related to the `jasmine` package in its repository.
|
||||
- name: Issues with jasmine-browser-runner
|
||||
url: https://github.com/jasmine/jasmine-browser-runner/issues
|
||||
about: Please create issues related to the `jasmine-browser-runner` package in its repository.
|
||||
- name: Documentation issues
|
||||
url: https://github.com/jasmine/jasmine.github.io/issues
|
||||
about: Please create documentation issues in the docs repository.
|
||||
- name: TypeScript issues
|
||||
url: https://github.com/DefinitelyTyped/DefinitelyTyped/discussions
|
||||
about: Please create issues related to TypeScript compilation errors or other problems with type definitions at DefinitelyTyped.
|
||||
31
.github/ISSUE_TEMPLATE/feature_proposal.yml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/feature_proposal.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Feature Proposal
|
||||
description: I'd like to propose a new feature
|
||||
labels: ["feature request"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Thanks for taking the time to propose a new feature. Although Jasmine is mostly feature complete, we're always open to hearing new ideas.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Feature Proposal
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: How would this feature be useful to you? What are you trying to accomplish? By providing context, you can help us come up with a solution that is most useful in the real world.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Example
|
||||
description: If you're proposing a new API or something similar, please show an example of how it would be used.
|
||||
render: JavaScript
|
||||
- type: textarea
|
||||
id: other-info
|
||||
attributes:
|
||||
label: Other Information
|
||||
description: Anything else that you think would be helpful.
|
||||
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"singleQuote": true
|
||||
}
|
||||
66
Gruntfile.js
66
Gruntfile.js
@@ -1,66 +0,0 @@
|
||||
module.exports = function(grunt) {
|
||||
var pkg = require("./package.json");
|
||||
global.jasmineVersion = pkg.version;
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: pkg,
|
||||
concat: require('./grunt/config/concat.js'),
|
||||
sass: require('./grunt/config/sass.js'),
|
||||
compress: require('./grunt/config/compress.js'),
|
||||
cssUrlEmbed: require('./grunt/config/cssUrlEmbed.js')
|
||||
});
|
||||
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
grunt.loadTasks('grunt/tasks');
|
||||
|
||||
grunt.registerTask('default', ['sass:dist', "cssUrlEmbed"]);
|
||||
|
||||
grunt.registerTask('buildDistribution',
|
||||
'Builds and lints jasmine.js, jasmine-html.js, jasmine.css',
|
||||
[
|
||||
'sass:dist',
|
||||
"cssUrlEmbed",
|
||||
'concat'
|
||||
]
|
||||
);
|
||||
|
||||
grunt.registerTask("execSpecsInNode",
|
||||
"Run Jasmine core specs in Node.js",
|
||||
function() {
|
||||
verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals());
|
||||
const done = this.async(),
|
||||
Jasmine = require('jasmine'),
|
||||
jasmineCore = require('./lib/jasmine-core.js'),
|
||||
jasmine = new Jasmine({jasmineCore: jasmineCore});
|
||||
|
||||
jasmine.loadConfigFile('./spec/support/jasmine.json');
|
||||
jasmine.exitOnCompletion = false;
|
||||
jasmine.execute().then(
|
||||
result => done(result.overallStatus === 'passed'),
|
||||
err => {
|
||||
console.error(err);
|
||||
exit(1);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("execSpecsInNode:performance",
|
||||
"Run Jasmine performance specs in Node.js",
|
||||
function() {
|
||||
require("shelljs").exec("node_modules/.bin/jasmine JASMINE_CONFIG_PATH=spec/support/jasmine-performance.json");
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function verifyNoGlobals(fn) {
|
||||
const initialGlobals = Object.keys(global);
|
||||
fn();
|
||||
|
||||
const extras = Object.keys(global).filter(k => !initialGlobals.includes(k));
|
||||
|
||||
if (extras.length !== 0) {
|
||||
throw new Error('Globals were unexpectedly created: ' + extras.join(', '));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2025 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
29
README.md
29
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 name="README"><img src="https://raw.githubusercontent.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" alt="Jasmine"></a>
|
||||
|
||||
# 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
|
||||
|
||||
@@ -30,18 +27,22 @@ for information on writing specs, and [the FAQ](https://jasmine.github.io/pages/
|
||||
Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and
|
||||
Microsoft Edge) as well as Node.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 12.17+, 14, 16, 18 |
|
||||
| Safari | 14-15 |
|
||||
| Chrome | Evergreen |
|
||||
| Firefox | Evergreen, 91 |
|
||||
| Edge | Evergreen |
|
||||
| Environment | Supported versions |
|
||||
|-------------------|----------------------------------|
|
||||
| Node | 18.20.5+*, 20, 22, 24 |
|
||||
| Safari | 15*, 16*, 17* |
|
||||
| Chrome | Evergreen |
|
||||
| Firefox | Evergreen, 102*, 115*, 128*, 140 |
|
||||
| Edge | Evergreen |
|
||||
|
||||
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
|
||||
at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
|
||||
However, Jasmine isn't tested against them and they aren't actively supported.
|
||||
|
||||
\* Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
|
||||
|
||||
## Maintainers
|
||||
@@ -58,4 +59,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-2025 The Jasmine developers<br>
|
||||
This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE).
|
||||
|
||||
39
RELEASE.md
39
RELEASE.md
@@ -18,12 +18,11 @@ copied to `jasmine.js` when the distribution is built. When releasing a new
|
||||
version, update `package.json` with the new version and `npm run build` to
|
||||
update the gem version number.
|
||||
|
||||
Note that Jasmine should only use the "patch" version number in the following cases:
|
||||
Note that Jasmine should only use the "patch" version number if the new release
|
||||
contains only bug fixes.
|
||||
|
||||
* Changes related to packaging for a specific binding library (npm or browser-runner)
|
||||
* Fixes for regressions.
|
||||
|
||||
When jasmine-core revs its major or minor version, the binding libraries should also rev to that version.
|
||||
When `jasmine-core` revs its major or minor version, the `jasmine` NPM package
|
||||
should also rev to that version.
|
||||
|
||||
## Release
|
||||
|
||||
@@ -42,13 +41,13 @@ When ready to release - specs are all green and the stories are done:
|
||||
|
||||
### Build standalone distribution
|
||||
|
||||
1. Build the standalone distribution with `grunt buildStandaloneDist`
|
||||
1. Build the standalone distribution with `npm run buildStandaloneDist`
|
||||
1. This will generate `dist/jasmine-standalone-<version>.zip`, which you will upload later (see "Finally" below).
|
||||
|
||||
### Release the core NPM module
|
||||
|
||||
1. `npm adduser` to save your credentials locally
|
||||
1. `npm publish .` to publish what's in `package.json`
|
||||
1. `npm login` to save your credentials locally
|
||||
2. `npm publish .` to publish what's in `package.json`
|
||||
|
||||
### Release the docs
|
||||
|
||||
@@ -56,25 +55,13 @@ Probably only need to do this when releasing a minor version, and not a patch
|
||||
version. See [the README file in the docs repo](https://github.com/jasmine/jasmine.github.io/blob/master/README.md)
|
||||
for instructions.
|
||||
|
||||
1. `rake update_edge_jasmine`
|
||||
1. `npm run jsdoc`
|
||||
1. `rake release[${version}]` to copy the current edge docs to the new version
|
||||
1. Commit and push.
|
||||
### Release the `jasmine` NPM package
|
||||
|
||||
### Release the binding libraries
|
||||
See <https://github.com/jasmine/jasmine-npm/blob/main/RELEASE.md>.
|
||||
|
||||
#### NPM
|
||||
### Publish the GitHub release
|
||||
|
||||
1. Create release notes using Anchorman as above
|
||||
1. In `package.json`, update both the package version and the jasmine-core dependency version
|
||||
1. Commit and push.
|
||||
1. Wait for Circle CI to go green again.
|
||||
1. `grunt release `. (Note: This will publish the package by running `npm publish`.)
|
||||
|
||||
### Finally
|
||||
|
||||
For each of the above GitHub repos:
|
||||
1. Visit the releases page and find the tag just published.
|
||||
1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes.
|
||||
1. If it is a pre-release, mark it as such.
|
||||
1. For core, attach the standalone zipfile.
|
||||
2. Paste in a link to the correct release notes for this release.
|
||||
3. If it is a pre-release, mark it as such.
|
||||
4. Attach the standalone zipfile.
|
||||
|
||||
56
eslint.config.mjs
Normal file
56
eslint.config.mjs
Normal file
@@ -0,0 +1,56 @@
|
||||
import { defineConfig } from "eslint/config";
|
||||
import globals from "globals";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default defineConfig([{
|
||||
extends: compat.extends("plugin:compat/recommended"),
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
|
||||
// 2022 isn't exactly right, but it's the earliest version that allows
|
||||
// private properties.
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "commonjs",
|
||||
},
|
||||
|
||||
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",
|
||||
"no-console": "error",
|
||||
},
|
||||
}]);
|
||||
@@ -1,57 +0,0 @@
|
||||
var standaloneLibDir = "lib/jasmine-" + jasmineVersion;
|
||||
|
||||
function root(path) { return "./" + path; }
|
||||
function libJasmineCore(path) { return root("lib/jasmine-core/" + path); }
|
||||
function dist(path) { return root("dist/" + path); }
|
||||
|
||||
module.exports = {
|
||||
standalone: {
|
||||
options: {
|
||||
archive: root("dist/jasmine-standalone-" + global.jasmineVersion + ".zip")
|
||||
},
|
||||
|
||||
files: [
|
||||
{ src: [ root("MIT.LICENSE") ] },
|
||||
{
|
||||
src: [ "jasmine_favicon.png"],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: root("images")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"jasmine.js",
|
||||
"jasmine-html.js",
|
||||
"jasmine.css"
|
||||
],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: libJasmineCore("")
|
||||
},
|
||||
{
|
||||
src: [ "boot0.js", "boot1.js" ],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: libJasmineCore("")
|
||||
},
|
||||
{
|
||||
src: [ "SpecRunner.html" ],
|
||||
dest: root(""),
|
||||
expand: true,
|
||||
cwd: dist("tmp")
|
||||
},
|
||||
{
|
||||
src: [ "*.js" ],
|
||||
dest: "src",
|
||||
expand: true,
|
||||
cwd: libJasmineCore("example/src/")
|
||||
},
|
||||
{
|
||||
src: [ "*.js" ],
|
||||
dest: "spec",
|
||||
expand: true,
|
||||
cwd: libJasmineCore("example/spec/")
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
var grunt = require('grunt');
|
||||
|
||||
function license() {
|
||||
var currentYear = "" + new Date(Date.now()).getFullYear();
|
||||
|
||||
return grunt.template.process(
|
||||
grunt.file.read("grunt/templates/licenseBanner.js.jst"),
|
||||
{ data: { currentYear: currentYear}});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'jasmine-html': {
|
||||
src: [
|
||||
'src/html/requireHtml.js',
|
||||
'src/html/HtmlReporter.js',
|
||||
'src/html/HtmlSpecFilter.js',
|
||||
'src/html/ResultsNode.js',
|
||||
'src/html/QueryString.js',
|
||||
'src/html/**/*.js'
|
||||
],
|
||||
dest: 'lib/jasmine-core/jasmine-html.js'
|
||||
},
|
||||
jasmine: {
|
||||
src: [
|
||||
'src/core/requireCore.js',
|
||||
'src/core/matchers/requireMatchers.js',
|
||||
'src/core/base.js',
|
||||
'src/core/util.js',
|
||||
'src/core/Spec.js',
|
||||
'src/core/Order.js',
|
||||
'src/core/Env.js',
|
||||
'src/core/JsApiReporter.js',
|
||||
'src/core/PrettyPrinter',
|
||||
'src/core/Suite',
|
||||
'src/core/**/*.js',
|
||||
'src/version.js'
|
||||
],
|
||||
dest: 'lib/jasmine-core/jasmine.js'
|
||||
},
|
||||
boot0: {
|
||||
src: ['src/boot/boot0.js'],
|
||||
dest: 'lib/jasmine-core/boot0.js'
|
||||
},
|
||||
boot1: {
|
||||
src: ['src/boot/boot1.js'],
|
||||
dest: 'lib/jasmine-core/boot1.js'
|
||||
},
|
||||
nodeBoot: {
|
||||
src: ['src/boot/node_boot.js'],
|
||||
dest: 'lib/jasmine-core/node_boot.js'
|
||||
},
|
||||
options: {
|
||||
banner: license(),
|
||||
process: {
|
||||
data: {
|
||||
version: global.jasmineVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
encodeWithBaseDir: {
|
||||
files: {
|
||||
"lib/jasmine-core/jasmine.css": ["lib/jasmine-core/jasmine.css"]
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
const sass = require('sass');
|
||||
|
||||
module.exports = {
|
||||
options: {
|
||||
implementation: sass,
|
||||
sourceComments: false
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
"lib/jasmine-core/jasmine.css": "src/html/jasmine.scss"
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
var grunt = require("grunt");
|
||||
|
||||
function standaloneTmpDir(path) { return "dist/tmp/" + path; }
|
||||
|
||||
grunt.registerTask("build:compileSpecRunner",
|
||||
"Processes the spec runner template and writes to a tmp file",
|
||||
function() {
|
||||
var runnerHtml = grunt.template.process(
|
||||
grunt.file.read("grunt/templates/SpecRunner.html.jst"),
|
||||
{ data: { jasmineVersion: global.jasmineVersion }});
|
||||
|
||||
grunt.file.write(standaloneTmpDir("SpecRunner.html"), runnerHtml);
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("build:cleanSpecRunner",
|
||||
"Deletes the tmp spec runner file",
|
||||
function() {
|
||||
grunt.file.delete(standaloneTmpDir(""));
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("buildStandaloneDist",
|
||||
"Builds a standalone distribution",
|
||||
[
|
||||
"buildDistribution",
|
||||
"build:compileSpecRunner",
|
||||
"compress:standalone",
|
||||
"build:cleanSpecRunner"
|
||||
]
|
||||
);
|
||||
@@ -6,47 +6,61 @@
|
||||
const jasmineRequire = require('./jasmine-core/jasmine.js');
|
||||
module.exports = jasmineRequire;
|
||||
|
||||
/**
|
||||
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
|
||||
* @type {function}
|
||||
* @return {jasmine}
|
||||
*/
|
||||
module.exports.boot = require('./jasmine-core/node_boot.js');
|
||||
const boot = (function() {
|
||||
let jasmine, jasmineInterface;
|
||||
|
||||
/**
|
||||
* Boots a copy of Jasmine and returns an object containing the properties
|
||||
* that would normally be added to the global object. If noGlobals is called
|
||||
* multiple times, the same object is returned every time.
|
||||
*
|
||||
* Do not call boot() if you also call noGlobals().
|
||||
*
|
||||
* @example
|
||||
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
|
||||
*/
|
||||
module.exports.noGlobals = (function() {
|
||||
let jasmineInterface;
|
||||
|
||||
return function bootWithoutGlobals() {
|
||||
if (!jasmineInterface) {
|
||||
const jasmine = jasmineRequire.core(jasmineRequire);
|
||||
return function bootWithoutGlobals(reinitialize) {
|
||||
if (!jasmineInterface || reinitialize === true) {
|
||||
jasmine = jasmineRequire.core(jasmineRequire);
|
||||
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||
jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
}
|
||||
|
||||
return jasmineInterface;
|
||||
return {jasmine, jasmineInterface};
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
|
||||
* If boot is called multiple times, the same object is returned every time
|
||||
* unless true is passed.
|
||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
||||
* @type {function}
|
||||
* @return {jasmine}
|
||||
*/
|
||||
module.exports.boot = function(reinitialize) {
|
||||
const {jasmine, jasmineInterface} = boot(reinitialize);
|
||||
|
||||
for (const k in jasmineInterface) {
|
||||
global[k] = jasmineInterface[k];
|
||||
}
|
||||
|
||||
return jasmine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Boots a copy of Jasmine and returns an object containing the properties
|
||||
* that would normally be added to the global object. If noGlobals is called
|
||||
* multiple times, the same object is returned every time unless true is passed.
|
||||
*
|
||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
||||
* @example
|
||||
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
|
||||
*/
|
||||
module.exports.noGlobals = function(reinitialize) {
|
||||
const {jasmineInterface} = boot(reinitialize);
|
||||
return jasmineInterface;
|
||||
};
|
||||
|
||||
const path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
const rootPath = path.join(__dirname, 'jasmine-core'),
|
||||
bootFiles = ['boot0.js', 'boot1.js'],
|
||||
legacyBootFiles = ['boot.js'],
|
||||
nodeBootFiles = ['node_boot.js'],
|
||||
cssFiles = [],
|
||||
jsFiles = [],
|
||||
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles, nodeBootFiles);
|
||||
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles);
|
||||
|
||||
fs.readdirSync(rootPath).forEach(function(file) {
|
||||
if(fs.statSync(path.join(rootPath, file)).isFile()) {
|
||||
@@ -56,18 +70,18 @@ fs.readdirSync(rootPath).forEach(function(file) {
|
||||
break;
|
||||
case '.js':
|
||||
if (jsFilesToSkip.indexOf(file) < 0) {
|
||||
jsFiles.push(file);
|
||||
}
|
||||
jsFiles.push(file);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports.files = {
|
||||
self: __filename,
|
||||
path: rootPath,
|
||||
bootDir: rootPath,
|
||||
bootFiles: bootFiles,
|
||||
nodeBootFiles: nodeBootFiles,
|
||||
cssFiles: cssFiles,
|
||||
jsFiles: ['jasmine.js'].concat(jsFiles),
|
||||
imagesDir: path.join(__dirname, '../images')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2022 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2025 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -20,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
This file starts the process of "booting" Jasmine. It initializes Jasmine,
|
||||
makes its globals available, and creates the env. This file should be loaded
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2022 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2025 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -20,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
This file finishes 'booting' Jasmine, performing all of the necessary
|
||||
initialization before executing the loaded environment and all of a project's
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
function Player() {
|
||||
}
|
||||
Player.prototype.play = function(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.pause = function() {
|
||||
this.isPlaying = false;
|
||||
};
|
||||
|
||||
Player.prototype.resume = function() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error("song is already playing");
|
||||
class Player {
|
||||
play(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
};
|
||||
pause() {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
Player.prototype.makeFavorite = function() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
};
|
||||
resume() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error('song is already playing');
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
}
|
||||
|
||||
makeFavorite() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Player;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
function Song() {
|
||||
class Song {
|
||||
persistFavoriteStatus(value) {
|
||||
// something complicated
|
||||
throw new Error('not yet implemented');
|
||||
}
|
||||
}
|
||||
|
||||
Song.prototype.persistFavoriteStatus = function(value) {
|
||||
// something complicated
|
||||
throw new Error("not yet implemented");
|
||||
};
|
||||
|
||||
module.exports = Song;
|
||||
|
||||
@@ -3,11 +3,11 @@ beforeEach(function () {
|
||||
toBePlaying: function () {
|
||||
return {
|
||||
compare: function (actual, expected) {
|
||||
var player = actual;
|
||||
const player = actual;
|
||||
|
||||
return {
|
||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
describe("Player", function() {
|
||||
var Player = require('../../lib/jasmine_examples/Player');
|
||||
var Song = require('../../lib/jasmine_examples/Song');
|
||||
var player;
|
||||
var song;
|
||||
const Player = require('../../lib/jasmine_examples/Player');
|
||||
const Song = require('../../lib/jasmine_examples/Song');
|
||||
|
||||
describe('Player', function() {
|
||||
let player;
|
||||
let song;
|
||||
|
||||
beforeEach(function() {
|
||||
player = new Player();
|
||||
song = new Song();
|
||||
});
|
||||
|
||||
it("should be able to play a Song", function() {
|
||||
it('should be able to play a Song', function() {
|
||||
player.play(song);
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
|
||||
//demonstrates use of custom matcher
|
||||
// demonstrates use of custom matcher
|
||||
expect(player).toBePlaying(song);
|
||||
});
|
||||
|
||||
describe("when song has been paused", function() {
|
||||
describe('when song has been paused', function() {
|
||||
beforeEach(function() {
|
||||
player.play(song);
|
||||
player.pause();
|
||||
});
|
||||
|
||||
it("should indicate that the song is currently paused", function() {
|
||||
it('should indicate that the song is currently paused', function() {
|
||||
expect(player.isPlaying).toBeFalsy();
|
||||
|
||||
// demonstrates use of 'not' with a custom matcher
|
||||
expect(player).not.toBePlaying(song);
|
||||
});
|
||||
|
||||
it("should be possible to resume", function() {
|
||||
it('should be possible to resume', function() {
|
||||
player.resume();
|
||||
expect(player.isPlaying).toBeTruthy();
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
@@ -38,7 +39,7 @@ describe("Player", function() {
|
||||
});
|
||||
|
||||
// demonstrates use of spies to intercept and test method calls
|
||||
it("tells the current song if the user has made it a favorite", function() {
|
||||
it('tells the current song if the user has made it a favorite', function() {
|
||||
spyOn(song, 'persistFavoriteStatus');
|
||||
|
||||
player.play(song);
|
||||
@@ -48,13 +49,13 @@ describe("Player", function() {
|
||||
});
|
||||
|
||||
//demonstrates use of expected exceptions
|
||||
describe("#resume", function() {
|
||||
it("should throw an exception if song is already playing", function() {
|
||||
describe('#resume', function() {
|
||||
it('should throw an exception if song is already playing', function() {
|
||||
player.play(song);
|
||||
|
||||
expect(function() {
|
||||
player.resume();
|
||||
}).toThrowError("song is already playing");
|
||||
}).toThrowError('song is already playing');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
describe("Player", function() {
|
||||
var player;
|
||||
var song;
|
||||
describe('Player', function() {
|
||||
let player;
|
||||
let song;
|
||||
|
||||
beforeEach(function() {
|
||||
player = new Player();
|
||||
song = new Song();
|
||||
});
|
||||
|
||||
it("should be able to play a Song", function() {
|
||||
it('should be able to play a Song', function() {
|
||||
player.play(song);
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
|
||||
//demonstrates use of custom matcher
|
||||
// demonstrates use of custom matcher
|
||||
expect(player).toBePlaying(song);
|
||||
});
|
||||
|
||||
describe("when song has been paused", function() {
|
||||
describe('when song has been paused', function() {
|
||||
beforeEach(function() {
|
||||
player.play(song);
|
||||
player.pause();
|
||||
});
|
||||
|
||||
it("should indicate that the song is currently paused", function() {
|
||||
it('should indicate that the song is currently paused', function() {
|
||||
expect(player.isPlaying).toBeFalsy();
|
||||
|
||||
// demonstrates use of 'not' with a custom matcher
|
||||
expect(player).not.toBePlaying(song);
|
||||
});
|
||||
|
||||
it("should be possible to resume", function() {
|
||||
it('should be possible to resume', function() {
|
||||
player.resume();
|
||||
expect(player.isPlaying).toBeTruthy();
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
@@ -36,7 +36,7 @@ describe("Player", function() {
|
||||
});
|
||||
|
||||
// demonstrates use of spies to intercept and test method calls
|
||||
it("tells the current song if the user has made it a favorite", function() {
|
||||
it('tells the current song if the user has made it a favorite', function() {
|
||||
spyOn(song, 'persistFavoriteStatus');
|
||||
|
||||
player.play(song);
|
||||
@@ -46,13 +46,13 @@ describe("Player", function() {
|
||||
});
|
||||
|
||||
//demonstrates use of expected exceptions
|
||||
describe("#resume", function() {
|
||||
it("should throw an exception if song is already playing", function() {
|
||||
describe('#resume', function() {
|
||||
it('should throw an exception if song is already playing', function() {
|
||||
player.play(song);
|
||||
|
||||
expect(function() {
|
||||
player.resume();
|
||||
}).toThrowError("song is already playing");
|
||||
}).toThrowError('song is already playing');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ beforeEach(function () {
|
||||
toBePlaying: function () {
|
||||
return {
|
||||
compare: function (actual, expected) {
|
||||
var player = actual;
|
||||
const player = actual;
|
||||
|
||||
return {
|
||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
function Player() {
|
||||
}
|
||||
Player.prototype.play = function(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.pause = function() {
|
||||
this.isPlaying = false;
|
||||
};
|
||||
|
||||
Player.prototype.resume = function() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error("song is already playing");
|
||||
class Player {
|
||||
play(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
};
|
||||
pause() {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
Player.prototype.makeFavorite = function() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
};
|
||||
resume() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error('song is already playing');
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
}
|
||||
|
||||
makeFavorite() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
function Song() {
|
||||
class Song {
|
||||
persistFavoriteStatus(value) {
|
||||
// something complicated
|
||||
throw new Error('not yet implemented');
|
||||
}
|
||||
}
|
||||
|
||||
Song.prototype.persistFavoriteStatus = function(value) {
|
||||
// something complicated
|
||||
throw new Error("not yet implemented");
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2022 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2025 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -20,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
|
||||
|
||||
@@ -154,8 +156,10 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
if (noExpectations(result)) {
|
||||
const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
|
||||
if (result.status === 'failed') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(noSpecMsg);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(noSpecMsg);
|
||||
}
|
||||
}
|
||||
@@ -462,7 +466,11 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
'tr',
|
||||
{},
|
||||
createDom('td', {}, entry.timestamp.toString()),
|
||||
createDom('td', {}, entry.message)
|
||||
createDom(
|
||||
'td',
|
||||
{ className: 'jasmine-debug-log-msg' },
|
||||
entry.message
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
@@ -530,14 +538,13 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
if (noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
if (
|
||||
resultNode.result.status === 'pending' &&
|
||||
resultNode.result.pendingReason !== ''
|
||||
) {
|
||||
specDescription =
|
||||
specDescription +
|
||||
' PENDING WITH MESSAGE: ' +
|
||||
resultNode.result.pendingReason;
|
||||
if (resultNode.result.status === 'pending') {
|
||||
if (resultNode.result.pendingReason !== '') {
|
||||
specDescription +=
|
||||
' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
|
||||
} else {
|
||||
specDescription += ' PENDING';
|
||||
}
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom(
|
||||
@@ -550,6 +557,11 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
'a',
|
||||
{ href: specHref(resultNode.result) },
|
||||
specDescription
|
||||
),
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-spec-duration' },
|
||||
'(' + resultNode.result.duration + 'ms)'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -55,9 +55,6 @@ body {
|
||||
position: fixed;
|
||||
right: 100%;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-version {
|
||||
color: #aaa;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-banner {
|
||||
margin-top: 14px;
|
||||
}
|
||||
@@ -169,10 +166,11 @@ body {
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar.jasmine-menu {
|
||||
background-color: #fff;
|
||||
color: #aaa;
|
||||
color: #000;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar.jasmine-menu a {
|
||||
color: #333;
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar a {
|
||||
color: white;
|
||||
@@ -231,6 +229,9 @@ body {
|
||||
.jasmine_html-reporter .jasmine-specs li.jasmine-excluded a:before {
|
||||
content: "• ";
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-specs li .jasmine-spec-duration {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-description + .jasmine-suite {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -297,4 +298,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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2022 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
module.exports = function(jasmineRequire) {
|
||||
const jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||
|
||||
const jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
|
||||
extend(global, jasmineInterface);
|
||||
|
||||
function extend(destination, source) {
|
||||
for (const property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
return jasmine;
|
||||
};
|
||||
92
package.json
92
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "4.4.0",
|
||||
"version": "5.10.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
@@ -15,9 +15,11 @@
|
||||
],
|
||||
"scripts": {
|
||||
"posttest": "eslint \"src/**/*.js\" \"spec/**/*.js\" && prettier --check \"src/**/*.js\" \"spec/**/*.js\"",
|
||||
"test": "grunt --stack execSpecsInNode",
|
||||
"test": "node scripts/runSpecsInNode.js",
|
||||
"test:parallel": "node scripts/runSpecsInParallel.js",
|
||||
"cleanup": "prettier --write \"src/**/*.js\" \"spec/**/*.js\"",
|
||||
"build": "grunt buildDistribution",
|
||||
"build": "node scripts/buildDistribution.js",
|
||||
"buildStandaloneDist": "node scripts/buildStandaloneDist.js",
|
||||
"serve": "node spec/support/localJasmineBrowser.js",
|
||||
"serve:performance": "node spec/support/localJasmineBrowser.js jasmine-browser-performance.json",
|
||||
"ci": "node spec/support/ci.js",
|
||||
@@ -27,84 +29,32 @@
|
||||
"homepage": "https://jasmine.github.io",
|
||||
"main": "./lib/jasmine-core.js",
|
||||
"files": [
|
||||
"MIT.LICENSE",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"images/*.{png,svg}",
|
||||
"lib/**/*.{js,css}",
|
||||
"package.json"
|
||||
],
|
||||
"devDependencies": {
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-compat": "^4.0.0",
|
||||
"glob": "^7.2.0",
|
||||
"grunt": "^1.0.4",
|
||||
"grunt-cli": "^1.3.2",
|
||||
"grunt-contrib-compress": "^2.0.0",
|
||||
"grunt-contrib-concat": "^2.0.0",
|
||||
"grunt-css-url-embed": "^1.11.1",
|
||||
"grunt-sass": "^3.0.2",
|
||||
"jasmine": "^4.1.0",
|
||||
"jasmine-browser-runner": "^1.0.0",
|
||||
"jsdom": "^19.0.0",
|
||||
"load-grunt-tasks": "^5.1.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.24.0",
|
||||
"archiver": "^7.0.1",
|
||||
"css-url-embed": "^0.1.0",
|
||||
"ejs": "^3.1.10",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-plugin-compat": "^6.0.2",
|
||||
"glob": "^10.2.3",
|
||||
"globals": "^16.0.0",
|
||||
"jasmine": "^5.0.0",
|
||||
"jasmine-browser-runner": "github:jasmine/jasmine-browser-runner",
|
||||
"jsdom": "^26.0.0",
|
||||
"prettier": "1.17.1",
|
||||
"sass": "^1.45.1",
|
||||
"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"
|
||||
}
|
||||
"sass": "^1.58.3"
|
||||
},
|
||||
"browserslist": [
|
||||
"Safari >= 14",
|
||||
"Safari >= 15",
|
||||
"Firefox >= 102",
|
||||
"last 2 Chrome versions",
|
||||
"last 2 Firefox versions",
|
||||
"Firefox >= 91",
|
||||
"last 2 Edge versions"
|
||||
]
|
||||
}
|
||||
|
||||
40
release_notes/4.5.0.md
Normal file
40
release_notes/4.5.0.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Jasmine 4.5.0 Release Notes
|
||||
|
||||
## New Features
|
||||
|
||||
* Added Safari 16 to supported browsers
|
||||
* Include inner exceptions in stack traces
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Report exceptions thrown by a describe before any it calls
|
||||
* Coerce the random string to a seed before sending it to reporters
|
||||
* This fixes an error in HTMLReporter when the configured seed is a
|
||||
number rather than a string, which has been allowed since 3.8.0
|
||||
|
||||
## Documentation updates
|
||||
|
||||
* Fixed the jsdoc types of SuiteResult and SpecResult ids
|
||||
* Replaced var with const in API doc examples
|
||||
* Updated the style of the examples that are included in jasmine-core
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Converted TreeProcessor to async/await
|
||||
* Converted ReportDispatcher to promises
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 4.5.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 12.17+, 14, 16, 18 |
|
||||
| Safari | 14-16 |
|
||||
| Chrome | 107 |
|
||||
| Firefox | 91, 102, 106 |
|
||||
| Edge | 106 |
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
19
release_notes/4.6.0.md
Normal file
19
release_notes/4.6.0.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Jasmine Core 4.6.0 Release Notes
|
||||
|
||||
## New Features
|
||||
|
||||
* Report the ID of each suite/spec's parent
|
||||
* Report the path/url of the file that the spec/suite was defined in
|
||||
* Fixes [#1884](https://github.com/jasmine/jasmine/issues/1884)
|
||||
* Added Firefox 102 (current ESR) to supported browsers
|
||||
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Pinned sass to 1.58.3 for compatibility with Node 12
|
||||
* Pinned eslint-plugin-compat to <4.1.0 for compatibility with Node 12
|
||||
* Pinned Grunt to <1.6.0 for compatibility with Node 12
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
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)_
|
||||
68
release_notes/5.0.0-alpha.0.md
Normal file
68
release_notes/5.0.0-alpha.0.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Jasmine Core 5.0.0-alpha.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This release primarily adds support for parallel execution via the `jasmine`
|
||||
package. Please see its release notes and the
|
||||
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
||||
for more information. Additionally, this release cleans up a few outdated
|
||||
interfaces.
|
||||
|
||||
This is a pre-release for a major version. It contains breaking changes, and
|
||||
there may be further breaking changes between this release and the final 5.0.0
|
||||
release.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
* Use addEventListener in browsers rather than setting window.onerror
|
||||
|
||||
This simplifies error handling in browsers, makes Jasmine's own integration
|
||||
tests easier to debug, and provides stack traces for more unhandled
|
||||
exceptions. However, some browsers will provide less error information when
|
||||
the error comes from a file:// URL. Additionally, Jasmine will no longer
|
||||
override existing onerror handlers, and setting window.onerror will no longer
|
||||
override Jasmine's global error handling. (Use `jasmine.spyOnGlobalErrors`
|
||||
instead.)
|
||||
|
||||
* Made Env#execute async
|
||||
* Env#execute no longer takes a callback
|
||||
* The `boot` function exported by the core module returns the same object
|
||||
every time it's called.
|
||||
* Removed node_boot.js. Use the exported `boot` function instead.
|
||||
|
||||
### Changes to supported environments
|
||||
|
||||
The following previously supported environments are no longer supported:
|
||||
|
||||
* Node <16.14
|
||||
* Safari 14
|
||||
* Firefox 91
|
||||
|
||||
Although this release may still work in some of those environments, we no
|
||||
longer test against them and won't try to maintain compatibility with them in
|
||||
future releases.
|
||||
|
||||
## New features
|
||||
|
||||
* Support for parallel execution in Node.js using the `jasmine` package
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* The global error handler is uninstalled at the end of env execution.
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.0-alpha.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 16.14+, 18 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 111 |
|
||||
| Firefox | 102, 111 |
|
||||
| Edge | 111 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
39
release_notes/5.0.0-alpha.1.md
Normal file
39
release_notes/5.0.0-alpha.1.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Jasmine Core 5.0.0-alpha.1 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This release provides improved support for parallel execution via the `jasmine`
|
||||
package. Please see its release notes and the
|
||||
[parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
||||
for more information.
|
||||
|
||||
## New features and bug fixes
|
||||
|
||||
* Parallel: Cleaner interface for reporter dispatching
|
||||
* When Env#config is called from spec and helper files in parallel mode, throw
|
||||
an error rather than behaving unpredictably.
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* API reference docs for parallel support APIs that jasmine-npm uses
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Updated dev dependencies
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.0-alpha.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 16.14+, 18 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 112 |
|
||||
| Firefox | 102, 111 |
|
||||
| Edge | 111 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
28
release_notes/5.0.0-beta.0.md
Normal file
28
release_notes/5.0.0-beta.0.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Jasmine Core 5.0.0-beta.0 Release Notes
|
||||
|
||||
This release supports the 5.0.0-beta-0 release of the `jasmine` package.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
* Dropped support for Node 16
|
||||
|
||||
## New features
|
||||
|
||||
* Added support for Node 20
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.0-beta.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 112 |
|
||||
| Firefox | 102, 112 |
|
||||
| Edge | 112 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
55
release_notes/5.0.0.md
Normal file
55
release_notes/5.0.0.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Jasmine Core 5.0.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a major release that includes breaking changes. It primarily adds
|
||||
support for parallel execution in Node via the `jasmine` package. Most users
|
||||
should be able to upgrade without changes, but please read the list of breaking
|
||||
changes below and see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0)
|
||||
for more information.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
* Dropped support for Node 12, 14, and 16
|
||||
* Dropped support for Safari 14 and Firefox 91
|
||||
* Made Env#execute async and removed the callback parameter
|
||||
* Global errors are detected via addEventListener rather than setting window.onerror
|
||||
* The `boot` function exported by the core module returns the same object
|
||||
every time it's called.
|
||||
* Removed node_boot.js. Use the exported `boot` function instead.
|
||||
|
||||
## New features
|
||||
|
||||
* Support for parallel execution in Node via the `jasmine` package
|
||||
See the [parallel guide](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
||||
for more information.
|
||||
* Added Node 20 to supported environments
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Accessibility: Always provide a non-color indication that a spec is pending
|
||||
* Accessibility: Improved contrast of version number and inactive tab links
|
||||
* Uninstall the global error handler at the end of env execution
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Updated dev dependencies
|
||||
* Dogfood parallel execution feature in CI
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 113 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
25
release_notes/5.0.1.md
Normal file
25
release_notes/5.0.1.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Jasmine Core 5.0.1 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Optionally restore the pre-5.0 behavior of boot() always creating a new instance
|
||||
|
||||
This is needed by jasmine-npm (and likely other tools like it) that may
|
||||
need to create and use multiple envs in sequence.
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 114 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
39
release_notes/5.1.0.md
Normal file
39
release_notes/5.1.0.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Jasmine Core 5.1.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Exclude inherited Error properties from stack trace
|
||||
|
||||
* Fixed error when formatting Error object with non-Error cause property
|
||||
|
||||
Merges [#2013](https://github.com/jasmine/jasmine/pull/2013) from @angrycat9000.
|
||||
|
||||
Fixes [#2011](https://github.com/jasmine/jasmine/issues/2011).
|
||||
|
||||
* Added `throwUnless` and `throwUnlessAsync`
|
||||
|
||||
These are similar to `expect` and `expectAsync` except that they throw
|
||||
exceptions rather than recording matcher failures as spec/suite failures.
|
||||
They're intended to support using Jasmine matchers in [testing-library's](https://testing-library.com/)
|
||||
`waitFor`, and also provide a way to integration-test custom matchers.
|
||||
|
||||
Fixes [#2003](https://github.com/jasmine/jasmine/issues/2003).
|
||||
|
||||
Fixes [#1980](https://github.com/jasmine/jasmine/issues/1980).
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.1.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 114 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
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)_
|
||||
53
release_notes/5.10.0.md
Normal file
53
release_notes/5.10.0.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Jasmine Core 5.10.0 Release Notes
|
||||
|
||||
## New Features
|
||||
|
||||
* Optionally detect late promise rejections and don't report them as errors
|
||||
This is off by default because it comes with a performance cost. It can be
|
||||
enabled by setting the `detectLateRejectionHandling` config property to true.
|
||||
* Add `getSpecProperty` to retrieve data that was set with `setSpecProperty`.
|
||||
* Merges [#2072](https://github.com/jasmine/jasmine/pull/2072) from @bonkevin
|
||||
* Show spec duration in the HTML reporter.
|
||||
* Merges [#2073](https://github.com/jasmine/jasmine/pull/2073) from @bonkevin
|
||||
* Protect `GlobalErrors` against monkey patching.
|
||||
|
||||
All currently shipped versions of zone.js contain a monkey patch that fails
|
||||
to pass constructor arguments on to `GlobalErrors`. This patch normally has
|
||||
no effect because zone.js is normally installed after `GlobalErrors` is
|
||||
instantiated, but it would crash Jasmine if it was applied early enough.
|
||||
|
||||
## Deprecations
|
||||
|
||||
* Issue a deprecation warning if the suite/spec order passed as a parameter to
|
||||
`Env#execute` causes a suite to be re-entered.
|
||||
|
||||
## Changes to supported environments
|
||||
|
||||
* Added Firefox 140 (current ESR) to supported environments
|
||||
* Demoted Firefox 128 (previous ESR) to best-effort support
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Core suite/spec execution flow has been significantly simplified.
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------------------|
|
||||
| Node | 18.20.5**, 20, 22, 24 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 139* |
|
||||
| Firefox | 102**, 115**, 128**, 140, 142* |
|
||||
| Edge | 139* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
------
|
||||
|
||||
_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)_
|
||||
39
release_notes/5.4.0.md
Normal file
39
release_notes/5.4.0.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Jasmine Core 5.4.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Fixed de-duplication of exception messages containing blank lines on Node and Chrome
|
||||
|
||||
This is particularly helpful when reporting testing-library errors, which
|
||||
have messages that contain blank lines and can be hundreds or even thousands
|
||||
of lines long.
|
||||
|
||||
* Document that the expected and actual properties of expectation results are deprecated
|
||||
|
||||
The values of these properties are not reliable in configurations where
|
||||
reporter messages are JSON serialized. They appear to have been seldom if ever
|
||||
used. They will be removed in the next major release.
|
||||
|
||||
* Added Firefox 128 (current ESR) to supported browsers
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 129* |
|
||||
| Firefox | 102**, 115**, 128, 131* |
|
||||
| Edge | 129* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Environments that are past end of life are supported on a best-effort basis.
|
||||
They may be dropped in a future minor release of Jasmine if continued support
|
||||
becomes impractical.
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
34
release_notes/5.5.0.md
Normal file
34
release_notes/5.5.0.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Jasmine Core 5.5.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Optionally enforce uniqueness of spec and suite names
|
||||
|
||||
This is off by default for backwards compatibility but can be enabled
|
||||
by setting the `forbidDuplicateNames` env config property to true.
|
||||
Fixes [#1633](https://github.com/jasmine/jasmine/issues/1633).
|
||||
|
||||
* Include property value mismatches in diffs even when there are missing or
|
||||
extra properties
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 131* |
|
||||
| Firefox | 102**, 115**, 128, 132* |
|
||||
| Edge | 131* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Environments that are past end of life are supported on a best-effort basis.
|
||||
They may be dropped in a future minor release of Jasmine if continued support
|
||||
becomes impractical.
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
51
release_notes/5.6.0.md
Normal file
51
release_notes/5.6.0.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Jasmine Core 5.6.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Added [toHaveNoOtherSpyInteractions](https://jasmine.github.io/api/5.6/matchers.html#toHaveNoOtherSpyInteractions) matcher
|
||||
* Merges [#2051](https://github.com/jasmine/jasmine/pull/2051) from @Eradev
|
||||
* Fixes [#1991](https://github.com/jasmine/jasmine/issues/1991)
|
||||
|
||||
* Added [toBeNullish](https://jasmine.github.io/api/5.6/matchers.html#toBeNullish) matcher
|
||||
* Merges [#2045](https://github.com/jasmine/jasmine/pull/2045) from @MattMcCherry
|
||||
|
||||
* Improved error messages when non-promises are passed to built-in async matchers
|
||||
* Merges [#2049](https://github.com/jasmine/jasmine/pull/2049) from @andiz2
|
||||
* Fixes [#2037](https://github.com/jasmine/jasmine/issues/2037)
|
||||
|
||||
* Added [toHaveClasses](https://jasmine.github.io/api/5.6/matchers.html#toHaveClasses) matcher
|
||||
* Merges [#2046](https://github.com/jasmine/jasmine/pull/2046) from @aYorky
|
||||
|
||||
## Documentation updates
|
||||
|
||||
* Demoted Safari to best-effort support
|
||||
|
||||
Due to limited availability of Safari versions for contributors and maintainers
|
||||
as well as in CI, Safari will be supported on the same best-effort basis as
|
||||
environments that are past end of life, such as previous Firefox ESR versions.
|
||||
See [this discussion](https://github.com/jasmine/jasmine/discussions/2050) for
|
||||
more information about why this change was made and what to expect.
|
||||
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18, 20, 22 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 133* |
|
||||
| Firefox | 102**, 115**, 128, 135* |
|
||||
| Edge | 132* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
62
release_notes/5.7.0.md
Normal file
62
release_notes/5.7.0.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Jasmine Core 5.7.0 Release Notes
|
||||
|
||||
## New features
|
||||
|
||||
* Added [Clock#autoTick](https://jasmine.github.io/api/5.7/Clock.html#autoTick)
|
||||
to automatically tick the clock asynchronously
|
||||
* Merges #2042 from @atscott and @stephenfarrar
|
||||
* Fixes #1725
|
||||
|
||||
* Expose [spec path](https://jasmine.github.io/api/5.7/Spec.html#getPath) as an
|
||||
array of names in addition to the existing concatenated name
|
||||
|
||||
This is meant to support tools like IDE integrations that need to filter a run
|
||||
to an exact set of suites/specs.
|
||||
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* Documented that [SpecResult#filename](https://jasmine.github.io/api/5.7/global.html#SpecResult)
|
||||
and [SuiteResult#filename](https://jasmine.github.io/api/5.7/global.html#SuiteResult)
|
||||
are wrong when zone.js is present and in some cases where it/describe/etc are
|
||||
replaced
|
||||
* Updated docs for expected and actual properties of
|
||||
[expectation results](https://jasmine.github.io/api/5.7/global.html#ExpectationResult)
|
||||
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Rewrote the build system to not use Grunt
|
||||
|
||||
Although Grunt has served Jasmine well over the years, it was keeping us tied
|
||||
to an aging and increasingly questionable set of dev dependencies.
|
||||
|
||||
* Updated to eslint 9
|
||||
* Removed mostly-unmaintained dev dependency 'temp'
|
||||
* Updated most other dev dependencies to latest versions
|
||||
* Fixed sass deprecation warning
|
||||
* Updated to Sauce Connect 5
|
||||
* Made stop-sauce-connect script more robust
|
||||
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18**, 20, 22 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 135* |
|
||||
| Firefox | 102**, 115**, 128, 137* |
|
||||
| Edge | 135* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
28
release_notes/5.7.1.md
Normal file
28
release_notes/5.7.1.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Jasmine Core 5.7.1 Release Notes
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Ensure that uninstalling the clock also stops auto tick
|
||||
* Merges #2057 from @atscott
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18**, 20, 22 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 136* |
|
||||
| Firefox | 102**, 115**, 128, 138* |
|
||||
| Edge | 135* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
44
release_notes/5.8.0.md
Normal file
44
release_notes/5.8.0.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Jasmine Core 5.8.0 Release Notes
|
||||
|
||||
## New Features
|
||||
|
||||
* Allow passing a function to `saveArgumentsByValue` to customize how arguments
|
||||
are saved
|
||||
* Merges [#2062](https://github.com/jasmine/jasmine/pull/2062) from @evanwaslh
|
||||
* Fixes [#1886](https://github.com/jasmine/jasmine/issues/1886)
|
||||
* Use custom object formatters in spy strategy mismatch errors
|
||||
* Include function names in pretty printer output
|
||||
* Improve performance of autoTick in Node
|
||||
* Merges [#2058](https://github.com/jasmine/jasmine/pull/2058) from @atscott
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix diff building when only one side has a custom object formatter
|
||||
* Fixes [#2061](https://github.com/jasmine/jasmine/issues/2061)
|
||||
|
||||
## Documentation improvements
|
||||
|
||||
* Added Node 24 to supported environments
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18**, 20, 22, 24 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 137* |
|
||||
| Firefox | 102**, 115**, 128, 139* |
|
||||
| Edge | 137* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
56
release_notes/5.9.0.md
Normal file
56
release_notes/5.9.0.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Jasmine Core 5.9.0 Release Notes
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Avoid generating mock clock timer IDs that conflict with native ones
|
||||
* Fixes [#2068](https://github.com/jasmine/jasmine/issues/2068)
|
||||
* Merges [#2069](https://github.com/jasmine/jasmine/pull/2069) from @atscott
|
||||
|
||||
## Deprecations and changes to platform support
|
||||
|
||||
* Node versions before 18.20.5 are no longer supported
|
||||
|
||||
Older 18.x versions might still work, but Jasmine is no longer tested in them
|
||||
prior to release.
|
||||
* Document that the filename properties of suite and spec results are deprecated
|
||||
|
||||
These properties are incorrect in many configurations. They'll be removed in
|
||||
the next major release unless there is enough user interest in fixing them.
|
||||
See <https://github.com/jasmine/jasmine/issues/2065>.
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Extensive GlobalErrors refactoring
|
||||
* Removed many of the error dispatching differences between browsers and Node
|
||||
* Split into portable and platform-specific parts
|
||||
* Converted to ES6 classes
|
||||
* Removed unnecessary errorWithStack helper
|
||||
|
||||
Jasmine no longer runs on platforms that create errors without stack traces.
|
||||
* Removed protections against user code redefining undefined
|
||||
|
||||
Jasmine no longer runs on platforms that allow redefining undefined.
|
||||
* Removed rimraf and shelljs dev dependencies
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|-------------------------|
|
||||
| Node | 18.20.5**, 20, 22, 24 |
|
||||
| Safari | 15**, 16**, 17** |
|
||||
| Chrome | 138* |
|
||||
| Firefox | 102**, 115**, 128, 140* |
|
||||
| Edge | 138* |
|
||||
|
||||
\* Evergreen browser. Each version of Jasmine is tested against the latest
|
||||
version available at release time.<br>
|
||||
\** Supported on a best-effort basis. Support for these versions may be dropped
|
||||
if it becomes impractical, and bugs affecting only these versions may not be
|
||||
treated as release blockers.
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
3
scripts/buildDistribution.js
Normal file
3
scripts/buildDistribution.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const buildDistribution = require('./lib/buildDistribution');
|
||||
|
||||
buildDistribution();
|
||||
86
scripts/buildStandaloneDist.js
Normal file
86
scripts/buildStandaloneDist.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const ejs = require('ejs');
|
||||
const archiver = require('archiver');
|
||||
const buildDistribution = require('./lib/buildDistribution');
|
||||
|
||||
const prefix = path.join(os.tmpdir(), 'jasmine-build-standalone');
|
||||
const tmpDir = fs.mkdtempSync(prefix);
|
||||
|
||||
buildStandaloneDist().finally(function() {
|
||||
fs.rmSync(tmpDir, { recursive: true });
|
||||
});
|
||||
|
||||
async function buildStandaloneDist() {
|
||||
buildDistribution();
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json'));
|
||||
compileSpecRunner(pkg.version);
|
||||
await zipStandaloneDist(pkg.version);
|
||||
}
|
||||
|
||||
function compileSpecRunner(jasmineVersion) {
|
||||
const template = fs.readFileSync('src/SpecRunner.html.ejs',
|
||||
{encoding: 'utf8'});
|
||||
const runnerHtml = ejs.render(template, { jasmineVersion });
|
||||
fs.writeFileSync(path.join(tmpDir, 'SpecRunner.html'), runnerHtml,
|
||||
{encoding: 'utf8'});
|
||||
}
|
||||
|
||||
async function zipStandaloneDist(jasmineVersion) {
|
||||
const fileGroups = [
|
||||
{
|
||||
src: [
|
||||
'LICENSE',
|
||||
path.join(tmpDir, 'SpecRunner.html'),
|
||||
]
|
||||
},
|
||||
{
|
||||
src: [
|
||||
'images/jasmine_favicon.png',
|
||||
'lib/jasmine-core/jasmine.js',
|
||||
'lib/jasmine-core/jasmine-html.js',
|
||||
'lib/jasmine-core/jasmine.css',
|
||||
'lib/jasmine-core/boot0.js',
|
||||
'lib/jasmine-core/boot1.js',
|
||||
],
|
||||
destDir: 'lib/jasmine-' + jasmineVersion
|
||||
},
|
||||
{
|
||||
src: glob.sync('lib/jasmine-core/example/src/*.js'),
|
||||
destDir: 'src'
|
||||
},
|
||||
{
|
||||
src: glob.sync('lib/jasmine-core/example/spec/*.js'),
|
||||
destDir: 'spec'
|
||||
}
|
||||
];
|
||||
|
||||
const destPath = `./dist/jasmine-standalone-${jasmineVersion}.zip`;
|
||||
const output = fs.createWriteStream(destPath);
|
||||
const archive = archiver('zip');
|
||||
|
||||
const done = new Promise(function(resolve, reject) {
|
||||
output.on('close', resolve);
|
||||
archive.on('warning', reject);
|
||||
archive.on('error', reject);
|
||||
});
|
||||
|
||||
archive.pipe(output);
|
||||
|
||||
for (const group of fileGroups) {
|
||||
for (const srcPath of group.src) {
|
||||
let destPath = path.basename(srcPath);
|
||||
|
||||
if (group.destDir) {
|
||||
destPath = `${group.destDir}/${destPath}`;
|
||||
}
|
||||
|
||||
archive.file(srcPath, {name: destPath});
|
||||
}
|
||||
}
|
||||
|
||||
archive.finalize();
|
||||
await done;
|
||||
}
|
||||
129
scripts/lib/buildDistribution.js
Normal file
129
scripts/lib/buildDistribution.js
Normal file
@@ -0,0 +1,129 @@
|
||||
const fs = require('fs');
|
||||
const sass = require('sass');
|
||||
const glob = require('glob');
|
||||
const ejs = require('ejs');
|
||||
const cssUrlEmbed = require('css-url-embed');
|
||||
|
||||
function buildDistribution() {
|
||||
compileSass();
|
||||
embedCssAssets();
|
||||
concatFiles();
|
||||
}
|
||||
|
||||
function embedCssAssets() {
|
||||
const cssPath = 'lib/jasmine-core/jasmine.css';
|
||||
cssUrlEmbed.processFile(cssPath, cssPath, function(filePath) {
|
||||
if (filePath.endsWith('.png')) {
|
||||
return 'image/png';
|
||||
} else if (filePath.endsWith('.svg')) {
|
||||
return 'image/svg+xml';
|
||||
} else {
|
||||
throw new Error(`Don't know MIME type for file: ${filePath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function compileSass() {
|
||||
const output = sass.compile('src/html/jasmine.scss');
|
||||
fs.writeFileSync('lib/jasmine-core/jasmine.css', output.css,
|
||||
{encoding: 'utf8'});
|
||||
}
|
||||
|
||||
function concatFiles() {
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json'));
|
||||
const configs = [
|
||||
{
|
||||
src: [
|
||||
'src/html/requireHtml.js',
|
||||
'src/html/HtmlReporter.js',
|
||||
'src/html/HtmlSpecFilter.js',
|
||||
'src/html/ResultsNode.js',
|
||||
'src/html/QueryString.js',
|
||||
'src/html/**/*.js'
|
||||
],
|
||||
dest: 'lib/jasmine-core/jasmine-html.js',
|
||||
},
|
||||
{
|
||||
dest: 'lib/jasmine-core/jasmine.js',
|
||||
src: [
|
||||
'src/core/requireCore.js',
|
||||
'src/core/matchers/requireMatchers.js',
|
||||
'src/core/base.js',
|
||||
'src/core/util.js',
|
||||
'src/core/Spec.js',
|
||||
'src/core/Order.js',
|
||||
'src/core/Env.js',
|
||||
'src/core/JsApiReporter.js',
|
||||
'src/core/PrettyPrinter',
|
||||
'src/core/Suite',
|
||||
'src/core/**/*.js',
|
||||
{
|
||||
template: 'src/version.js',
|
||||
data: {version: pkg.version}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
dest: 'lib/jasmine-core/boot0.js',
|
||||
src: ['src/boot/boot0.js'],
|
||||
},
|
||||
{
|
||||
dest: 'lib/jasmine-core/boot1.js',
|
||||
src: ['src/boot/boot1.js'],
|
||||
}
|
||||
];
|
||||
const licenseBanner = {
|
||||
template: 'src/licenseBanner.js.ejs',
|
||||
data: {currentYear: new Date(Date.now()).getFullYear()}
|
||||
};
|
||||
|
||||
for (const {src, dest} of configs) {
|
||||
src.unshift(licenseBanner);
|
||||
|
||||
function expand(srcListEntry) {
|
||||
if (typeof srcListEntry === 'object') {
|
||||
return srcListEntry;
|
||||
}
|
||||
|
||||
return glob.sync(srcListEntry)
|
||||
.sort(function (a, b) {
|
||||
// Match the sort order of previous build tools, so that the
|
||||
// output is the same.
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a === b) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const srcs = src.flatMap(expand);
|
||||
const seen = new Set();
|
||||
const chunks = [];
|
||||
|
||||
for (const s of srcs) {
|
||||
let content;
|
||||
|
||||
if (!seen.has(s)) {
|
||||
if (s.template) {
|
||||
const template = fs.readFileSync(s.template, {encoding: 'utf8'});
|
||||
content = ejs.render(template, s.data);
|
||||
} else {
|
||||
content = fs.readFileSync(s, {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
chunks.push(content);
|
||||
seen.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(dest, chunks.join('\n'), {encoding: 'utf8'});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = buildDistribution;
|
||||
@@ -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,12 +24,17 @@ run_browser() {
|
||||
|
||||
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
|
||||
run_browser chrome latest
|
||||
|
||||
run_browser firefox latest
|
||||
run_browser firefox 140
|
||||
run_browser firefox 128
|
||||
run_browser firefox 115
|
||||
run_browser firefox 102
|
||||
run_browser firefox 91
|
||||
run_browser safari 17
|
||||
run_browser safari 16
|
||||
run_browser safari 15
|
||||
run_browser safari 14
|
||||
run_browser MicrosoftEdge latest
|
||||
|
||||
echo
|
||||
|
||||
28
scripts/runSpecsInNode.js
Normal file
28
scripts/runSpecsInNode.js
Normal file
@@ -0,0 +1,28 @@
|
||||
verifyNoGlobals(() => require('../lib/jasmine-core.js').noGlobals());
|
||||
|
||||
const Jasmine = require('jasmine');
|
||||
const jasmineCore = require('../lib/jasmine-core.js');
|
||||
const runner = new Jasmine({jasmineCore: jasmineCore});
|
||||
|
||||
runner.loadConfigFile('./spec/support/jasmine.json');
|
||||
runner.exitOnCompletion = false;
|
||||
runner.execute()
|
||||
.then(
|
||||
result => result.overallStatus === 'passed',
|
||||
err => {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
)
|
||||
.then(ok => process.exit(ok ? 0 : 1));
|
||||
|
||||
function verifyNoGlobals(fn) {
|
||||
const initialGlobals = Object.keys(global);
|
||||
fn();
|
||||
|
||||
const extras = Object.keys(global).filter(k => !initialGlobals.includes(k));
|
||||
|
||||
if (extras.length !== 0) {
|
||||
throw new Error('Globals were unexpectedly created: ' + extras.join(', '));
|
||||
}
|
||||
}
|
||||
28
scripts/runSpecsInParallel.js
Normal file
28
scripts/runSpecsInParallel.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const ParallelRunner = require('jasmine/parallel');
|
||||
const jasmineCore = require('../lib/jasmine-core.js');
|
||||
let numWorkers = require('os').cpus().length;
|
||||
|
||||
if (process.env['CIRCLECI']) {
|
||||
// On Circle CI, the above gives the number of CPU cores on the host
|
||||
// computer, which is unrelated to the resources actually available
|
||||
// to the container. 2 workers gives peak performance with our current
|
||||
// configuration, but 4 might increase the odds of discovering any
|
||||
// parallel-specific bugs.
|
||||
numWorkers = 4;
|
||||
}
|
||||
|
||||
const runner = new ParallelRunner({jasmineCore, numWorkers});
|
||||
|
||||
runner.loadConfigFile('./spec/support/jasmine.json')
|
||||
.then(() => {
|
||||
runner.exitOnCompletion = false;
|
||||
return runner.execute();
|
||||
})
|
||||
.then(
|
||||
jasmineDoneInfo => jasmineDoneInfo.overallStatus === 'passed',
|
||||
err => {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
)
|
||||
.then(ok => process.exit(ok ? 0 : 1));
|
||||
@@ -2,32 +2,19 @@
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
if [ $# -gt 1 -o "$1" = "--help" ]; then
|
||||
echo "Usage: $0 [pidfile]" 1>&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
pidfile=`mktemp`
|
||||
else
|
||||
pidfile="$1"
|
||||
if [ -z "$SAUCE_TUNNEL_NAME" ]; then
|
||||
echo "SAUCE_TUNNEL_NAME must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
outfile=`mktemp`
|
||||
echo "Starting Sauce Connect"
|
||||
if [ -z "$SAUCE_TUNNEL_IDENTIFIER" ]; then
|
||||
sc -u "$SAUCE_USERNAME" -k "$SAUCE_ACCESS_KEY" -X 4445 --pidfile "$pidfile" 2>&1 | tee "$outfile" &
|
||||
else
|
||||
sc -u "$SAUCE_USERNAME" -k "$SAUCE_ACCESS_KEY" -X 4445 --pidfile "$pidfile" -i "$SAUCE_TUNNEL_IDENTIFIER" 2>&1 | tee "$outfile" &
|
||||
fi
|
||||
sc legacy --proxy-localhost --tunnel-domains localhost --region us-west \
|
||||
-u "$SAUCE_USERNAME" -k "$SAUCE_ACCESS_KEY" \
|
||||
-X 4445 -i "$SAUCE_TUNNEL_NAME" 2>&1 | tee "$outfile" &
|
||||
|
||||
while ! fgrep "Sauce Connect is up, you may start your tests." "$outfile" > /dev/null; do
|
||||
while ! fgrep "Sauce Connect is up, you may start your tests" "$outfile" > /dev/null; do
|
||||
sleep 1
|
||||
|
||||
if ! ps -p $(cat "$pidfile") > /dev/null; then
|
||||
echo "Sauce Connect exited"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if ! nc -z localhost 4445; then
|
||||
|
||||
@@ -2,32 +2,38 @@
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 sauce-connect-pid" 1>&2
|
||||
exit
|
||||
fi
|
||||
|
||||
pid="$1"
|
||||
echo "PID: $pid"
|
||||
|
||||
echo "Stopping Sauce Connect"
|
||||
# Sauce Connect docs say that we can just kill -9 it if we don't care about
|
||||
# failing any ongoing sessions. In practice, that sometimes works but usually
|
||||
# leaks a tunnel so badly that you can't even stop it from the web UI.
|
||||
# Instead of doing that, we give Sauce Connect some time to shut down
|
||||
# gracefully and then give up.
|
||||
kill -INT $pid
|
||||
|
||||
# Sauce Connect 4 docs said that we can just kill -9 it if we don't care about
|
||||
# failing any ongoing sessions. In practice, that sometimes worked but usually
|
||||
# leaked a tunnel so badly that you couldn't even stop it from the web UI.
|
||||
#
|
||||
# Sauce Connect 5 appears to be *much* more prone to hung jobs. Hung jobs have
|
||||
# a shutdown deadline of *three hours*, however, they appear to usually exit
|
||||
# within a minute or so. Unfortunately the only thing the Sauce Connect 5 docs
|
||||
# say about shutdown is that "you can stop your tunnel from the terminal where
|
||||
# Sauce Connect is running by entering Ctrl+C". Nothing is said about what to
|
||||
# do if Sauce Connect doesn't exit on it own or about non-interactive usage.
|
||||
#
|
||||
# So we do our best to be well-behaved without assuming that Sauce Connect
|
||||
# always is: send it the same signal that it would get if an interactive user
|
||||
# hit ctrl-c, wait a while for it to exit, then give up so that the CI task
|
||||
# doesn't keep running indefinitely.
|
||||
|
||||
if ! pkill -INT '^sc$'; then
|
||||
echo "sc does not appear to be running" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait up to 2 minutes, then give up if it's still running
|
||||
n=0
|
||||
while [ $n -lt 120 ] && ps -p $pid > /dev/null; do
|
||||
while [ $n -lt 120 ] && pgrep '^sc$' > /dev/null; do
|
||||
sleep 1
|
||||
kill -INT $pid 2> /dev/null || true
|
||||
pkill -INT '^sc$' || true
|
||||
n=$(($n + 1))
|
||||
done
|
||||
|
||||
if ps -p $pid > /dev/null; then
|
||||
if pgrep '^sc$' > /dev/null; then
|
||||
echo "Could not shut down Sauce Connect"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit $exitcode
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('AsyncExpectation', function() {
|
||||
|
||||
it('converts a fail to a pass', function() {
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = Promise.reject(),
|
||||
actual = Promise.reject(new Error('nope')),
|
||||
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
matchersUtil: new jasmineUnderTest.MatchersUtil({
|
||||
pp: function() {}
|
||||
@@ -129,33 +129,33 @@ describe('AsyncExpectation', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('prepends the context to a custom failure message from a function', function() {
|
||||
pending('should actually work, but no custom matchers for async yet');
|
||||
|
||||
it('prepends the context to a custom failure message from a matcher', async function() {
|
||||
const matchersUtil = {
|
||||
buildFailureMessage: function() {
|
||||
return 'failure message';
|
||||
}
|
||||
buildFailureMessage() {
|
||||
return 'failure message';
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = Promise.reject(),
|
||||
expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: actual,
|
||||
addExpectationResult: addExpectationResult,
|
||||
matchersUtil: matchersUtil
|
||||
});
|
||||
pp(v) {
|
||||
return v.toString();
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = Promise.reject(new Error('nope'));
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: actual,
|
||||
addExpectationResult: addExpectationResult,
|
||||
matchersUtil: matchersUtil
|
||||
});
|
||||
|
||||
return expectation
|
||||
.withContext('Some context')
|
||||
.toBeResolved()
|
||||
.then(function() {
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(
|
||||
false,
|
||||
jasmine.objectContaining({
|
||||
message: 'Some context: msg'
|
||||
})
|
||||
);
|
||||
});
|
||||
await expectation.withContext('Some context').toBeResolved();
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(
|
||||
false,
|
||||
jasmine.objectContaining({
|
||||
message:
|
||||
'Some context: Expected a promise to be resolved but it ' +
|
||||
'was rejected with Error: nope.'
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('works with #not', function() {
|
||||
@@ -277,23 +277,18 @@ describe('AsyncExpectation', function() {
|
||||
|
||||
it('reports a passing result to the spec when the comparison passes', function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
matchersUtil = {
|
||||
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const matchersUtil = {
|
||||
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -310,7 +305,7 @@ describe('AsyncExpectation', function() {
|
||||
error: undefined,
|
||||
expected: 'hello',
|
||||
actual: 'an actual',
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -329,13 +324,8 @@ describe('AsyncExpectation', function() {
|
||||
buildFailureMessage: function() {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -352,30 +342,25 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: '',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports a failing result and a custom fail message to the spec when the comparison fails', function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: 'an actual',
|
||||
@@ -391,32 +376,27 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: function() {
|
||||
return 'I am a custom message';
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: function() {
|
||||
return 'I am a custom message';
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -432,28 +412,23 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports a passing result to the spec when the comparison fails for a negative expectation', function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: false });
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = 'an actual',
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: false });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = 'an actual';
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -469,7 +444,7 @@ describe('AsyncExpectation', function() {
|
||||
error: undefined,
|
||||
expected: 'hello',
|
||||
actual: actual,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -488,14 +463,9 @@ describe('AsyncExpectation', function() {
|
||||
buildFailureMessage: function() {
|
||||
return 'default message';
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = 'an actual',
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = 'an actual';
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -512,31 +482,26 @@ describe('AsyncExpectation', function() {
|
||||
actual: actual,
|
||||
message: 'default message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = 'an actual',
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = 'an actual';
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -552,31 +517,26 @@ describe('AsyncExpectation', function() {
|
||||
actual: actual,
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
},
|
||||
negativeCompare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = 'an actual',
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
},
|
||||
negativeCompare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = 'an actual';
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -592,34 +552,29 @@ describe('AsyncExpectation', function() {
|
||||
actual: actual,
|
||||
message: '',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
},
|
||||
negativeCompare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: "I'm a custom message"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
actual = 'an actual',
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({ pass: true });
|
||||
},
|
||||
negativeCompare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: "I'm a custom message"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
const actual = 'an actual';
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
customAsyncMatchers: matchers,
|
||||
@@ -635,7 +590,7 @@ describe('AsyncExpectation', function() {
|
||||
actual: actual,
|
||||
message: "I'm a custom message",
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -643,24 +598,19 @@ describe('AsyncExpectation', function() {
|
||||
it('reports errorWithStack when a custom error message is returned', function() {
|
||||
const customError = new Error('I am a custom error');
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: 'I am a custom message',
|
||||
error: customError
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: false,
|
||||
message: 'I am a custom message',
|
||||
error: customError
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: 'an actual',
|
||||
@@ -676,30 +626,25 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a custom message to the spec when a 'not' comparison fails", function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: 'I am a custom message'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
const expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: 'an actual',
|
||||
@@ -715,32 +660,27 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a custom message func to the spec when a 'not' comparison fails", function() {
|
||||
const matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: function() {
|
||||
return 'I am a custom message';
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy('addExpectationResult'),
|
||||
errorWithStack = new Error('errorWithStack');
|
||||
|
||||
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
|
||||
errorWithStack
|
||||
);
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return Promise.resolve({
|
||||
pass: true,
|
||||
message: function() {
|
||||
return 'I am a custom message';
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const addExpectationResult = jasmine.createSpy('addExpectationResult');
|
||||
|
||||
let expectation = jasmineUnderTest.Expectation.asyncFactory({
|
||||
actual: 'an actual',
|
||||
@@ -756,7 +696,7 @@ describe('AsyncExpectation', function() {
|
||||
actual: 'an actual',
|
||||
message: 'I am a custom message',
|
||||
error: undefined,
|
||||
errorForStack: errorWithStack
|
||||
errorForStack: jasmine.any(Error)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,6 +134,42 @@ describe('CallTracker', function() {
|
||||
expect(callTracker.mostRecent().args[1]).toEqual(arrayArg);
|
||||
});
|
||||
|
||||
it('allows object arguments to be deep cloned', function() {
|
||||
const callTracker = new jasmineUnderTest.CallTracker();
|
||||
callTracker.saveArgumentsByValue(args => JSON.parse(JSON.stringify(args)));
|
||||
|
||||
const objectArg = { foo: { bar: { baz: ['qux'] } } },
|
||||
arrayArg = ['foo', 'bar'];
|
||||
|
||||
callTracker.track({
|
||||
object: {},
|
||||
args: [objectArg, arrayArg, false, undefined, null, NaN, '', 0, 1.0]
|
||||
});
|
||||
|
||||
objectArg.foo.bar.baz.push('quux');
|
||||
|
||||
expect(callTracker.mostRecent().args[0]).not.toBe(objectArg);
|
||||
expect(callTracker.mostRecent().args[0]).not.toEqual(objectArg);
|
||||
expect(callTracker.mostRecent().args[0]).toEqual({
|
||||
foo: { bar: { baz: ['qux'] } }
|
||||
});
|
||||
expect(callTracker.mostRecent().args[1]).not.toBe(arrayArg);
|
||||
expect(callTracker.mostRecent().args[1]).toEqual(arrayArg);
|
||||
});
|
||||
|
||||
it('can take any function to transform arguments when saving by value', function() {
|
||||
const callTracker = new jasmineUnderTest.CallTracker();
|
||||
callTracker.saveArgumentsByValue(JSON.stringify);
|
||||
|
||||
const objectArg = { foo: { bar: { baz: ['qux'] } } },
|
||||
arrayArg = ['foo', 'bar'],
|
||||
args = [objectArg, arrayArg, false, undefined, null, NaN, '', 0, 1.0];
|
||||
|
||||
callTracker.track({ object: {}, args });
|
||||
|
||||
expect(callTracker.mostRecent().args).toEqual(JSON.stringify(args));
|
||||
});
|
||||
|
||||
it('saves primitive arguments by value', function() {
|
||||
const callTracker = new jasmineUnderTest.CallTracker(),
|
||||
args = [undefined, null, false, '', /\s/, 0, 1.2, NaN];
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -687,6 +687,159 @@ describe('Clock (acceptance)', function() {
|
||||
expect(recurring1.calls.count()).toBe(4);
|
||||
});
|
||||
|
||||
describe('auto tick mode', () => {
|
||||
let delayedFunctionScheduler;
|
||||
let mockDate;
|
||||
let clock;
|
||||
|
||||
beforeEach(() => {
|
||||
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler();
|
||||
mockDate = {
|
||||
install: function() {},
|
||||
tick: function() {},
|
||||
uninstall: function() {}
|
||||
};
|
||||
// window setTimeout to window to make firefox happy
|
||||
const _setTimeout =
|
||||
typeof window !== 'undefined' ? setTimeout.bind(window) : setTimeout;
|
||||
// passing a fake global allows us to preserve the real timing functions for use in tests
|
||||
const _global = { setTimeout: _setTimeout, setInterval: setInterval };
|
||||
clock = new jasmineUnderTest.Clock(
|
||||
_global,
|
||||
function() {
|
||||
return delayedFunctionScheduler;
|
||||
},
|
||||
mockDate
|
||||
);
|
||||
clock.install().autoTick();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clock.uninstall();
|
||||
});
|
||||
|
||||
it('flushes microtask queue between macrotasks', async () => {
|
||||
const log = [];
|
||||
await new Promise(r => clock.setTimeout(r, 10)).then(() => {
|
||||
log.push(1);
|
||||
Promise.resolve().then(() => log.push(2));
|
||||
Promise.resolve().then(() => log.push(3));
|
||||
});
|
||||
await new Promise(r => clock.setTimeout(r, 10)).then(() => {
|
||||
log.push(4);
|
||||
Promise.resolve().then(() => log.push(5));
|
||||
});
|
||||
expect(log).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
it('can run setTimeouts/setIntervals asynchronously', function() {
|
||||
const recurring = jasmine.createSpy('recurring'),
|
||||
fn1 = jasmine.createSpy('fn1'),
|
||||
fn2 = jasmine.createSpy('fn2'),
|
||||
fn3 = jasmine.createSpy('fn3');
|
||||
|
||||
const intervalId = clock.setInterval(recurring, 50);
|
||||
// In a microtask, add some timeouts.
|
||||
Promise.resolve()
|
||||
.then(function() {
|
||||
return new Promise(function(resolve) {
|
||||
clock.setTimeout(resolve, 25);
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
fn1();
|
||||
return new Promise(function(resolve) {
|
||||
clock.setTimeout(resolve, 200);
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
fn2();
|
||||
return new Promise(function(resolve) {
|
||||
clock.setTimeout(resolve, 100);
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
fn3();
|
||||
});
|
||||
|
||||
expect(recurring).not.toHaveBeenCalled();
|
||||
expect(fn1).not.toHaveBeenCalled();
|
||||
expect(fn2).not.toHaveBeenCalled();
|
||||
expect(fn3).not.toHaveBeenCalled();
|
||||
|
||||
return new Promise(resolve => clock.setTimeout(resolve, 50))
|
||||
.then(function() {
|
||||
expect(recurring).toHaveBeenCalledTimes(1);
|
||||
expect(fn1).toHaveBeenCalled();
|
||||
expect(fn2).not.toHaveBeenCalled();
|
||||
expect(fn3).not.toHaveBeenCalled();
|
||||
|
||||
return new Promise(resolve => clock.setTimeout(resolve, 175));
|
||||
})
|
||||
.then(function() {
|
||||
expect(recurring).toHaveBeenCalledTimes(4);
|
||||
expect(fn1).toHaveBeenCalled();
|
||||
expect(fn2).toHaveBeenCalled();
|
||||
expect(fn3).not.toHaveBeenCalled();
|
||||
|
||||
clock.clearInterval(intervalId);
|
||||
return new Promise(resolve => clock.setTimeout(resolve, 100));
|
||||
})
|
||||
.then(function() {
|
||||
expect(recurring).toHaveBeenCalledTimes(4);
|
||||
expect(fn1).toHaveBeenCalled();
|
||||
expect(fn2).toHaveBeenCalled();
|
||||
expect(fn3).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('aborts auto ticking when uninstalled, even if installed again synchonrously', async () => {
|
||||
clock.uninstall();
|
||||
clock.install();
|
||||
|
||||
let resolved = false;
|
||||
const promise = new Promise(resolve => {
|
||||
clock.setTimeout(resolve, 1);
|
||||
}).then(() => {
|
||||
resolved = true;
|
||||
});
|
||||
|
||||
// wait some real time and verify that the clock did not flush the timer above automatically
|
||||
await new Promise(resolve => setTimeout(resolve, 2));
|
||||
expect(resolved).toBe(false);
|
||||
|
||||
// enabling auto tick again will flush the timer
|
||||
clock.autoTick();
|
||||
await expectAsync(promise).toBeResolved();
|
||||
});
|
||||
|
||||
it('speeds up the execution of the timers in all browsers', async () => {
|
||||
const startTimeMs = performance.now() / 1000;
|
||||
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
||||
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
||||
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
||||
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
||||
const endTimeMs = performance.now() / 1000;
|
||||
// Ensure we didn't take 20s to complete the awaits above and, in fact, can do it in a fraction of a second
|
||||
expect(endTimeMs - startTimeMs).toBeLessThan(100);
|
||||
});
|
||||
|
||||
it('is easy to test async functions with interleaved timers and microtasks', async () => {
|
||||
async function blackBoxWithLotsOfAsyncStuff() {
|
||||
await new Promise(r => clock.setTimeout(r, 10));
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await new Promise(r => clock.setTimeout(r, 20));
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
return 'done';
|
||||
}
|
||||
const result = await blackBoxWithLotsOfAsyncStuff();
|
||||
expect(result).toBe('done');
|
||||
});
|
||||
});
|
||||
|
||||
it('can clear a previously set timeout', function() {
|
||||
const clearedFn = jasmine.createSpy('clearedFn'),
|
||||
delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
|
||||
|
||||
@@ -86,12 +86,13 @@ describe('DelayedFunctionScheduler', function() {
|
||||
it('increments scheduled fns ids unless one is passed', function() {
|
||||
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
|
||||
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(1);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(2);
|
||||
const initial = scheduler.scheduleFunction(function() {}, 0);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(initial + 1);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(initial + 2);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0, [], false, 123)).toBe(
|
||||
123
|
||||
);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(3);
|
||||
expect(scheduler.scheduleFunction(function() {}, 0)).toBe(initial + 3);
|
||||
});
|
||||
|
||||
it('#removeFunctionWithId removes a previously scheduled function with a given id', function() {
|
||||
@@ -264,6 +265,42 @@ describe('DelayedFunctionScheduler', function() {
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('runs the next scheduled funtion', function() {
|
||||
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
|
||||
const fn = jasmine.createSpy('fn');
|
||||
const tickSpy = jasmine.createSpy('tick');
|
||||
|
||||
scheduler.scheduleFunction(fn, 10, [], false, 'foo');
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.runNextQueuedFunction(tickSpy);
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
expect(tickSpy).toHaveBeenCalledWith(10);
|
||||
});
|
||||
|
||||
it('runs the only a single scheduled funtion in a time slot', function() {
|
||||
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
|
||||
const fn1 = jasmine.createSpy('fn');
|
||||
const fn2 = jasmine.createSpy('fn2');
|
||||
const tickSpy = jasmine.createSpy('tick');
|
||||
|
||||
scheduler.scheduleFunction(fn1, 10, [], false, 'foo1');
|
||||
scheduler.scheduleFunction(fn2, 10, [], false, 'foo2');
|
||||
|
||||
scheduler.runNextQueuedFunction(tickSpy);
|
||||
|
||||
expect(fn1).toHaveBeenCalled();
|
||||
expect(fn2).not.toHaveBeenCalled();
|
||||
expect(tickSpy).toHaveBeenCalledWith(10);
|
||||
|
||||
tickSpy.calls.reset();
|
||||
scheduler.runNextQueuedFunction(tickSpy);
|
||||
expect(fn2).toHaveBeenCalled();
|
||||
expect(tickSpy).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it('updates the mockDate per scheduled time', function() {
|
||||
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
|
||||
tickDate = jasmine.createSpy('tickDate');
|
||||
@@ -277,6 +314,28 @@ describe('DelayedFunctionScheduler', function() {
|
||||
expect(tickDate).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it('does not conflict with native timer IDs', function() {
|
||||
const NODE_JS =
|
||||
typeof process !== 'undefined' &&
|
||||
process.versions &&
|
||||
typeof process.versions.node === 'string';
|
||||
if (NODE_JS) {
|
||||
pending('numeric timer ID conflicts only relevant for browsers.');
|
||||
}
|
||||
const nativeTimeoutId = setTimeout(function() {}, 100);
|
||||
|
||||
const scheduler = new jasmineUnderTest.DelayedFunctionScheduler();
|
||||
const fn = jasmine.createSpy('fn');
|
||||
|
||||
for (let i = 0; i < nativeTimeoutId; i++) {
|
||||
scheduler.scheduleFunction(fn, 0, [], false);
|
||||
}
|
||||
scheduler.removeFunctionWithId(nativeTimeoutId);
|
||||
scheduler.tick(1);
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(nativeTimeoutId);
|
||||
});
|
||||
|
||||
describe('ticking inside a scheduled function', function() {
|
||||
let clock;
|
||||
|
||||
|
||||
@@ -80,6 +80,19 @@ describe('Env', function() {
|
||||
);
|
||||
expect(suite.children[1].children[1].children[0].children).toBeFalsy();
|
||||
});
|
||||
|
||||
it('throws if called in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
check();
|
||||
env.setParallelLoadingState('specs');
|
||||
check();
|
||||
|
||||
function check() {
|
||||
expect(function() {
|
||||
env.topSuite();
|
||||
}).toThrowError("'topSuite' is not available in parallel mode");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts its own current configureation', function() {
|
||||
@@ -192,7 +205,6 @@ describe('Env', function() {
|
||||
|
||||
it('throws an error when given arguments', function() {
|
||||
expect(function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
env.describe('done method', function(done) {});
|
||||
}).toThrowError('describe does not expect any arguments');
|
||||
});
|
||||
@@ -251,6 +263,15 @@ describe('Env', function() {
|
||||
|
||||
describe('#fdescribe', function() {
|
||||
behavesLikeDescribe('fdescribe');
|
||||
|
||||
it('throws an error in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.fdescribe('a suite', function() {
|
||||
env.it('a spec');
|
||||
});
|
||||
}).toThrowError("'fdescribe' is not available in parallel mode");
|
||||
});
|
||||
});
|
||||
|
||||
describe('xdescribe', function() {
|
||||
@@ -372,6 +393,13 @@ describe('Env', function() {
|
||||
env.fit('huge timeout', function() {}, 2147483648);
|
||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||
});
|
||||
|
||||
it('throws an error in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.fit('a spec', function() {});
|
||||
}).toThrowError("'fit' is not available in parallel mode");
|
||||
});
|
||||
});
|
||||
|
||||
describe('#beforeEach', function() {
|
||||
@@ -394,6 +422,28 @@ describe('Env', function() {
|
||||
env.beforeEach(function() {}, 2147483648);
|
||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||
});
|
||||
|
||||
it('throws when called at the top level in a spec file in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.beforeEach(function() {});
|
||||
}).toThrowError(
|
||||
'In parallel mode, beforeEach must be in a describe block or in a helper file'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not throw when called at the top level in a helper file in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
env.beforeEach(function() {});
|
||||
});
|
||||
|
||||
it('does not throw when called in a describe in a spec file in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
env.describe('a suite', function() {
|
||||
env.beforeEach(function() {});
|
||||
env.it('a spec');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#beforeAll', function() {
|
||||
@@ -416,6 +466,47 @@ describe('Env', function() {
|
||||
env.beforeAll(function() {}, 2147483648);
|
||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||
});
|
||||
|
||||
describe('in parallel mode', function() {
|
||||
it('throws an error when called at the top level', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
check();
|
||||
env.setParallelLoadingState('specs');
|
||||
check();
|
||||
|
||||
function check() {
|
||||
expect(function() {
|
||||
env.beforeAll(function() {});
|
||||
}).toThrowError(
|
||||
"In parallel mode, 'beforeAll' must be in a describe block. " +
|
||||
'Use the globalSetup config property for exactly-once setup in' +
|
||||
' parallel mode.'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('does not throw an error when called in a describe', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
check();
|
||||
env.setParallelLoadingState('specs');
|
||||
check();
|
||||
|
||||
function check() {
|
||||
let done = false;
|
||||
|
||||
env.describe('a suite', function() {
|
||||
expect(function() {
|
||||
env.it('a spec');
|
||||
env.beforeAll(function() {});
|
||||
}).not.toThrow();
|
||||
|
||||
done = true;
|
||||
});
|
||||
|
||||
expect(done).toBeTrue();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#afterEach', function() {
|
||||
@@ -438,6 +529,28 @@ describe('Env', function() {
|
||||
env.afterEach(function() {}, 2147483648);
|
||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||
});
|
||||
|
||||
it('throws when called at the top level in a spec file in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.afterEach(function() {});
|
||||
}).toThrowError(
|
||||
'In parallel mode, afterEach must be in a describe block or in a helper file'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not throw when called at the top level in a helper file in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
env.afterEach(function() {});
|
||||
});
|
||||
|
||||
it('does not throw when called in a describe in a spec file in parallel mode', function() {
|
||||
env.setParallelLoadingState('specs');
|
||||
env.describe('a suite', function() {
|
||||
env.afterEach(function() {});
|
||||
env.it('a spec');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#afterAll', function() {
|
||||
@@ -460,6 +573,47 @@ describe('Env', function() {
|
||||
env.afterAll(function() {}, 2147483648);
|
||||
}).toThrowError('Timeout value cannot be greater than 2147483647');
|
||||
});
|
||||
|
||||
describe('in parallel mode', function() {
|
||||
it('throws an error when called at the top level', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
check();
|
||||
env.setParallelLoadingState('specs');
|
||||
check();
|
||||
|
||||
function check() {
|
||||
expect(function() {
|
||||
env.afterAll(function() {});
|
||||
}).toThrowError(
|
||||
"In parallel mode, 'afterAll' must be in a describe block. " +
|
||||
'Use the globalTeardown config property for exactly-once ' +
|
||||
'teardown in parallel mode.'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('does not throw an error when called in a describe', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
check();
|
||||
env.setParallelLoadingState('specs');
|
||||
check();
|
||||
|
||||
function check() {
|
||||
let done = false;
|
||||
|
||||
env.describe('a suite', function() {
|
||||
expect(function() {
|
||||
env.it('a spec');
|
||||
env.afterAll(function() {});
|
||||
}).not.toThrow();
|
||||
|
||||
done = true;
|
||||
});
|
||||
|
||||
expect(done).toBeTrue();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when not constructed with suppressLoadErrors: true', function() {
|
||||
@@ -471,9 +625,12 @@ describe('Env', function() {
|
||||
'popListener',
|
||||
'removeOverrideListener'
|
||||
]);
|
||||
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
||||
env.cleanup_();
|
||||
env = new jasmineUnderTest.Env();
|
||||
env = new jasmineUnderTest.Env({
|
||||
GlobalErrors: function() {
|
||||
return globalErrors;
|
||||
}
|
||||
});
|
||||
expect(globalErrors.install).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -487,9 +644,13 @@ describe('Env', function() {
|
||||
'popListener',
|
||||
'removeOverrideListener'
|
||||
]);
|
||||
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
||||
env.cleanup_();
|
||||
env = new jasmineUnderTest.Env({ suppressLoadErrors: true });
|
||||
env = new jasmineUnderTest.Env({
|
||||
suppressLoadErrors: true,
|
||||
GlobalErrors: function() {
|
||||
return globalErrors;
|
||||
}
|
||||
});
|
||||
expect(globalErrors.install).not.toHaveBeenCalled();
|
||||
env.execute();
|
||||
expect(globalErrors.install).toHaveBeenCalled();
|
||||
@@ -592,6 +753,32 @@ describe('Env', function() {
|
||||
expect(id).toEqual(env.topSuite().id);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not reset the topSuite if parallelReset was called since the last run', async function() {
|
||||
await env.execute();
|
||||
env.parallelReset();
|
||||
spyOn(jasmineUnderTest.Suite.prototype, 'reset');
|
||||
await env.execute();
|
||||
expect(jasmineUnderTest.Suite.prototype.reset).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('In parallel mode', function() {
|
||||
it('rejects if random is set to false', async function() {
|
||||
env.configure({ random: false });
|
||||
env.setParallelLoadingState('specs');
|
||||
await expectAsync(env.execute()).toBeRejectedWithError(
|
||||
'Randomization cannot be disabled in parallel mode'
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects if seed is set', async function() {
|
||||
env.configure({ seed: 1234 });
|
||||
env.setParallelLoadingState('specs');
|
||||
await expectAsync(env.execute()).toBeRejectedWithError(
|
||||
'Random seed cannot be set in parallel mode'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#spyOnGlobalErrorsAsync', function() {
|
||||
@@ -608,4 +795,46 @@ describe('Env', function() {
|
||||
).toBeRejectedWithError(msg);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addReporter', function() {
|
||||
it('throws when called in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
expect(function() {
|
||||
env.addReporter({});
|
||||
}).toThrowError('Reporters cannot be added via Env in parallel mode');
|
||||
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.addReporter({});
|
||||
}).toThrowError('Reporters cannot be added via Env in parallel mode');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#clearReporters', function() {
|
||||
it('throws when called in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
expect(function() {
|
||||
env.clearReporters();
|
||||
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
|
||||
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.clearReporters();
|
||||
}).toThrowError('Reporters cannot be removed via Env in parallel mode');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#configure', function() {
|
||||
it('throws when called in parallel mode', function() {
|
||||
env.setParallelLoadingState('helpers');
|
||||
expect(function() {
|
||||
env.configure({});
|
||||
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
|
||||
|
||||
env.setParallelLoadingState('specs');
|
||||
expect(function() {
|
||||
env.configure({});
|
||||
}).toThrowError('Jasmine cannot be configured via Env in parallel mode');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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/)) {
|
||||
@@ -197,7 +218,7 @@ describe('ExceptionFormatter', function() {
|
||||
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
|
||||
});
|
||||
|
||||
it('includes error properties in stack', function() {
|
||||
it("includes the error's own properties in stack", function() {
|
||||
const error = new Error('an error');
|
||||
error.someProperty = 'hello there';
|
||||
|
||||
@@ -206,6 +227,19 @@ describe('ExceptionFormatter', function() {
|
||||
expect(result).toMatch(/error properties:.*someProperty.*hello there/);
|
||||
});
|
||||
|
||||
it('does not include inherited error properties', function() {
|
||||
function CustomError(msg) {
|
||||
Error.call(this, msg);
|
||||
}
|
||||
|
||||
CustomError.prototype = new Error();
|
||||
CustomError.prototype.anInheritedProp = 'something';
|
||||
const error = new CustomError('nope');
|
||||
|
||||
const result = new jasmineUnderTest.ExceptionFormatter().stack(error);
|
||||
expect(result).not.toContain('anInheritedProp');
|
||||
});
|
||||
|
||||
describe('When omitMessage is true', function() {
|
||||
it('filters the message from V8-style stack traces', function() {
|
||||
const error = {
|
||||
@@ -256,5 +290,61 @@ describe('ExceptionFormatter', function() {
|
||||
expect(result).not.toContain('an error');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the error has a cause property', function() {
|
||||
it('recursively includes the cause in the stack trace in this environment', function() {
|
||||
const subject = new jasmineUnderTest.ExceptionFormatter();
|
||||
const rootCause = new Error('root cause');
|
||||
const proximateCause = new Error('proximate cause', {
|
||||
cause: rootCause
|
||||
});
|
||||
const symptom = new Error('symptom', { cause: proximateCause });
|
||||
|
||||
const lines = subject.stack(symptom).split('\n');
|
||||
// Not all environments include the message in the stack trace.
|
||||
const hasRootMessage = lines[0].indexOf('symptom') !== -1;
|
||||
const firstSymptomStackIx = hasRootMessage ? 1 : 0;
|
||||
|
||||
expect(lines[firstSymptomStackIx])
|
||||
.withContext('first symptom stack frame')
|
||||
.toContain('ExceptionFormatterSpec.js');
|
||||
const proximateCauseMsgIx = lines.indexOf(
|
||||
'Caused by: Error: proximate cause'
|
||||
);
|
||||
expect(proximateCauseMsgIx)
|
||||
.withContext('index of proximate cause message')
|
||||
.toBeGreaterThan(firstSymptomStackIx);
|
||||
expect(lines[proximateCauseMsgIx + 1])
|
||||
.withContext('first proximate cause stack frame')
|
||||
.toContain('ExceptionFormatterSpec.js');
|
||||
const rootCauseMsgIx = lines.indexOf('Caused by: Error: root cause');
|
||||
expect(rootCauseMsgIx)
|
||||
.withContext('index of root cause message')
|
||||
.toBeGreaterThan(proximateCauseMsgIx + 1);
|
||||
expect(lines[rootCauseMsgIx + 1])
|
||||
.withContext('first root cause stack frame')
|
||||
.toContain('ExceptionFormatterSpec.js');
|
||||
});
|
||||
|
||||
it('does not throw if cause is a non Error', function() {
|
||||
const formatter = new jasmineUnderTest.ExceptionFormatter();
|
||||
|
||||
expect(function() {
|
||||
formatter.stack(
|
||||
new Error('error', {
|
||||
cause: function() {}
|
||||
})
|
||||
);
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(function() {
|
||||
formatter.stack(
|
||||
new Error('error', {
|
||||
cause: 'another error'
|
||||
})
|
||||
);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
176
spec/core/ParallelReportDispatcherSpec.js
Normal file
176
spec/core/ParallelReportDispatcherSpec.js
Normal file
@@ -0,0 +1,176 @@
|
||||
describe('ParallelReportDispatcher', function() {
|
||||
it('dispatches the standard reporter events', async function() {
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
||||
globalErrors: mockGlobalErrors()
|
||||
});
|
||||
const events = [
|
||||
'jasmineStarted',
|
||||
'jasmineDone',
|
||||
'suiteStarted',
|
||||
'suiteDone',
|
||||
'specStarted',
|
||||
'specDone'
|
||||
];
|
||||
const reporter = jasmine.createSpyObj('reporter', events);
|
||||
subject.addReporter(reporter);
|
||||
|
||||
for (const eventName of events) {
|
||||
const payload = { payloadFor: eventName };
|
||||
await subject[eventName](payload);
|
||||
expect(reporter[eventName]).toHaveBeenCalledWith(payload);
|
||||
}
|
||||
});
|
||||
|
||||
it('installs and uninstalls the global error handler', function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
||||
globalErrors
|
||||
});
|
||||
|
||||
subject.installGlobalErrors();
|
||||
expect(globalErrors.install).toHaveBeenCalled();
|
||||
|
||||
subject.uninstallGlobalErrors();
|
||||
expect(globalErrors.uninstall).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles global errors from async reporters', async function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const onError = jasmine.createSpy('onError');
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||
globalErrors
|
||||
});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'jasmineStarted',
|
||||
'jasmineDone'
|
||||
]);
|
||||
let resolveStarted;
|
||||
reporter.jasmineStarted.and.callFake(function() {
|
||||
return new Promise(function(res) {
|
||||
resolveStarted = res;
|
||||
});
|
||||
});
|
||||
subject.addReporter(reporter);
|
||||
|
||||
const promise = subject.jasmineStarted({});
|
||||
expect(globalErrors.pushListener).toHaveBeenCalled();
|
||||
expect(globalErrors.popListener).not.toHaveBeenCalled();
|
||||
const error = new Error('nope');
|
||||
globalErrors.pushListener.calls.argsFor(0)[0](error);
|
||||
expect(onError).toHaveBeenCalledWith(error);
|
||||
|
||||
resolveStarted();
|
||||
await promise;
|
||||
expect(globalErrors.popListener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles done(error) from callback-style async reporters', function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const onError = jasmine.createSpy('onError');
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||
globalErrors
|
||||
});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'jasmineStarted',
|
||||
'jasmineDone'
|
||||
]);
|
||||
let callback;
|
||||
reporter.jasmineStarted = function(event, cb) {
|
||||
callback = cb;
|
||||
};
|
||||
subject.addReporter(reporter);
|
||||
|
||||
subject.jasmineStarted({});
|
||||
|
||||
expect(callback).toBeInstanceOf(Function);
|
||||
const error = new Error('nope');
|
||||
callback(error);
|
||||
|
||||
expect(onError).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('handles done.fail() from callback-style async reporters', function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const onError = jasmine.createSpy('onError');
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||
globalErrors
|
||||
});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'jasmineStarted',
|
||||
'jasmineDone'
|
||||
]);
|
||||
let callback;
|
||||
reporter.jasmineStarted = function(event, cb) {
|
||||
callback = cb;
|
||||
};
|
||||
subject.addReporter(reporter);
|
||||
|
||||
subject.jasmineStarted({});
|
||||
|
||||
expect(callback).toBeInstanceOf(Function);
|
||||
const error = new Error('nope');
|
||||
callback.fail(error);
|
||||
expect(onError).toHaveBeenCalledWith(error);
|
||||
onError.calls.reset();
|
||||
|
||||
callback.fail();
|
||||
expect(onError).toHaveBeenCalledWith(
|
||||
new Error('A reporter called done.fail()')
|
||||
);
|
||||
});
|
||||
|
||||
it('handles errors due to mixed async style in reporters', async function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const onError = jasmine.createSpy('onError');
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||
globalErrors
|
||||
});
|
||||
subject.addReporter({
|
||||
async jasmineStarted(event, done) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
await subject.jasmineStarted({});
|
||||
expect(onError).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
'An asynchronous before/it/after function took a done callback but also returned a promise. Either remove the done callback (recommended) or change the function to not return a promise.'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('handles errors due to multiple done calls in reporters', async function() {
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const onError = jasmine.createSpy('onError');
|
||||
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||
globalErrors
|
||||
});
|
||||
subject.addReporter({
|
||||
jasmineStarted(event, done) {
|
||||
done();
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
await subject.jasmineStarted({});
|
||||
expect(onError).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
"An asynchronous reporter callback called its 'done' callback more than once."
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
function mockGlobalErrors() {
|
||||
const globalErrors = jasmine.createSpyObj('globalErrors', [
|
||||
'install',
|
||||
'pushListener',
|
||||
'popListener'
|
||||
]);
|
||||
|
||||
globalErrors.install.and.callFake(function() {
|
||||
globalErrors.uninstall = jasmine.createSpy('globalErrors.uninstall');
|
||||
});
|
||||
|
||||
return globalErrors;
|
||||
}
|
||||
});
|
||||
@@ -164,7 +164,7 @@ describe('PrettyPrinter', function() {
|
||||
"Object({ foo: 'bar', baz: 3, nullValue: null, undefinedValue: undefined })"
|
||||
);
|
||||
expect(pp({ foo: function() {}, bar: [1, 2, 3] })).toEqual(
|
||||
'Object({ foo: Function, bar: [ 1, 2, 3 ] })'
|
||||
"Object({ foo: Function 'foo', bar: [ 1, 2, 3 ] })"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -450,7 +450,7 @@ describe('PrettyPrinter', function() {
|
||||
};
|
||||
|
||||
expect(pp(objFromOtherContext)).toEqual(
|
||||
"Object({ foo: 'bar', toString: Function })"
|
||||
"Object({ foo: 'bar', toString: Function 'toString' })"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -477,6 +477,17 @@ describe('PrettyPrinter', function() {
|
||||
expect(pp(a)).toEqual('<anonymous>({ })');
|
||||
});
|
||||
|
||||
it('stringifies functions with names', function() {
|
||||
const pp = jasmineUnderTest.makePrettyPrinter();
|
||||
expect(pp(foo)).toEqual("Function 'foo'");
|
||||
function foo() {}
|
||||
});
|
||||
|
||||
it('stringifies functions without names', function() {
|
||||
const pp = jasmineUnderTest.makePrettyPrinter();
|
||||
expect(pp(function() {})).toEqual('Function');
|
||||
});
|
||||
|
||||
it('should handle objects with null prototype', function() {
|
||||
const pp = jasmineUnderTest.makePrettyPrinter();
|
||||
const obj = Object.create(null);
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
describe('QueueRunner', function() {
|
||||
it('validates that queueableFns are truthy', function() {
|
||||
expect(function() {
|
||||
new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [undefined]
|
||||
});
|
||||
}).toThrowError('Received a falsy queueableFn');
|
||||
});
|
||||
|
||||
it('validates that queueableFns have fn properties', function() {
|
||||
expect(function() {
|
||||
new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [{ fn: undefined }]
|
||||
});
|
||||
}).toThrowError('Received a queueableFn with no fn');
|
||||
});
|
||||
|
||||
it("runs all the functions it's passed", function() {
|
||||
const calls = [],
|
||||
queueableFn1 = { fn: jasmine.createSpy('fn1') },
|
||||
@@ -185,43 +201,20 @@ describe('QueueRunner', function() {
|
||||
|
||||
queueRunner.execute();
|
||||
});
|
||||
|
||||
it('does not log a deprecation', function(done) {
|
||||
const err = new Error('foo'),
|
||||
queueableFn1 = {
|
||||
fn: function() {
|
||||
return Promise.resolve(err);
|
||||
}
|
||||
},
|
||||
deprecated = jasmine.createSpy('deprecated'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn1],
|
||||
deprecated: deprecated,
|
||||
onComplete: function() {
|
||||
expect(deprecated).not.toHaveBeenCalled();
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
});
|
||||
});
|
||||
|
||||
describe('and the argument is not an Error', function() {
|
||||
it('does not log a deprecation or report a failure', function(done) {
|
||||
it('does not report a failure', function(done) {
|
||||
const queueableFn1 = {
|
||||
fn: function() {
|
||||
return Promise.resolve('not an error');
|
||||
}
|
||||
},
|
||||
failFn = jasmine.createSpy('fail'),
|
||||
deprecated = jasmine.createSpy('deprecated'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn1],
|
||||
deprecated: deprecated,
|
||||
fail: failFn,
|
||||
onComplete: function() {
|
||||
expect(deprecated).not.toHaveBeenCalled();
|
||||
expect(failFn).not.toHaveBeenCalled();
|
||||
done();
|
||||
}
|
||||
@@ -262,7 +255,6 @@ describe('QueueRunner', function() {
|
||||
|
||||
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
|
||||
const timeout = 3,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
beforeFn = { fn: function(done) {}, type: 'before', timeout: timeout },
|
||||
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
|
||||
onComplete = jasmine.createSpy('onComplete'),
|
||||
@@ -310,7 +302,6 @@ describe('QueueRunner', function() {
|
||||
});
|
||||
|
||||
it('by default does not set a timeout for asynchronous functions', function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const beforeFn = { fn: function(done) {} },
|
||||
queueableFn = { fn: jasmine.createSpy('fn') },
|
||||
onComplete = jasmine.createSpy('onComplete'),
|
||||
@@ -333,7 +324,6 @@ describe('QueueRunner', function() {
|
||||
|
||||
it('clears the timeout when an async function throws an exception, to prevent additional exception reporting', function() {
|
||||
const queueableFn = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
fn: function(done) {
|
||||
throw new Error('error!');
|
||||
}
|
||||
@@ -406,17 +396,12 @@ describe('QueueRunner', function() {
|
||||
}
|
||||
},
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
|
||||
deprecated = jasmine.createSpy('deprecated'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
deprecated: deprecated,
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
});
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick(1);
|
||||
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
||||
// Don't issue a deprecation. The error already tells the user that
|
||||
// something went wrong.
|
||||
expect(deprecated).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return a null when you call done', function() {
|
||||
@@ -437,7 +422,6 @@ describe('QueueRunner', function() {
|
||||
|
||||
it('continues running functions when an exception is thrown in async code without timing out', function() {
|
||||
const queueableFn = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
fn: function(done) {
|
||||
throwAsync();
|
||||
},
|
||||
@@ -487,6 +471,31 @@ describe('QueueRunner', function() {
|
||||
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles a global error event with a message but no error', function() {
|
||||
const queueableFn = {
|
||||
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) {
|
||||
@@ -520,6 +529,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() {
|
||||
@@ -609,7 +652,6 @@ describe('QueueRunner', function() {
|
||||
|
||||
it('issues an error if the function also takes a parameter', function() {
|
||||
const queueableFn = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
fn: function(done) {
|
||||
return new StubPromise();
|
||||
}
|
||||
@@ -623,16 +665,17 @@ describe('QueueRunner', function() {
|
||||
queueRunner.execute();
|
||||
|
||||
expect(onException).toHaveBeenCalledWith(
|
||||
'An asynchronous ' +
|
||||
'before/it/after function took a done callback but also returned a ' +
|
||||
'promise. ' +
|
||||
'Either remove the done callback (recommended) or change the function ' +
|
||||
'to not return a promise.'
|
||||
new Error(
|
||||
'An asynchronous ' +
|
||||
'before/it/after function took a done callback but also returned a ' +
|
||||
'promise. ' +
|
||||
'Either remove the done callback (recommended) or change the function ' +
|
||||
'to not return a promise.'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('issues a more specific error if the function is `async`', function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async function fn(done) {}
|
||||
const onException = jasmine.createSpy('onException'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
@@ -643,15 +686,17 @@ describe('QueueRunner', function() {
|
||||
queueRunner.execute();
|
||||
|
||||
expect(onException).toHaveBeenCalledWith(
|
||||
'An asynchronous ' +
|
||||
'before/it/after function was defined with the async keyword but ' +
|
||||
'also took a done callback. Either remove the done callback ' +
|
||||
'(recommended) or remove the async keyword.'
|
||||
new Error(
|
||||
'An asynchronous ' +
|
||||
'before/it/after function was defined with the async keyword but ' +
|
||||
'also took a done callback. Either remove the done callback ' +
|
||||
'(recommended) or remove the async keyword.'
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('passes the error instance to exception handlers in HTML browsers', function() {
|
||||
it('passes final errors to exception handlers', function() {
|
||||
const error = new Error('fake error'),
|
||||
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
@@ -659,24 +704,11 @@ describe('QueueRunner', function() {
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
queueRunner.handleFinalError(error.message, 'fake.js', 1, 1, error);
|
||||
queueRunner.handleFinalError(error);
|
||||
|
||||
expect(onExceptionCallback).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('passes the first argument to exception handlers for compatibility', function() {
|
||||
const error = new Error('fake error'),
|
||||
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
onException: onExceptionCallback
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
queueRunner.handleFinalError(error.message);
|
||||
|
||||
expect(onExceptionCallback).toHaveBeenCalledWith(error.message);
|
||||
});
|
||||
|
||||
it('calls exception handlers when an exception is thrown in a fn', function() {
|
||||
const queueableFn = {
|
||||
type: 'queueable',
|
||||
@@ -697,7 +729,6 @@ describe('QueueRunner', function() {
|
||||
|
||||
it('continues running the functions even after an exception is thrown in an async spec', function() {
|
||||
const queueableFn = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
fn: function(done) {
|
||||
throw new Error('error');
|
||||
}
|
||||
|
||||
@@ -12,21 +12,20 @@ describe('ReportDispatcher', function() {
|
||||
});
|
||||
|
||||
it('dispatches requested methods to added reporters', function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
|
||||
const runQueue = jasmine.createSpy('runQueue'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(
|
||||
['foo', 'bar'],
|
||||
queueRunnerFactory
|
||||
runQueue
|
||||
),
|
||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||
completeCallback = jasmine.createSpy('complete');
|
||||
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
|
||||
|
||||
dispatcher.addReporter(reporter);
|
||||
dispatcher.addReporter(anotherReporter);
|
||||
|
||||
dispatcher.foo(123, 456, completeCallback);
|
||||
dispatcher.foo(123, 456);
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [
|
||||
{ fn: jasmine.any(Function) },
|
||||
@@ -36,7 +35,7 @@ describe('ReportDispatcher', function() {
|
||||
})
|
||||
);
|
||||
|
||||
let fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
let fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
expect(reporter.foo.calls.mostRecent().object).toBe(reporter);
|
||||
@@ -45,11 +44,11 @@ describe('ReportDispatcher', function() {
|
||||
expect(anotherReporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
expect(anotherReporter.foo.calls.mostRecent().object).toBe(anotherReporter);
|
||||
|
||||
queueRunnerFactory.calls.reset();
|
||||
runQueue.calls.reset();
|
||||
|
||||
dispatcher.bar('a', 'b', completeCallback);
|
||||
dispatcher.bar('a', 'b');
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [
|
||||
{ fn: jasmine.any(Function) },
|
||||
@@ -59,7 +58,7 @@ describe('ReportDispatcher', function() {
|
||||
})
|
||||
);
|
||||
|
||||
fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter.bar).toHaveBeenCalledWith('a', 'b');
|
||||
|
||||
@@ -68,17 +67,14 @@ describe('ReportDispatcher', function() {
|
||||
});
|
||||
|
||||
it("does not dispatch to a reporter if the reporter doesn't accept the method", function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(
|
||||
['foo'],
|
||||
queueRunnerFactory
|
||||
),
|
||||
const runQueue = jasmine.createSpy('runQueue'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(['foo'], runQueue),
|
||||
reporter = jasmine.createSpyObj('reporter', ['baz']);
|
||||
|
||||
dispatcher.addReporter(reporter);
|
||||
|
||||
dispatcher.foo(123, 456);
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: []
|
||||
})
|
||||
@@ -86,91 +82,88 @@ describe('ReportDispatcher', function() {
|
||||
});
|
||||
|
||||
it("allows providing a fallback reporter in case there's no other reporter", function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
|
||||
const runQueue = jasmine.createSpy('runQueue'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(
|
||||
['foo', 'bar'],
|
||||
queueRunnerFactory
|
||||
runQueue
|
||||
),
|
||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||
completeCallback = jasmine.createSpy('complete');
|
||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
|
||||
|
||||
dispatcher.provideFallbackReporter(reporter);
|
||||
dispatcher.foo(123, 456, completeCallback);
|
||||
dispatcher.foo(123, 456);
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
isReporter: true
|
||||
})
|
||||
);
|
||||
|
||||
const fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
const fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
});
|
||||
|
||||
it('does not call fallback reporting methods when another reporter is provided', function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
|
||||
const runQueue = jasmine.createSpy('runQueue'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(
|
||||
['foo', 'bar'],
|
||||
queueRunnerFactory
|
||||
runQueue
|
||||
),
|
||||
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
|
||||
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']),
|
||||
completeCallback = jasmine.createSpy('complete');
|
||||
fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']);
|
||||
|
||||
dispatcher.provideFallbackReporter(fallbackReporter);
|
||||
dispatcher.addReporter(reporter);
|
||||
dispatcher.foo(123, 456, completeCallback);
|
||||
dispatcher.foo(123, 456);
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
isReporter: true
|
||||
})
|
||||
);
|
||||
|
||||
const fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
const fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
expect(fallbackReporter.foo).not.toHaveBeenCalledWith(123, 456);
|
||||
});
|
||||
|
||||
it('allows registered reporters to be cleared', function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunner'),
|
||||
const runQueue = jasmine.createSpy('runQueue'),
|
||||
dispatcher = new jasmineUnderTest.ReportDispatcher(
|
||||
['foo', 'bar'],
|
||||
queueRunnerFactory
|
||||
runQueue
|
||||
),
|
||||
reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']),
|
||||
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']),
|
||||
completeCallback = jasmine.createSpy('complete');
|
||||
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']);
|
||||
|
||||
dispatcher.addReporter(reporter1);
|
||||
dispatcher.foo(123, completeCallback);
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
dispatcher.foo(123);
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
isReporter: true
|
||||
})
|
||||
);
|
||||
|
||||
let fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
let fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter1.foo).toHaveBeenCalledWith(123);
|
||||
|
||||
dispatcher.clearReporters();
|
||||
dispatcher.addReporter(reporter2);
|
||||
dispatcher.bar(456, completeCallback);
|
||||
dispatcher.bar(456);
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalledWith(
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
isReporter: true
|
||||
})
|
||||
);
|
||||
|
||||
fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns;
|
||||
fns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
fns[0].fn();
|
||||
expect(reporter1.bar).not.toHaveBeenCalled();
|
||||
expect(reporter2.bar).toHaveBeenCalledWith(456);
|
||||
|
||||
630
spec/core/RunnerSpec.js
Normal file
630
spec/core/RunnerSpec.js
Normal file
@@ -0,0 +1,630 @@
|
||||
describe('Runner', function() {
|
||||
describe('Integration with TreeProcessor and TreeRunner', function() {
|
||||
let suiteNumber,
|
||||
specNumber,
|
||||
runQueue,
|
||||
globalErrors,
|
||||
reportDispatcher,
|
||||
failSpecWithNoExpectations,
|
||||
detectLateRejectionHandling;
|
||||
|
||||
beforeEach(function() {
|
||||
suiteNumber = 0;
|
||||
specNumber = 0;
|
||||
runQueue = jasmine.createSpy('runQueue');
|
||||
globalErrors = 'the global errors instance';
|
||||
reportDispatcher = jasmine.createSpyObj(
|
||||
'reportDispatcher',
|
||||
jasmineUnderTest.reporterEvents
|
||||
);
|
||||
|
||||
for (const k of jasmineUnderTest.reporterEvents) {
|
||||
reportDispatcher[k].and.returnValue(Promise.resolve());
|
||||
}
|
||||
|
||||
// Reasonable defaults, may be overridden in some cases
|
||||
failSpecWithNoExpectations = false;
|
||||
detectLateRejectionHandling = false;
|
||||
|
||||
spyOn(jasmineUnderTest.TreeRunner.prototype, '_executeSpec');
|
||||
});
|
||||
|
||||
function StubSuite(attrs) {
|
||||
attrs = attrs || {};
|
||||
this.id = 'suite' + suiteNumber++;
|
||||
this.children = attrs.children || [];
|
||||
this.canBeReentered = function() {
|
||||
return !attrs.noReenter;
|
||||
};
|
||||
this.markedPending = attrs.markedPending || false;
|
||||
this.sharedUserContext = function() {
|
||||
return attrs.userContext || {};
|
||||
};
|
||||
this.result = {
|
||||
id: this.id,
|
||||
failedExpectations: []
|
||||
};
|
||||
this.getResult = jasmine.createSpy('getResult');
|
||||
this.beforeAllFns = attrs.beforeAllFns || [];
|
||||
this.afterAllFns = attrs.afterAllFns || [];
|
||||
this.cleanupBeforeAfter = function() {};
|
||||
this.startTimer = function() {};
|
||||
this.endTimer = function() {};
|
||||
}
|
||||
|
||||
function StubSpec(attrs) {
|
||||
attrs = attrs || {};
|
||||
this.id = 'spec' + specNumber++;
|
||||
this.markedPending = attrs.markedPending || false;
|
||||
this.execute = jasmine.createSpy(this.id + '#execute');
|
||||
this.beforeAndAfterFns = () => ({ befores: [], afters: [] });
|
||||
this.userContext = () => ({});
|
||||
this.getFullName = () => '';
|
||||
this.queueableFn = () => {};
|
||||
}
|
||||
|
||||
function makeRunner(topSuite) {
|
||||
const defaultOptions = {
|
||||
getConfig: () => ({
|
||||
specFilter: () => true,
|
||||
failSpecWithNoExpectations,
|
||||
detectLateRejectionHandling
|
||||
}),
|
||||
focusedRunables: () => [],
|
||||
totalSpecsDefined: () => 1,
|
||||
TreeProcessor: jasmineUnderTest.TreeProcessor,
|
||||
runableResources: {
|
||||
initForRunable: () => {},
|
||||
clearForRunable: () => {}
|
||||
},
|
||||
reportDispatcher,
|
||||
globalErrors,
|
||||
runQueue
|
||||
};
|
||||
return new jasmineUnderTest.Runner({
|
||||
...defaultOptions,
|
||||
topSuite
|
||||
});
|
||||
}
|
||||
|
||||
function arrayNotContaining(item) {
|
||||
return {
|
||||
asymmetricMatch(other, matchersUtil) {
|
||||
if (!jasmine.isArray_(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const x of other) {
|
||||
if (matchersUtil.equals(x, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Precondition: jasmineUnderTest.TreeRunner.prototype._executeSpec is a spy
|
||||
function verifyAndFinishSpec(spec, queueableFn, shouldBeExcluded) {
|
||||
const ex = jasmineUnderTest.TreeRunner.prototype._executeSpec;
|
||||
ex.withArgs(spec, 'onComplete').and.callThrough();
|
||||
|
||||
queueableFn.fn('onComplete');
|
||||
expect(ex).toHaveBeenCalledWith(spec, 'onComplete');
|
||||
|
||||
expect(runQueue).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
isLeaf: true,
|
||||
SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy,
|
||||
queueableFns: shouldBeExcluded
|
||||
? arrayNotContaining(spec.queueableFn)
|
||||
: jasmine.arrayContaining([spec.queueableFn])
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
it('runs a single spec', async function() {
|
||||
const spec = new StubSpec();
|
||||
const topSuite = new StubSuite({
|
||||
children: [spec],
|
||||
userContext: { root: 'context' }
|
||||
});
|
||||
detectLateRejectionHandling = true;
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(runQueue).toHaveBeenCalledWith({
|
||||
onComplete: jasmine.any(Function),
|
||||
onException: jasmine.any(Function),
|
||||
userContext: { root: 'context' },
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
onMultipleDone: null,
|
||||
SkipPolicy: jasmineUnderTest.SkipAfterBeforeAllErrorPolicy
|
||||
});
|
||||
|
||||
const runQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
verifyAndFinishSpec(spec, runQueueArgs.queueableFns[0], false);
|
||||
runQueueArgs.onComplete();
|
||||
await promise;
|
||||
});
|
||||
|
||||
it('runs an empty suite', async function() {
|
||||
const suite = new StubSuite({ userContext: { for: 'suite' } });
|
||||
const topSuite = new StubSuite({
|
||||
children: [suite],
|
||||
userContext: { for: 'topSuite' }
|
||||
});
|
||||
suite.parentSuite = topSuite;
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(runQueue).toHaveBeenCalledWith({
|
||||
onComplete: jasmine.any(Function),
|
||||
onException: jasmine.any(Function),
|
||||
userContext: { for: 'topSuite' },
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
onMultipleDone: null,
|
||||
SkipPolicy: jasmineUnderTest.SkipAfterBeforeAllErrorPolicy
|
||||
});
|
||||
|
||||
const runQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
const nodeDone = jasmine.createSpy('nodeDone');
|
||||
runQueueArgs.queueableFns[0].fn(nodeDone);
|
||||
expect(runQueue).toHaveBeenCalledWith({
|
||||
onComplete: jasmine.any(Function),
|
||||
onMultipleDone: null,
|
||||
queueableFns: [{ fn: jasmine.any(Function) }],
|
||||
userContext: { for: 'suite' },
|
||||
onException: jasmine.any(Function),
|
||||
onMultipleDone: null,
|
||||
SkipPolicy: jasmineUnderTest.SkipAfterBeforeAllErrorPolicy
|
||||
});
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[0].fn('foo');
|
||||
expect(reportDispatcher.suiteStarted).toHaveBeenCalledWith(suite.result);
|
||||
|
||||
suite.getResult.and.returnValue({ my: 'result' });
|
||||
|
||||
runQueue.calls.mostRecent().args[0].onComplete();
|
||||
expect(reportDispatcher.suiteDone).toHaveBeenCalledWith({ my: 'result' });
|
||||
|
||||
runQueueArgs.onComplete();
|
||||
await promise;
|
||||
});
|
||||
|
||||
it('runs a non-empty suite', async function() {
|
||||
const spec1 = new StubSpec();
|
||||
const spec2 = new StubSpec();
|
||||
const suite = new StubSuite({ children: [spec1, spec2] });
|
||||
const topSuite = new StubSuite({ children: [suite] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
let queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(2);
|
||||
queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(3);
|
||||
|
||||
verifyAndFinishSpec(spec1, queueableFns[1], false);
|
||||
verifyAndFinishSpec(spec2, queueableFns[2], false);
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('"runs" an excluded suite', async function() {
|
||||
const spec = new StubSpec();
|
||||
const parent = new StubSuite({ children: [spec] });
|
||||
const topSuite = new StubSuite({ children: [parent] });
|
||||
parent.parentSuite = topSuite;
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
// Empty list of runable IDs excludes everything
|
||||
const promise = subject.execute([]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
let queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(2);
|
||||
|
||||
queueableFns[0].fn();
|
||||
expect(reportDispatcher.suiteStarted).toHaveBeenCalledWith(parent.result);
|
||||
|
||||
verifyAndFinishSpec(spec, queueableFns[1], true);
|
||||
|
||||
parent.getResult.and.returnValue(parent.result);
|
||||
runQueue.calls.argsFor(1)[0].onComplete();
|
||||
expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(parent.result);
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('handles the failSpecWithNoExpectations option', async function() {
|
||||
failSpecWithNoExpectations = true;
|
||||
const spec = new StubSpec();
|
||||
const parent = new StubSuite({ children: [spec] });
|
||||
const topSuite = new StubSuite({ children: [parent] });
|
||||
parent.parentSuite = topSuite;
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
let queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(2);
|
||||
|
||||
queueableFns[1].fn('foo');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec, 'foo');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs beforeAlls and afterAlls for a suite with children', async function() {
|
||||
const spec = new StubSpec();
|
||||
const target = new StubSuite({
|
||||
children: [spec],
|
||||
beforeAllFns: [
|
||||
{ fn: 'beforeAll1', timeout: 1 },
|
||||
{ fn: 'beforeAll2', timeout: 2 }
|
||||
],
|
||||
afterAllFns: [
|
||||
{ fn: 'afterAll1', timeout: 3 },
|
||||
{ fn: 'afterAll2', timeout: 4 }
|
||||
]
|
||||
});
|
||||
const topSuite = new StubSuite({ children: [target] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns).toEqual([
|
||||
{ fn: jasmine.any(Function) },
|
||||
{ fn: 'beforeAll1', timeout: 1 },
|
||||
{ fn: 'beforeAll2', timeout: 2 },
|
||||
{ fn: jasmine.any(Function) },
|
||||
{ fn: 'afterAll1', timeout: 3 },
|
||||
{ fn: 'afterAll2', timeout: 4 }
|
||||
]);
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('does not run beforeAlls or afterAlls for a suite with no children', async function() {
|
||||
const target = new StubSuite({
|
||||
beforeAllFns: [{ fn: 'before' }],
|
||||
afterAllFns: [{ fn: 'after' }]
|
||||
});
|
||||
const topSuite = new StubSuite({ children: [target] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toEqual(
|
||||
1
|
||||
);
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('does not run beforeAlls or afterAlls for a suite with only pending children', async function() {
|
||||
const spec = new StubSpec({ markedPending: true });
|
||||
const target = new StubSuite({
|
||||
children: [spec],
|
||||
beforeAllFns: [{ fn: 'before' }],
|
||||
afterAllFns: [{ fn: 'after' }]
|
||||
});
|
||||
const topSuite = new StubSuite({ children: [target] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toEqual(
|
||||
2
|
||||
);
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs specs in the order specified', async function() {
|
||||
const specs = [new StubSpec(), new StubSpec()];
|
||||
const topSuite = new StubSuite({ children: specs });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute([specs[1].id, specs[0].id]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn('done');
|
||||
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).not.toHaveBeenCalledWith(specs[0], jasmine.anything());
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(specs[1], 'done');
|
||||
|
||||
queueableFns[1].fn('done');
|
||||
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(specs[0], 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs specified specs before non-specified specs within a suite', async function() {
|
||||
const specified = new StubSpec();
|
||||
const nonSpecified = new StubSpec();
|
||||
const topSuite = new StubSuite({ children: [nonSpecified, specified] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute([specified.id]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn('done');
|
||||
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).not.toHaveBeenCalledWith(nonSpecified, jasmine.anything());
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(specified, 'done');
|
||||
|
||||
queueableFns[1].fn('done');
|
||||
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(nonSpecified, 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs suites and specs with a specified order', async function() {
|
||||
const specifiedSpec = new StubSpec();
|
||||
const nonSpecifiedSpec = new StubSpec();
|
||||
const specifiedSuite = new StubSuite({ children: [nonSpecifiedSpec] });
|
||||
const topSuite = new StubSuite({
|
||||
children: [specifiedSpec, specifiedSuite]
|
||||
});
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute([specifiedSuite.id, specifiedSpec.id]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn();
|
||||
|
||||
expect(specifiedSpec.execute).not.toHaveBeenCalled();
|
||||
const nodeQueueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
nodeQueueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(nonSpecifiedSpec, 'done');
|
||||
|
||||
queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(specifiedSpec, 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs suites and specs in the order they were declared', async function() {
|
||||
const spec1 = new StubSpec();
|
||||
const spec2 = new StubSpec();
|
||||
const spec3 = new StubSpec();
|
||||
const parent = new StubSuite({ children: [spec2, spec3] });
|
||||
const topSuite = new StubSuite({ children: [spec1, parent] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(2);
|
||||
|
||||
queueableFns[0].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec1, 'done');
|
||||
|
||||
queueableFns[1].fn();
|
||||
const childFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(childFns.length).toBe(3);
|
||||
childFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec2, 'done');
|
||||
|
||||
childFns[2].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec3, 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs a suite multiple times if the order specified leaves and re-enters it', async function() {
|
||||
const spec1 = new StubSpec();
|
||||
const spec2 = new StubSpec();
|
||||
const spec3 = new StubSpec();
|
||||
const spec4 = new StubSpec();
|
||||
const spec5 = new StubSpec();
|
||||
const reentered = new StubSuite({ children: [spec1, spec2, spec3] });
|
||||
const topSuite = new StubSuite({ children: [reentered, spec4, spec5] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
spyOn(jasmineUnderTest.getEnv(), 'deprecated');
|
||||
const promise = subject.execute([
|
||||
spec1.id,
|
||||
spec4.id,
|
||||
spec2.id,
|
||||
spec5.id,
|
||||
spec3.id
|
||||
]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
queueableFns[0].fn();
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec1, 'done');
|
||||
|
||||
queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec4, 'done');
|
||||
|
||||
queueableFns[2].fn();
|
||||
expect(runQueue.calls.count()).toBe(3);
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec2, 'done');
|
||||
|
||||
queueableFns[3].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec5, 'done');
|
||||
|
||||
queueableFns[4].fn();
|
||||
expect(runQueue.calls.count()).toBe(4);
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec3, 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs a parent of a suite with multiple segments correctly', async function() {
|
||||
const spec1 = new StubSpec();
|
||||
const spec2 = new StubSpec();
|
||||
const spec3 = new StubSpec();
|
||||
const spec4 = new StubSpec();
|
||||
const spec5 = new StubSpec();
|
||||
const parent = new StubSuite({ children: [spec1, spec2, spec3] });
|
||||
const grandparent = new StubSuite({ children: [parent] });
|
||||
const topSuite = new StubSuite({ children: [grandparent, spec4, spec5] });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
spyOn(jasmineUnderTest.getEnv(), 'deprecated');
|
||||
const promise = subject.execute([
|
||||
spec1.id,
|
||||
spec4.id,
|
||||
spec2.id,
|
||||
spec5.id,
|
||||
spec3.id
|
||||
]);
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(5);
|
||||
|
||||
queueableFns[0].fn();
|
||||
expect(runQueue.calls.count()).toBe(2);
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn();
|
||||
expect(runQueue.calls.count()).toBe(3);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec1, 'done');
|
||||
|
||||
queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec4, 'done');
|
||||
|
||||
queueableFns[2].fn();
|
||||
expect(runQueue.calls.count()).toBe(4);
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn();
|
||||
expect(runQueue.calls.count()).toBe(5);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec2, 'done');
|
||||
|
||||
queueableFns[3].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec5, 'done');
|
||||
|
||||
queueableFns[4].fn();
|
||||
expect(runQueue.calls.count()).toBe(6);
|
||||
expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn();
|
||||
expect(runQueue.calls.count()).toBe(7);
|
||||
|
||||
runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(spec3, 'done');
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
|
||||
it('runs large segments of nodes in the order they were declared', async function() {
|
||||
const specs = [];
|
||||
|
||||
for (let i = 0; i < 11; i++) {
|
||||
specs.push(new StubSpec());
|
||||
}
|
||||
|
||||
const topSuite = new StubSuite({ children: specs });
|
||||
const subject = makeRunner(topSuite);
|
||||
|
||||
const promise = subject.execute();
|
||||
await Promise.resolve();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(11);
|
||||
|
||||
for (let i = 0; i < 11; i++) {
|
||||
queueableFns[i].fn('done');
|
||||
expect(
|
||||
jasmineUnderTest.TreeRunner.prototype._executeSpec
|
||||
).toHaveBeenCalledWith(specs[i], 'done');
|
||||
}
|
||||
|
||||
await expectAsync(promise).toBePending();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -33,112 +33,6 @@ describe('Spec', function() {
|
||||
expect(jasmineUnderTest.Spec.isPendingSpecException(void 0)).toBe(false);
|
||||
});
|
||||
|
||||
it('delegates execution to a QueueRunner', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
description: 'my test',
|
||||
id: 'some-id',
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
expect(fakeQueueRunner).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call the start callback on execution', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
id: 123,
|
||||
description: 'foo bar',
|
||||
queueableFn: { fn: function() {} },
|
||||
onStart: startCallback
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
expect(startCallback.calls.first().object).toEqual(spec);
|
||||
});
|
||||
|
||||
it('should call the start callback on execution but before any befores are called', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner');
|
||||
let beforesWereCalled = false;
|
||||
const startCallback = jasmine
|
||||
.createSpy('start-callback')
|
||||
.and.callFake(function() {
|
||||
expect(beforesWereCalled).toBe(false);
|
||||
});
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
beforeFns: function() {
|
||||
return [
|
||||
function() {
|
||||
beforesWereCalled = true;
|
||||
}
|
||||
];
|
||||
},
|
||||
onStart: startCallback
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('provides all before fns and after fns to be run', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
before = jasmine.createSpy('before'),
|
||||
after = jasmine.createSpy('after'),
|
||||
queueableFn = {
|
||||
fn: jasmine.createSpy('test body').and.callFake(function() {
|
||||
expect(before).toHaveBeenCalled();
|
||||
expect(after).not.toHaveBeenCalled();
|
||||
})
|
||||
},
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: queueableFn,
|
||||
beforeAndAfterFns: function() {
|
||||
return { befores: [before], afters: [after] };
|
||||
}
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
const options = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
expect(options.queueableFns).toEqual([
|
||||
{ fn: jasmine.any(Function) },
|
||||
before,
|
||||
queueableFn,
|
||||
after,
|
||||
{
|
||||
fn: jasmine.any(Function),
|
||||
type: 'specCleanup'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("tells the queue runner that it's a leaf node", function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
beforeAndAfterFns: function() {
|
||||
return { befores: [], afters: [] };
|
||||
}
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
expect(fakeQueueRunner).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
isLeaf: true
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('is marked pending if created without a function body', function() {
|
||||
const startCallback = jasmine.createSpy('startCallback'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
@@ -151,162 +45,75 @@ describe('Spec', function() {
|
||||
expect(spec.status()).toBe('pending');
|
||||
});
|
||||
|
||||
it('can be excluded at execution time by a parent', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
specBody = jasmine.createSpy('specBody'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
onStart: startCallback,
|
||||
queueableFn: { fn: specBody },
|
||||
resultCallback: resultCallback
|
||||
describe('#executionFinished', function() {
|
||||
it('removes the fn if autoCleanClosures is true', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} },
|
||||
autoCleanClosures: true
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner, 'cally-back', true);
|
||||
|
||||
expect(fakeQueueRunner).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
onComplete: jasmine.any(Function),
|
||||
queueableFns: [
|
||||
{ fn: jasmine.any(Function) },
|
||||
{
|
||||
fn: jasmine.any(Function),
|
||||
type: 'specCleanup'
|
||||
}
|
||||
]
|
||||
})
|
||||
);
|
||||
expect(specBody).not.toHaveBeenCalled();
|
||||
|
||||
const args = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
args.queueableFns[0].fn();
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
args.queueableFns[args.queueableFns.length - 1].fn();
|
||||
expect(resultCallback).toHaveBeenCalled();
|
||||
|
||||
expect(spec.result.status).toBe('excluded');
|
||||
});
|
||||
|
||||
it('can be marked pending, but still calls callbacks when executed', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
onStart: startCallback,
|
||||
resultCallback: resultCallback,
|
||||
description: 'with a spec',
|
||||
getSpecName: function() {
|
||||
return 'a suite with a spec';
|
||||
},
|
||||
queueableFn: { fn: null }
|
||||
});
|
||||
|
||||
spec.pend();
|
||||
|
||||
expect(spec.status()).toBe('pending');
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
expect(fakeQueueRunner).toHaveBeenCalled();
|
||||
|
||||
const args = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
args.queueableFns[0].fn();
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
args.queueableFns[1].fn('things');
|
||||
expect(resultCallback).toHaveBeenCalledWith(
|
||||
{
|
||||
id: spec.id,
|
||||
status: 'pending',
|
||||
description: 'with a spec',
|
||||
fullName: 'a suite with a spec',
|
||||
failedExpectations: [],
|
||||
passedExpectations: [],
|
||||
deprecationWarnings: [],
|
||||
pendingReason: '',
|
||||
duration: jasmine.any(Number),
|
||||
properties: null,
|
||||
debugLogs: null
|
||||
},
|
||||
'things'
|
||||
);
|
||||
});
|
||||
|
||||
it('should call the done callback on execution complete', function() {
|
||||
const done = jasmine.createSpy('done callback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
catchExceptions: function() {
|
||||
return false;
|
||||
},
|
||||
resultCallback: function() {}
|
||||
});
|
||||
|
||||
spec.execute(attrs => attrs.onComplete(), done);
|
||||
|
||||
expect(done).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call the done callback with an error if the spec is failed', function() {
|
||||
const done = jasmine.createSpy('done callback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
catchExceptions: function() {
|
||||
return false;
|
||||
},
|
||||
resultCallback: function() {}
|
||||
});
|
||||
|
||||
function queueRunnerFactory(attrs) {
|
||||
spec.result.status = 'failed';
|
||||
attrs.onComplete();
|
||||
}
|
||||
spec.execute(queueRunnerFactory, done);
|
||||
|
||||
expect(done).toHaveBeenCalledWith(
|
||||
jasmine.any(jasmineUnderTest.StopExecutionError)
|
||||
);
|
||||
});
|
||||
|
||||
it('should report the duration of the test', function() {
|
||||
const timer = jasmine.createSpyObj('timer', {
|
||||
start: null,
|
||||
elapsed: 77000
|
||||
});
|
||||
let duration = undefined;
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: jasmine.createSpy('spec body') },
|
||||
catchExceptions: function() {
|
||||
return false;
|
||||
},
|
||||
resultCallback: function(result) {
|
||||
duration = result.duration;
|
||||
},
|
||||
timer: timer
|
||||
spec.executionFinished();
|
||||
expect(spec.queueableFn.fn).toBeFalsy();
|
||||
});
|
||||
|
||||
function queueRunnerFactory(config) {
|
||||
config.queueableFns.forEach(function(qf) {
|
||||
qf.fn();
|
||||
it('removes the fn after execution if autoCleanClosures is undefined', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} },
|
||||
autoCleanClosures: undefined
|
||||
});
|
||||
config.onComplete();
|
||||
}
|
||||
|
||||
spec.execute(queueRunnerFactory, function() {});
|
||||
expect(duration).toBe(77000);
|
||||
spec.executionFinished();
|
||||
expect(spec.queueableFn.fn).toBeFalsy();
|
||||
});
|
||||
|
||||
it('does not remove the fn after execution if autoCleanClosures is false', function() {
|
||||
function originalFn() {}
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: originalFn },
|
||||
autoCleanClosures: false
|
||||
});
|
||||
|
||||
spec.executionFinished();
|
||||
expect(spec.queueableFn.fn).toBe(originalFn);
|
||||
});
|
||||
});
|
||||
|
||||
it('should report properties set during the test', function() {
|
||||
const done = jasmine.createSpy('done callback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: jasmine.createSpy('spec body') },
|
||||
catchExceptions: function() {
|
||||
return false;
|
||||
},
|
||||
resultCallback: function() {}
|
||||
describe('#getSpecProperty', function() {
|
||||
it('get the property value', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
spec.setSpecProperty('a', 4);
|
||||
spec.execute(attrs => attrs.onComplete(), done);
|
||||
expect(spec.result.properties).toEqual({ a: 4 });
|
||||
|
||||
spec.setSpecProperty('a', 4);
|
||||
expect(spec.getSpecProperty('a')).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setSpecProperty', function() {
|
||||
it('adds the property to the result', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.setSpecProperty('a', 4);
|
||||
|
||||
expect(spec.result.properties).toEqual({ a: 4 });
|
||||
});
|
||||
|
||||
it('replace the property result when it was previously set', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.setSpecProperty('a', 'original-value');
|
||||
spec.setSpecProperty('b', 'original-value');
|
||||
spec.setSpecProperty('a', 'new-value');
|
||||
|
||||
expect(spec.result.properties).toEqual({
|
||||
a: 'new-value',
|
||||
b: 'original-value'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('#status returns passing by default', function() {
|
||||
@@ -316,70 +123,84 @@ describe('Spec', function() {
|
||||
expect(spec.status()).toBe('passed');
|
||||
});
|
||||
|
||||
it('#status returns passed if all expectations in the spec have passed', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: jasmine.createSpy('spec body') }
|
||||
});
|
||||
spec.addExpectationResult(true, {});
|
||||
expect(spec.status()).toBe('passed');
|
||||
});
|
||||
|
||||
it('#status returns failed if any expectations in the spec have failed', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: jasmine.createSpy('spec body') }
|
||||
});
|
||||
spec.addExpectationResult(true, {});
|
||||
spec.addExpectationResult(false, {});
|
||||
expect(spec.status()).toBe('failed');
|
||||
});
|
||||
|
||||
it('keeps track of passed and failed expectations', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: jasmine.createSpy('spec body') },
|
||||
resultCallback: resultCallback
|
||||
describe('#status', function() {
|
||||
it('returns "passed"" by default', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
spec.addExpectationResult(true, { message: 'expectation1' });
|
||||
spec.addExpectationResult(false, { message: 'expectation2' });
|
||||
expect(spec.status()).toBe('passed');
|
||||
});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
fns[fns.length - 1].fn();
|
||||
|
||||
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'expectation1' })
|
||||
]);
|
||||
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'expectation2' })
|
||||
]);
|
||||
});
|
||||
|
||||
it("throws an ExpectationFailed error upon receiving a failed expectation when 'throwOnExpectationFailure' is set", function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
resultCallback: resultCallback,
|
||||
throwOnExpectationFailure: true
|
||||
it('returns "passed"" if all expectations passed', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.addExpectationResult(true, { message: 'passed' });
|
||||
expect(function() {
|
||||
spec.addExpectationResult(false, { message: 'failed' });
|
||||
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
|
||||
spec.addExpectationResult(true, {});
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
expect(spec.status()).toBe('passed');
|
||||
});
|
||||
|
||||
const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
fns[fns.length - 1].fn();
|
||||
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'passed' })
|
||||
]);
|
||||
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'failed' })
|
||||
]);
|
||||
it('returns "failed" if any expectation failed', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.addExpectationResult(true, {});
|
||||
spec.addExpectationResult(false, {});
|
||||
|
||||
expect(spec.status()).toBe('failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addExpectationResult', function() {
|
||||
it('keeps track of passed and failed expectations', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.addExpectationResult(true, { message: 'expectation1' });
|
||||
spec.addExpectationResult(false, { message: 'expectation2' });
|
||||
|
||||
expect(spec.result.passedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'expectation1' })
|
||||
]);
|
||||
expect(spec.result.failedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'expectation2' })
|
||||
]);
|
||||
});
|
||||
|
||||
describe("when 'throwOnExpectationFailure' is set", function() {
|
||||
it('throws an ExpectationFailed error', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} },
|
||||
throwOnExpectationFailure: true
|
||||
});
|
||||
|
||||
spec.addExpectationResult(true, { message: 'passed' });
|
||||
expect(function() {
|
||||
spec.addExpectationResult(false, { message: 'failed' });
|
||||
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
|
||||
|
||||
expect(spec.result.failedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'failed' })
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when 'throwOnExpectationFailure' is not set", function() {
|
||||
it('does not throw', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
spec.addExpectationResult(false, { message: 'failed' });
|
||||
|
||||
expect(spec.result.failedExpectations).toEqual([
|
||||
jasmine.objectContaining({ message: 'failed' })
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('forwards late expectation failures to onLateError', function() {
|
||||
@@ -481,138 +302,76 @@ describe('Spec', function() {
|
||||
});
|
||||
|
||||
it('can return its full name', function() {
|
||||
const specNameSpy = jasmine
|
||||
.createSpy('specNameSpy')
|
||||
.and.returnValue('expected val');
|
||||
const getPath = jasmine
|
||||
.createSpy('getPath')
|
||||
.and.returnValue(['expected', 'val']);
|
||||
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
getSpecName: specNameSpy,
|
||||
getPath,
|
||||
queueableFn: { fn: null }
|
||||
});
|
||||
|
||||
expect(spec.getFullName()).toBe('expected val');
|
||||
expect(specNameSpy.calls.mostRecent().args[0].id).toEqual(spec.id);
|
||||
expect(getPath.calls.mostRecent().args[0]).toBe(spec);
|
||||
});
|
||||
|
||||
describe('when a spec is marked pending during execution', function() {
|
||||
it('should mark the spec as pending', function() {
|
||||
const fakeQueueRunner = function(opts) {
|
||||
opts.onException(
|
||||
new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage)
|
||||
);
|
||||
},
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
description: 'my test',
|
||||
id: 'some-id',
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
it('can return its full path', function() {
|
||||
const getPath = jasmine
|
||||
.createSpy('getPath')
|
||||
.and.returnValue(['expected val']);
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
expect(spec.status()).toEqual('pending');
|
||||
expect(spec.result.pendingReason).toEqual('');
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
getPath,
|
||||
queueableFn: { fn: null }
|
||||
});
|
||||
|
||||
it('should set the pendingReason', function() {
|
||||
const fakeQueueRunner = function(opts) {
|
||||
opts.onException(
|
||||
new Error(
|
||||
jasmineUnderTest.Spec.pendingSpecExceptionMessage +
|
||||
'custom message'
|
||||
)
|
||||
);
|
||||
},
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
description: 'my test',
|
||||
id: 'some-id',
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
expect(spec.getPath()).toEqual(['expected val']);
|
||||
expect(getPath.calls.mostRecent().args[0]).toBe(spec);
|
||||
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
expect(spec.status()).toEqual('pending');
|
||||
expect(spec.result.pendingReason).toEqual('custom message');
|
||||
});
|
||||
expect(spec.metadata.getPath()).toEqual(['expected val']);
|
||||
});
|
||||
|
||||
it('should log a failure when handling an exception', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
resultCallback: resultCallback
|
||||
describe('#handleException', function() {
|
||||
it('records a failure', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {}
|
||||
});
|
||||
|
||||
spec.handleException('foo');
|
||||
spec.execute(fakeQueueRunner);
|
||||
spec.handleException('foo');
|
||||
|
||||
const args = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
args.queueableFns[args.queueableFns.length - 1].fn();
|
||||
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
|
||||
{
|
||||
message: 'foo thrown',
|
||||
matcherName: '',
|
||||
passed: false,
|
||||
expected: '',
|
||||
actual: '',
|
||||
stack: null
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not log an additional failure when handling an ExpectationFailed error', function() {
|
||||
const fakeQueueRunner = jasmine.createSpy('queueRunner'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
resultCallback: resultCallback
|
||||
});
|
||||
|
||||
spec.handleException(new jasmineUnderTest.errors.ExpectationFailed());
|
||||
spec.execute(fakeQueueRunner);
|
||||
|
||||
const args = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
args.queueableFns[args.queueableFns.length - 1].fn();
|
||||
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]);
|
||||
});
|
||||
|
||||
it('treats multiple done calls as late errors', function() {
|
||||
const queueRunnerFactory = jasmine.createSpy('queueRunnerFactory'),
|
||||
onLateError = jasmine.createSpy('onLateError'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
onLateError: onLateError,
|
||||
queueableFn: { fn: function() {} },
|
||||
getSpecName: function() {
|
||||
return 'a spec';
|
||||
expect(spec.result.failedExpectations).toEqual([
|
||||
{
|
||||
message: 'foo thrown',
|
||||
matcherName: '',
|
||||
passed: false,
|
||||
expected: '',
|
||||
actual: '',
|
||||
stack: null
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not record an additional failure when the error is ExpectationFailed', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {}
|
||||
});
|
||||
|
||||
spec.execute(queueRunnerFactory);
|
||||
spec.handleException(new jasmineUnderTest.errors.ExpectationFailed());
|
||||
|
||||
expect(queueRunnerFactory).toHaveBeenCalled();
|
||||
queueRunnerFactory.calls.argsFor(0)[0].onMultipleDone();
|
||||
|
||||
expect(onLateError).toHaveBeenCalledTimes(1);
|
||||
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
|
||||
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
|
||||
'An asynchronous spec, beforeEach, or afterEach function called its ' +
|
||||
"'done' callback more than once.\n(in spec: a spec)"
|
||||
);
|
||||
expect(spec.result.failedExpectations).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#trace', function() {
|
||||
describe('#debugLog', function() {
|
||||
it('adds the messages to the result', function() {
|
||||
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {
|
||||
fn: function() {}
|
||||
},
|
||||
timer: timer
|
||||
}),
|
||||
t1 = 123,
|
||||
t2 = 456;
|
||||
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']);
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} },
|
||||
timer: timer
|
||||
});
|
||||
const t1 = 123;
|
||||
const t2 = 456;
|
||||
|
||||
spec.execute(() => {});
|
||||
expect(spec.result.debugLogs).toBeNull();
|
||||
timer.elapsed.and.returnValue(t1);
|
||||
spec.debugLog('msg 1');
|
||||
@@ -628,84 +387,36 @@ describe('Spec', function() {
|
||||
});
|
||||
|
||||
describe('When the spec passes', function() {
|
||||
it('omits the messages from the reported result', function() {
|
||||
const resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {
|
||||
fn: function() {}
|
||||
},
|
||||
resultCallback: resultCallback
|
||||
});
|
||||
it('removes the logs from the result', function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} }
|
||||
});
|
||||
|
||||
function queueRunnerFactory(config) {
|
||||
spec.debugLog('msg');
|
||||
for (const fn of config.queueableFns) {
|
||||
fn.fn();
|
||||
}
|
||||
config.onComplete(false);
|
||||
}
|
||||
spec.debugLog('msg');
|
||||
spec.executionFinished();
|
||||
|
||||
spec.execute(queueRunnerFactory, function() {});
|
||||
expect(resultCallback).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({ debugLogs: null }),
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it('removes the messages to save memory', function() {
|
||||
const resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {
|
||||
fn: function() {}
|
||||
},
|
||||
resultCallback: resultCallback
|
||||
});
|
||||
|
||||
function queueRunnerFactory(config) {
|
||||
spec.debugLog('msg');
|
||||
for (const fn of config.queueableFns) {
|
||||
fn.fn();
|
||||
}
|
||||
config.onComplete(false);
|
||||
}
|
||||
|
||||
spec.execute(queueRunnerFactory, function() {});
|
||||
expect(resultCallback).toHaveBeenCalled();
|
||||
expect(spec.result.debugLogs).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the spec fails', function() {
|
||||
it('includes the messages in the reported result', function() {
|
||||
const resultCallback = jasmine.createSpy('resultCallback'),
|
||||
timer = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: {
|
||||
fn: function() {}
|
||||
},
|
||||
resultCallback: resultCallback,
|
||||
timer: timer
|
||||
}),
|
||||
timestamp = 12345;
|
||||
it('includes the messages in the result', function() {
|
||||
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']);
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: () => {} },
|
||||
timer: timer
|
||||
});
|
||||
const timestamp = 12345;
|
||||
|
||||
timer.elapsed.and.returnValue(timestamp);
|
||||
|
||||
function queueRunnerFactory(config) {
|
||||
spec.debugLog('msg');
|
||||
spec.handleException(new Error('nope'));
|
||||
for (const fn of config.queueableFns) {
|
||||
fn.fn();
|
||||
}
|
||||
config.onComplete(true);
|
||||
}
|
||||
spec.debugLog('msg');
|
||||
spec.handleException(new Error('nope'));
|
||||
spec.executionFinished();
|
||||
|
||||
spec.execute(queueRunnerFactory, function() {});
|
||||
expect(resultCallback).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
debugLogs: [{ message: 'msg', timestamp: timestamp }]
|
||||
}),
|
||||
undefined
|
||||
);
|
||||
expect(spec.result.debugLogs).toEqual([
|
||||
{ message: 'msg', timestamp: timestamp }
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -97,17 +97,11 @@ describe('Spies', function() {
|
||||
it('preserves arity of original function', function() {
|
||||
const functions = [
|
||||
function nullary() {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function unary(arg) {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function binary(arg1, arg2) {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function ternary(arg1, arg2, arg3) {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function quaternary(arg1, arg2, arg3, arg4) {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function quinary(arg1, arg2, arg3, arg4, arg5) {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function senary(arg1, arg2, arg3, arg4, arg5, arg6) {}
|
||||
];
|
||||
|
||||
@@ -159,7 +153,7 @@ describe('Spies', function() {
|
||||
it('should throw if you do not pass an array or object argument', function() {
|
||||
expect(function() {
|
||||
env.createSpyObj('BaseName');
|
||||
}).toThrow(
|
||||
}).toThrowError(
|
||||
'createSpyObj requires a non-empty array or object of method names to create spies for'
|
||||
);
|
||||
});
|
||||
@@ -167,7 +161,7 @@ describe('Spies', function() {
|
||||
it('should throw if you pass an empty array argument', function() {
|
||||
expect(function() {
|
||||
env.createSpyObj('BaseName', []);
|
||||
}).toThrow(
|
||||
}).toThrowError(
|
||||
'createSpyObj requires a non-empty array or object of method names to create spies for'
|
||||
);
|
||||
});
|
||||
@@ -175,7 +169,7 @@ describe('Spies', function() {
|
||||
it('should throw if you pass an empty object argument', function() {
|
||||
expect(function() {
|
||||
env.createSpyObj('BaseName', {});
|
||||
}).toThrow(
|
||||
}).toThrowError(
|
||||
'createSpyObj requires a non-empty array or object of method names to create spies for'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -51,6 +51,27 @@ describe('StackTrace', function() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('understands Chrome/Edge style traces with messages containing blank lines', function() {
|
||||
const error = {
|
||||
message: 'line 1\n\nline 2',
|
||||
stack:
|
||||
'Error: line 1\n\nline 2\n' +
|
||||
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
|
||||
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
|
||||
};
|
||||
|
||||
const result = new jasmineUnderTest.StackTrace(error);
|
||||
|
||||
expect(result.message).toEqual('Error: line 1\n\nline 2');
|
||||
const rawFrames = result.frames.map(function(f) {
|
||||
return f.raw;
|
||||
});
|
||||
expect(rawFrames).toEqual([
|
||||
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)',
|
||||
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
|
||||
]);
|
||||
});
|
||||
|
||||
it('understands Node style traces', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
@@ -95,7 +116,7 @@ describe('StackTrace', function() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('understands Safari <=14/Firefox/Phantom-OS X style traces', function() {
|
||||
it('understands Safari <=14/Firefox style traces', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
stack:
|
||||
@@ -149,7 +170,7 @@ describe('StackTrace', function() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces', function() {
|
||||
it('does not mistake gibberish for Safari/Firefox style traces', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
stack: 'randomcharsnotincludingwhitespace'
|
||||
@@ -159,36 +180,6 @@ describe('StackTrace', function() {
|
||||
expect(result.frames).toEqual([{ raw: error.stack }]);
|
||||
});
|
||||
|
||||
it('understands Phantom-Linux style traces', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
stack:
|
||||
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
|
||||
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
|
||||
};
|
||||
|
||||
const result = new jasmineUnderTest.StackTrace(error);
|
||||
|
||||
expect(result.message).toBeFalsy();
|
||||
expect(result.style).toEqual('v8');
|
||||
expect(result.frames).toEqual([
|
||||
{
|
||||
raw:
|
||||
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)',
|
||||
func: 'UserContext.<anonymous>',
|
||||
file: 'http://localhost:8888/__spec__/core/UtilSpec.js',
|
||||
line: 115
|
||||
},
|
||||
{
|
||||
raw:
|
||||
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)',
|
||||
func: 'QueueRunner.run',
|
||||
file: 'http://localhost:8888/__jasmine__/jasmine.js',
|
||||
line: 4320
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores blank lines', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
@@ -241,7 +232,7 @@ describe('StackTrace', function() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('consideres different types of errors', function() {
|
||||
it('considers different types of errors', function() {
|
||||
const error = {
|
||||
message: 'nope',
|
||||
stack:
|
||||
|
||||
@@ -163,6 +163,20 @@ describe('SuiteBuilder', function() {
|
||||
expect(spec2.id).toMatch(/^spec[0-9]+$/);
|
||||
expect(spec1.id).not.toEqual(spec2.id);
|
||||
});
|
||||
|
||||
it('gives each spec a full path', function() {
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
let spec;
|
||||
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.describe('a nested suite', function() {
|
||||
spec = suiteBuilder[fnName]('a spec', function() {});
|
||||
});
|
||||
});
|
||||
|
||||
expect(spec.getPath()).toEqual(['a suite', 'a nested suite', 'a spec']);
|
||||
});
|
||||
}
|
||||
|
||||
function sameInstanceAs(expected) {
|
||||
@@ -175,4 +189,202 @@ describe('SuiteBuilder', function() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('Duplicate name handling', function() {
|
||||
describe('When forbidDuplicateNames is true', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
env = { configuration: () => ({ forbidDuplicateNames: true }) };
|
||||
});
|
||||
|
||||
it('forbids duplicate spec names', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.describe('a nested suite', function() {
|
||||
suiteBuilder.it('a spec');
|
||||
suiteBuilder.it('a spec');
|
||||
});
|
||||
});
|
||||
}).toThrowError(
|
||||
'Duplicate spec name "a spec" found in "a suite a nested suite"'
|
||||
);
|
||||
});
|
||||
|
||||
it('forbids duplicate spec names in the top suite', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.it('another spec');
|
||||
suiteBuilder.it('another spec');
|
||||
}).toThrowError(
|
||||
'Duplicate spec name "another spec" found in top suite'
|
||||
);
|
||||
});
|
||||
|
||||
it('forbids duplicate suite names', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.describe('a nested suite', function() {
|
||||
suiteBuilder.describe('another suite', function() {
|
||||
suiteBuilder.it('a spec');
|
||||
});
|
||||
suiteBuilder.describe('another suite', function() {
|
||||
suiteBuilder.it('a spec');
|
||||
});
|
||||
});
|
||||
});
|
||||
}).toThrowError(
|
||||
'Duplicate suite name "another suite" found in "a suite a nested suite"'
|
||||
);
|
||||
});
|
||||
|
||||
it('forbids duplicate suite names in the top suite', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.it('a spec');
|
||||
});
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.it('a spec');
|
||||
});
|
||||
}).toThrowError('Duplicate suite name "a suite" found in top suite');
|
||||
});
|
||||
|
||||
it('allows spec and suite names to be duplicated in different suites', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.describe('suite a', function() {
|
||||
suiteBuilder.describe('dupe suite', function() {
|
||||
suiteBuilder.it('dupe spec');
|
||||
suiteBuilder.describe('child suite', function() {
|
||||
suiteBuilder.it('dupe spec');
|
||||
});
|
||||
});
|
||||
});
|
||||
suiteBuilder.describe('suite b', function() {
|
||||
suiteBuilder.describe('dupe suite', function() {
|
||||
suiteBuilder.it('dupe spec');
|
||||
});
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When forbidDuplicateNames is false', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
env = { configuration: () => ({ forbidDuplicateNames: false }) };
|
||||
});
|
||||
|
||||
it('allows duplicate spec and suite names', function() {
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
expect(function() {
|
||||
suiteBuilder.describe('dupe suite', function() {
|
||||
suiteBuilder.it('dupe spec');
|
||||
suiteBuilder.it('dupe spec');
|
||||
});
|
||||
suiteBuilder.describe('dupe suite', function() {
|
||||
suiteBuilder.it('dupe spec');
|
||||
suiteBuilder.it('dupe spec');
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#parallelReset', function() {
|
||||
it('resets the top suite result', function() {
|
||||
jasmineUnderTest.Suite.prototype.handleException.and.callThrough();
|
||||
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
suiteBuilder.topSuite.handleException(new Error('nope'));
|
||||
suiteBuilder.parallelReset();
|
||||
|
||||
expect(suiteBuilder.topSuite.result).toEqual({
|
||||
id: suiteBuilder.topSuite.id,
|
||||
description: 'Jasmine__TopLevel__Suite',
|
||||
fullName: '',
|
||||
failedExpectations: [],
|
||||
deprecationWarnings: [],
|
||||
duration: null,
|
||||
properties: null,
|
||||
parentSuiteId: null,
|
||||
filename: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('removes children of the top suite', function() {
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
suiteBuilder.describe('a suite', function() {
|
||||
suiteBuilder.it('a nested spec');
|
||||
});
|
||||
suiteBuilder.it('a spec');
|
||||
|
||||
suiteBuilder.parallelReset();
|
||||
|
||||
expect(suiteBuilder.topSuite.children).toEqual([]);
|
||||
});
|
||||
|
||||
it('preserves top suite befores and afters', function() {
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
|
||||
function beforeAll() {}
|
||||
function beforeEach() {}
|
||||
function afterEach() {}
|
||||
function afterAll() {}
|
||||
|
||||
suiteBuilder.beforeAll(beforeAll);
|
||||
suiteBuilder.beforeEach(beforeEach);
|
||||
suiteBuilder.afterEach(afterEach);
|
||||
suiteBuilder.afterAll(afterAll);
|
||||
|
||||
suiteBuilder.parallelReset();
|
||||
|
||||
expect(suiteBuilder.topSuite.beforeAllFns).toEqual([
|
||||
jasmine.objectContaining({ fn: beforeAll })
|
||||
]);
|
||||
expect(suiteBuilder.topSuite.beforeFns).toEqual([
|
||||
jasmine.objectContaining({ fn: beforeEach })
|
||||
]);
|
||||
expect(suiteBuilder.topSuite.afterFns).toEqual([
|
||||
jasmine.objectContaining({ fn: afterEach })
|
||||
]);
|
||||
expect(suiteBuilder.topSuite.afterAllFns).toEqual([
|
||||
jasmine.objectContaining({ fn: afterAll })
|
||||
]);
|
||||
});
|
||||
|
||||
it('resets totalSpecsDefined', function() {
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
suiteBuilder.it('a spec');
|
||||
|
||||
suiteBuilder.parallelReset();
|
||||
|
||||
expect(suiteBuilder.totalSpecsDefined).toEqual(0);
|
||||
});
|
||||
|
||||
it('resets focusedRunables', function() {
|
||||
const env = { configuration: () => ({}) };
|
||||
const suiteBuilder = new jasmineUnderTest.SuiteBuilder({ env });
|
||||
suiteBuilder.fit('a spec', function() {});
|
||||
|
||||
suiteBuilder.parallelReset();
|
||||
|
||||
expect(suiteBuilder.focusedRunables).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -378,4 +378,31 @@ describe('Suite', function() {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#hasChildWithDescription', function() {
|
||||
it('returns true if there is a child with the given description', function() {
|
||||
const subject = new jasmineUnderTest.Suite({});
|
||||
const description = 'a spec';
|
||||
subject.addChild({ description });
|
||||
|
||||
expect(subject.hasChildWithDescription(description)).toBeTrue();
|
||||
});
|
||||
|
||||
it('returns false if there is no child with the given description', function() {
|
||||
const subject = new jasmineUnderTest.Suite({});
|
||||
subject.addChild({ description: 'a different spec' });
|
||||
|
||||
expect(subject.hasChildWithDescription('a spec')).toBeFalse();
|
||||
});
|
||||
|
||||
it('does not recurse into child suites', function() {
|
||||
const subject = new jasmineUnderTest.Suite({});
|
||||
const childSuite = new jasmineUnderTest.Suite({});
|
||||
subject.addChild(childSuite);
|
||||
const description = 'a spec';
|
||||
childSuite.addChild(description);
|
||||
|
||||
expect(subject.hasChildWithDescription('a spec')).toBeFalse();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
542
spec/core/TreeRunnerSpec.js
Normal file
542
spec/core/TreeRunnerSpec.js
Normal file
@@ -0,0 +1,542 @@
|
||||
describe('TreeRunner', function() {
|
||||
describe('spec execution', function() {
|
||||
it('starts the timer, reports the spec started, and updates run state at the start of the queue', async function() {
|
||||
const timer = jasmine.createSpyObj('timer', ['start']);
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
id: 'spec1',
|
||||
queueableFn: {},
|
||||
timer
|
||||
});
|
||||
const {
|
||||
runQueue,
|
||||
currentRunableTracker,
|
||||
runableResources,
|
||||
reportDispatcher,
|
||||
suiteRunQueueArgs,
|
||||
executePromise
|
||||
} = runSingleSpecSuite(spec);
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
const next = jasmine.createSpy('next');
|
||||
specRunQueueArgs.queueableFns[0].fn(next);
|
||||
|
||||
expect(timer.start).toHaveBeenCalled();
|
||||
expect(currentRunableTracker.currentRunable()).toBe(spec);
|
||||
expect(runableResources.initForRunable).toHaveBeenCalledWith(
|
||||
spec.id,
|
||||
spec.parentSuiteId
|
||||
);
|
||||
expect(reportDispatcher.specStarted).toHaveBeenCalledWith(spec.result);
|
||||
await Promise.resolve();
|
||||
expect(reportDispatcher.specStarted).toHaveBeenCalledBefore(next);
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
|
||||
it('stops the timer, updates run state, and reports the spec done at the end of the queue', async function() {
|
||||
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']);
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
id: 'spec1',
|
||||
queueableFn: {},
|
||||
timer
|
||||
});
|
||||
const {
|
||||
runQueue,
|
||||
currentRunableTracker,
|
||||
runableResources,
|
||||
reportDispatcher,
|
||||
suiteRunQueueArgs,
|
||||
executePromise
|
||||
} = runSingleSpecSuite(spec);
|
||||
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
const next = jasmine.createSpy('next');
|
||||
timer.elapsed.and.returnValue('the elapsed time');
|
||||
currentRunableTracker.setCurrentSpec(spec);
|
||||
specRunQueueArgs.queueableFns[1].fn(next);
|
||||
|
||||
expect(currentRunableTracker.currentSpec()).toBeFalsy();
|
||||
expect(runableResources.clearForRunable).toHaveBeenCalledWith(spec.id);
|
||||
expect(reportDispatcher.specDone).toHaveBeenCalledWith(spec.result);
|
||||
expect(spec.result.duration).toEqual('the elapsed time');
|
||||
expect(spec.reportedDone).toEqual(true);
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
expect(reportDispatcher.specDone).toHaveBeenCalledBefore(next);
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
|
||||
it('runs before and after fns', function() {
|
||||
const before = { fn: jasmine.createSpy('before') };
|
||||
const after = { fn: jasmine.createSpy('after') };
|
||||
const queueableFn = {
|
||||
fn: jasmine.createSpy('test body').and.callFake(function() {
|
||||
expect(before).toHaveBeenCalled();
|
||||
expect(after).not.toHaveBeenCalled();
|
||||
})
|
||||
};
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: queueableFn,
|
||||
beforeAndAfterFns: function() {
|
||||
return { befores: [before], afters: [after] };
|
||||
}
|
||||
});
|
||||
|
||||
const { runQueue, suiteRunQueueArgs } = runSingleSpecSuite(spec);
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
|
||||
expect(specRunQueueArgs.queueableFns[1]).toEqual(before);
|
||||
expect(specRunQueueArgs.queueableFns[2]).toEqual(queueableFn);
|
||||
expect(specRunQueueArgs.queueableFns[3]).toEqual(after);
|
||||
});
|
||||
|
||||
it('marks specs pending at runtime', function() {
|
||||
let spec;
|
||||
const queueableFn = {
|
||||
fn() {
|
||||
spec.pend();
|
||||
}
|
||||
};
|
||||
spec = new jasmineUnderTest.Spec({ queueableFn });
|
||||
|
||||
const { runQueue, suiteRunQueueArgs } = runSingleSpecSuite(spec);
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
|
||||
expect(specRunQueueArgs.queueableFns[1]).toEqual(queueableFn);
|
||||
queueableFn.fn();
|
||||
|
||||
expect(spec.status()).toEqual('pending');
|
||||
expect(spec.getResult().status).toEqual('pending');
|
||||
expect(spec.getResult().pendingReason).toEqual('');
|
||||
});
|
||||
|
||||
it('marks specs pending at runtime with a message', function() {
|
||||
let spec;
|
||||
const queueableFn = {
|
||||
fn() {
|
||||
spec.pend('some reason');
|
||||
}
|
||||
};
|
||||
spec = new jasmineUnderTest.Spec({ queueableFn });
|
||||
|
||||
const { runQueue, suiteRunQueueArgs } = runSingleSpecSuite(spec);
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
|
||||
expect(specRunQueueArgs.queueableFns[1]).toEqual(queueableFn);
|
||||
queueableFn.fn();
|
||||
|
||||
expect(spec.status()).toEqual('pending');
|
||||
expect(spec.getResult().status).toEqual('pending');
|
||||
expect(spec.getResult().pendingReason).toEqual('some reason');
|
||||
});
|
||||
|
||||
it('passes failSpecWithNoExp to Spec#executionFinished', async function() {
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
id: 'spec1',
|
||||
queueableFn: {}
|
||||
});
|
||||
spyOn(spec, 'executionFinished');
|
||||
const {
|
||||
runQueue,
|
||||
suiteRunQueueArgs,
|
||||
executePromise
|
||||
} = runSingleSpecSuite(spec, { failSpecWithNoExpectations: true });
|
||||
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
expect(specRunQueueArgs.queueableFns[1].type).toEqual('specCleanup');
|
||||
specRunQueueArgs.queueableFns[1].fn();
|
||||
|
||||
expect(spec.executionFinished).toHaveBeenCalledWith(false, true);
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
|
||||
describe('Late promise rejection handling', function() {
|
||||
it('is enabled when the detectLateRejectionHandling param is true', function() {
|
||||
const before = jasmine.createSpy('before');
|
||||
const after = jasmine.createSpy('after');
|
||||
const queueableFn = {
|
||||
fn: jasmine.createSpy('test body').and.callFake(function() {
|
||||
expect(before).toHaveBeenCalled();
|
||||
expect(after).not.toHaveBeenCalled();
|
||||
})
|
||||
};
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
queueableFn,
|
||||
beforeAndAfterFns: function() {
|
||||
return { befores: [before], afters: [after] };
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
runQueue,
|
||||
setTimeout,
|
||||
suiteRunQueueArgs,
|
||||
globalErrors
|
||||
} = runSingleSpecSuite(spec, { detectLateRejectionHandling: true });
|
||||
|
||||
suiteRunQueueArgs.queueableFns[0].fn();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const specRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
|
||||
expect(specRunQueueOpts.queueableFns).toEqual([
|
||||
{ fn: jasmine.any(Function) },
|
||||
before,
|
||||
queueableFn,
|
||||
after,
|
||||
{ fn: jasmine.any(Function) },
|
||||
{
|
||||
fn: jasmine.any(Function),
|
||||
type: 'specCleanup'
|
||||
}
|
||||
]);
|
||||
|
||||
const done = jasmine.createSpy('done');
|
||||
specRunQueueOpts.queueableFns[4].fn(done);
|
||||
expect(globalErrors.reportUnhandledRejections).not.toHaveBeenCalled();
|
||||
expect(done).not.toHaveBeenCalled();
|
||||
|
||||
expect(setTimeout).toHaveBeenCalledOnceWith(jasmine.any(Function));
|
||||
setTimeout.calls.argsFor(0)[0]();
|
||||
expect(globalErrors.reportUnhandledRejections).toHaveBeenCalled();
|
||||
expect(globalErrors.reportUnhandledRejections).toHaveBeenCalledBefore(
|
||||
done
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function runSingleSpecSuite(spec, optionalConfig) {
|
||||
const topSuiteId = 'suite1';
|
||||
spec.parentSuiteId = topSuiteId;
|
||||
const topSuite = new jasmineUnderTest.Suite({ id: topSuiteId });
|
||||
topSuite.addChild(spec);
|
||||
const executionTree = {
|
||||
topSuite,
|
||||
childrenOfTopSuite() {
|
||||
return [{ spec }];
|
||||
},
|
||||
isExcluded() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const runQueue = jasmine.createSpy('runQueue');
|
||||
const reportDispatcher = mockReportDispatcher();
|
||||
const runableResources = mockRunableResources();
|
||||
const globalErrors = mockGlobalErrors();
|
||||
const setTimeout = jasmine.createSpy('setTimeout');
|
||||
const currentRunableTracker = new jasmineUnderTest.CurrentRunableTracker();
|
||||
const subject = new jasmineUnderTest.TreeRunner({
|
||||
executionTree,
|
||||
runQueue,
|
||||
globalErrors,
|
||||
setTimeout,
|
||||
runableResources,
|
||||
reportDispatcher,
|
||||
currentRunableTracker,
|
||||
getConfig() {
|
||||
return optionalConfig || {};
|
||||
},
|
||||
reportChildrenOfBeforeAllFailure() {}
|
||||
});
|
||||
|
||||
const executePromise = subject.execute();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const suiteRunQueueArgs = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
|
||||
return {
|
||||
runQueue,
|
||||
globalErrors,
|
||||
setTimeout,
|
||||
currentRunableTracker,
|
||||
runableResources,
|
||||
reportDispatcher,
|
||||
suiteRunQueueArgs,
|
||||
executePromise
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
describe('Suite execution', function() {
|
||||
it('reports the duration of the suite', async function() {
|
||||
const timer = jasmine.createSpyObj('timer', ['start', 'elapsed']);
|
||||
const topSuite = new jasmineUnderTest.Suite({ id: 'topSuite' });
|
||||
const suite = new jasmineUnderTest.Suite({
|
||||
id: 'suite1',
|
||||
parentSuite: topSuite,
|
||||
timer
|
||||
});
|
||||
topSuite.addChild(suite);
|
||||
const executionTree = {
|
||||
topSuite,
|
||||
childrenOfTopSuite() {
|
||||
return [{ suite }];
|
||||
},
|
||||
childrenOfSuiteSegment() {
|
||||
return [];
|
||||
},
|
||||
isExcluded() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const runQueue = jasmine.createSpy('runQueue');
|
||||
const reportDispatcher = mockReportDispatcher();
|
||||
const subject = new jasmineUnderTest.TreeRunner({
|
||||
executionTree,
|
||||
runQueue,
|
||||
globalErrors: mockGlobalErrors(),
|
||||
runableResources: mockRunableResources(),
|
||||
reportDispatcher,
|
||||
currentRunableTracker: new jasmineUnderTest.CurrentRunableTracker(),
|
||||
getConfig() {
|
||||
return {};
|
||||
},
|
||||
reportChildrenOfBeforeAllFailure() {}
|
||||
});
|
||||
|
||||
const executePromise = subject.execute();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const topSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
topSuiteRunQueueOpts.queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
expect(timer.start).not.toHaveBeenCalled();
|
||||
const suiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
suiteRunQueueOpts.queueableFns[0].fn();
|
||||
expect(timer.start).toHaveBeenCalled();
|
||||
expect(timer.elapsed).not.toHaveBeenCalled();
|
||||
|
||||
timer.elapsed.and.returnValue('the duration');
|
||||
suiteRunQueueOpts.onComplete();
|
||||
expect(timer.elapsed).toHaveBeenCalled();
|
||||
const result = suite.getResult();
|
||||
expect(result.duration).toEqual('the duration');
|
||||
expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(result);
|
||||
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
|
||||
it('returns false if a suite failed', async function() {
|
||||
const topSuite = new jasmineUnderTest.Suite({ id: 'topSuite' });
|
||||
const failingSuite = new jasmineUnderTest.Suite({
|
||||
id: 'failingSuite',
|
||||
parentSuite: topSuite
|
||||
});
|
||||
const passingSuite = new jasmineUnderTest.Suite({
|
||||
id: 'passingSuite',
|
||||
parentSuite: topSuite
|
||||
});
|
||||
const executionTree = {
|
||||
topSuite,
|
||||
childrenOfTopSuite() {
|
||||
return [{ suite: failingSuite }, { suite: passingSuite }];
|
||||
},
|
||||
childrenOfSuiteSegment() {
|
||||
return [];
|
||||
},
|
||||
isExcluded() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const runQueue = jasmine.createSpy('runQueue');
|
||||
const reportDispatcher = mockReportDispatcher();
|
||||
const subject = new jasmineUnderTest.TreeRunner({
|
||||
executionTree,
|
||||
runQueue,
|
||||
globalErrors: mockGlobalErrors(),
|
||||
runableResources: mockRunableResources(),
|
||||
reportDispatcher,
|
||||
currentRunableTracker: new jasmineUnderTest.CurrentRunableTracker(),
|
||||
getConfig() {
|
||||
return {};
|
||||
},
|
||||
reportChildrenOfBeforeAllFailure() {}
|
||||
});
|
||||
|
||||
const executePromise = subject.execute();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const topSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
topSuiteRunQueueOpts.queueableFns[0].fn(function() {});
|
||||
|
||||
// Fail the first suite.
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const failingSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
failingSuiteRunQueueOpts.queueableFns[0].fn();
|
||||
failingSuite.addExpectationResult(false, {});
|
||||
failingSuiteRunQueueOpts.onComplete();
|
||||
|
||||
// Passing the second suite should not reset the overall result.
|
||||
topSuiteRunQueueOpts.queueableFns[1].fn(function() {});
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const passingSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
passingSuiteRunQueueOpts.queueableFns[0].fn();
|
||||
passingSuiteRunQueueOpts.onComplete();
|
||||
|
||||
topSuiteRunQueueOpts.onComplete();
|
||||
|
||||
const result = await executePromise;
|
||||
expect(result.hasFailures).toEqual(true);
|
||||
});
|
||||
|
||||
it('reports children when there is a beforeAll failure', async function() {
|
||||
const topSuite = new jasmineUnderTest.Suite({ id: 'topSuite' });
|
||||
const suite = new jasmineUnderTest.Suite({
|
||||
id: 'suite',
|
||||
parentSuite: topSuite
|
||||
});
|
||||
suite.beforeAll({ fn() {} });
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
id: 'spec',
|
||||
parentSuite: suite,
|
||||
queueableFn: { fn() {} }
|
||||
});
|
||||
suite.addChild(spec);
|
||||
topSuite.addChild(suite);
|
||||
const executionTree = {
|
||||
topSuite,
|
||||
childrenOfTopSuite() {
|
||||
return [{ suite }];
|
||||
},
|
||||
childrenOfSuiteSegment() {
|
||||
return [{ spec }];
|
||||
},
|
||||
isExcluded() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const runQueue = jasmine.createSpy('runQueue');
|
||||
const reportDispatcher = mockReportDispatcher();
|
||||
const reportChildrenOfBeforeAllFailure = jasmine
|
||||
.createSpy('reportChildrenOfBeforeAllFailure')
|
||||
.and.returnValue(Promise.resolve());
|
||||
const subject = new jasmineUnderTest.TreeRunner({
|
||||
executionTree,
|
||||
runQueue,
|
||||
globalErrors: mockGlobalErrors(),
|
||||
runableResources: mockRunableResources(),
|
||||
reportDispatcher,
|
||||
currentRunableTracker: new jasmineUnderTest.CurrentRunableTracker(),
|
||||
reportChildrenOfBeforeAllFailure,
|
||||
getConfig() {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
const executePromise = subject.execute();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const topSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
topSuiteRunQueueOpts.queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const suiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
suiteRunQueueOpts.queueableFns[0].fn();
|
||||
suite.hadBeforeAllFailure = true;
|
||||
suiteRunQueueOpts.onComplete();
|
||||
|
||||
while (reportDispatcher.suiteDone.calls.count() === 0) {
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
expect(reportDispatcher.specDone).toHaveBeenCalledBefore(
|
||||
reportDispatcher.suiteDone
|
||||
);
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
|
||||
it('throws if the wrong suite is completed', async function() {
|
||||
const topSuite = new jasmineUnderTest.Suite({ id: 'topSuite' });
|
||||
const suite = new jasmineUnderTest.Suite({
|
||||
id: 'suite',
|
||||
parentSuite: topSuite
|
||||
});
|
||||
const spec = new jasmineUnderTest.Spec({
|
||||
id: 'spec',
|
||||
parentSuite: suite,
|
||||
queueableFn: { fn() {} }
|
||||
});
|
||||
const executionTree = {
|
||||
topSuite,
|
||||
childrenOfTopSuite() {
|
||||
return [{ suite }];
|
||||
},
|
||||
childrenOfSuiteSegment() {
|
||||
return [{ spec }];
|
||||
},
|
||||
isExcluded() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const runQueue = jasmine.createSpy('runQueue');
|
||||
const reportDispatcher = mockReportDispatcher();
|
||||
const subject = new jasmineUnderTest.TreeRunner({
|
||||
executionTree,
|
||||
runQueue,
|
||||
globalErrors: mockGlobalErrors(),
|
||||
runableResources: mockRunableResources(),
|
||||
reportDispatcher,
|
||||
currentRunableTracker: new jasmineUnderTest.CurrentRunableTracker(),
|
||||
getConfig() {
|
||||
return {};
|
||||
},
|
||||
reportChildrenOfBeforeAllFailure() {}
|
||||
});
|
||||
|
||||
const executePromise = subject.execute();
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const topSuiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
runQueue.calls.reset();
|
||||
topSuiteRunQueueOpts.queueableFns[0].fn(function() {});
|
||||
|
||||
expect(runQueue).toHaveBeenCalledTimes(1);
|
||||
const suiteRunQueueOpts = runQueue.calls.mostRecent().args[0];
|
||||
|
||||
// Complete the suite without starting it
|
||||
expect(function() {
|
||||
suiteRunQueueOpts.onComplete();
|
||||
}).toThrowError('Tried to complete the wrong suite');
|
||||
|
||||
await expectAsync(executePromise).toBePending();
|
||||
});
|
||||
});
|
||||
|
||||
function mockReportDispatcher() {
|
||||
const reportDispatcher = jasmine.createSpyObj(
|
||||
'reportDispatcher',
|
||||
jasmineUnderTest.reporterEvents
|
||||
);
|
||||
|
||||
for (const k of jasmineUnderTest.reporterEvents) {
|
||||
reportDispatcher[k].and.returnValue(Promise.resolve());
|
||||
}
|
||||
|
||||
return reportDispatcher;
|
||||
}
|
||||
|
||||
function mockRunableResources() {
|
||||
return jasmine.createSpyObj('runableResources', [
|
||||
'initForRunable',
|
||||
'clearForRunable'
|
||||
]);
|
||||
}
|
||||
|
||||
function mockGlobalErrors() {
|
||||
return jasmine.createSpyObj('globalErrors', ['reportUnhandledRejections']);
|
||||
}
|
||||
});
|
||||
@@ -128,17 +128,6 @@ describe('util', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUndefined', function() {
|
||||
it('reports if a variable is defined', function() {
|
||||
let a;
|
||||
expect(jasmineUnderTest.util.isUndefined(a)).toBe(true);
|
||||
expect(jasmineUnderTest.util.isUndefined(undefined)).toBe(true);
|
||||
|
||||
const defined = 'diz be undefined yo';
|
||||
expect(jasmineUnderTest.util.isUndefined(defined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cloneArgs', function() {
|
||||
it('clones primitives as-is', function() {
|
||||
expect(jasmineUnderTest.util.cloneArgs([true, false])).toEqual([
|
||||
|
||||
@@ -2,8 +2,7 @@ describe('base helpers', function() {
|
||||
describe('isError_', function() {
|
||||
it('correctly handles WebSocket events', function(done) {
|
||||
if (typeof jasmine.getGlobal().WebSocket === 'undefined') {
|
||||
done();
|
||||
return;
|
||||
pending('Environment does not provide WebSocket');
|
||||
}
|
||||
|
||||
const obj = (function() {
|
||||
@@ -145,7 +144,7 @@ describe('base helpers', function() {
|
||||
});
|
||||
|
||||
it('returns a promise that resolves to false when the promise is rejected', function() {
|
||||
const promise = Promise.reject();
|
||||
const promise = Promise.reject(new Error('nope'));
|
||||
return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo(
|
||||
false
|
||||
);
|
||||
@@ -179,7 +178,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() {
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('buildExpectationResult', function() {
|
||||
|
||||
it('handles nodejs assertions', function() {
|
||||
if (typeof require === 'undefined') {
|
||||
return;
|
||||
pending('This test only runs in Node');
|
||||
}
|
||||
const assert = require('assert');
|
||||
const value = 8421;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1287
spec/core/integration/GlobalErrorHandlingSpec.js
Normal file
1287
spec/core/integration/GlobalErrorHandlingSpec.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -349,7 +349,7 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
|
||||
verifyFailsAsync(function(env) {
|
||||
return env.expectAsync(Promise.reject()).toBeResolved();
|
||||
return env.expectAsync(Promise.reject(new Error('nope'))).toBeResolved();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -469,6 +469,24 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('toBeNullish', function() {
|
||||
verifyPasses(function(env) {
|
||||
env.expect(undefined).toBeNullish();
|
||||
});
|
||||
|
||||
verifyPasses(function(env) {
|
||||
env.expect(null).toBeNullish();
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
env.expect(1).toBeNullish();
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
env.expect('').toBeNullish();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toContain', function() {
|
||||
verifyPasses(function(env) {
|
||||
env.addCustomEqualityTester(function(a, b) {
|
||||
@@ -610,23 +628,31 @@ 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');
|
||||
});
|
||||
});
|
||||
|
||||
describe('toHaveClasses', function() {
|
||||
verifyPasses(function(env) {
|
||||
const el = specHelpers.domHelpers.createElementWithClassName(
|
||||
'foo bar baz'
|
||||
);
|
||||
env.expect(el).toHaveClasses(['bar', 'baz']);
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
const el = specHelpers.domHelpers.createElementWithClassName('foo bar');
|
||||
env.expect(el).toHaveClasses(['bar', 'baz']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toHaveSpyInteractions', function() {
|
||||
let spyObj;
|
||||
beforeEach(function() {
|
||||
@@ -649,6 +675,23 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('toHaveNoOtherSpyInteractions', function() {
|
||||
let spyObj;
|
||||
|
||||
beforeEach(function() {
|
||||
spyObj = env.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
});
|
||||
|
||||
verifyPasses(function(env) {
|
||||
env.expect(spyObj).toHaveNoOtherSpyInteractions();
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
spyObj.spyA();
|
||||
env.expect(spyObj).toHaveNoOtherSpyInteractions();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toMatch', function() {
|
||||
verifyPasses(function(env) {
|
||||
env.expect('foo').toMatch(/oo$/);
|
||||
|
||||
162
spec/core/integration/ParallelSpec.js
Normal file
162
spec/core/integration/ParallelSpec.js
Normal file
@@ -0,0 +1,162 @@
|
||||
describe('Support for parallel execution', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
env = new jasmineUnderTest.Env();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.cleanup_();
|
||||
});
|
||||
|
||||
it('removes specs and suites from previous batches', async function() {
|
||||
env.describe('a suite', function() {
|
||||
env.it('a spec', function() {});
|
||||
});
|
||||
env.it('a spec', function() {});
|
||||
|
||||
await env.execute();
|
||||
env.parallelReset();
|
||||
|
||||
env.describe('a suite in a new batch', function() {
|
||||
env.it('a spec in a new batch', function() {});
|
||||
});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'suiteDone',
|
||||
'specDone'
|
||||
]);
|
||||
env.addReporter(reporter);
|
||||
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
||||
jasmine.objectContaining({
|
||||
fullName: 'a suite in a new batch'
|
||||
})
|
||||
);
|
||||
expect(reporter.specDone).toHaveBeenCalledOnceWith(
|
||||
jasmine.objectContaining({
|
||||
fullName: 'a suite in a new batch a spec in a new batch'
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves top-level before and after fns from previous batches', async function() {
|
||||
const beforeAll = jasmine.createSpy('beforeAll');
|
||||
const beforeEach = jasmine.createSpy('beforeEach');
|
||||
const afterEach = jasmine.createSpy('afterEach');
|
||||
const afterAll = jasmine.createSpy('afterAll');
|
||||
env.beforeAll(beforeAll);
|
||||
env.beforeEach(beforeEach);
|
||||
env.afterEach(afterEach);
|
||||
env.afterAll(afterAll);
|
||||
|
||||
env.parallelReset();
|
||||
env.it('a spec', function() {});
|
||||
await env.execute();
|
||||
|
||||
expect(beforeAll).toHaveBeenCalled();
|
||||
expect(beforeEach).toHaveBeenCalled();
|
||||
expect(afterEach).toHaveBeenCalled();
|
||||
expect(afterAll).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not remember focused runables from previous batches', async function() {
|
||||
env.fit('a focused spec', function() {});
|
||||
env.parallelReset();
|
||||
env.it('a spec', function() {});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'specDone',
|
||||
'jasmineDone'
|
||||
]);
|
||||
env.addReporter(reporter);
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledOnceWith(
|
||||
jasmine.objectContaining({
|
||||
fullName: 'a spec',
|
||||
status: 'passed'
|
||||
})
|
||||
);
|
||||
expect(reporter.jasmineDone).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({ overallStatus: 'passed' })
|
||||
);
|
||||
});
|
||||
|
||||
it('does not remember failures from previous batches', async function() {
|
||||
env.it('a failing spec', function() {
|
||||
env.expect(true).toBe(false);
|
||||
});
|
||||
await env.execute();
|
||||
env.parallelReset();
|
||||
env.it('a spec', function() {});
|
||||
const reporter = jasmine.createSpyObj('reporter', [
|
||||
'specDone',
|
||||
'jasmineDone'
|
||||
]);
|
||||
env.addReporter(reporter);
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.jasmineDone).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({ overallStatus: 'passed' })
|
||||
);
|
||||
});
|
||||
|
||||
it('reports errors thrown from describe', async function() {
|
||||
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.describe('borken', function() {
|
||||
throw new Error('nope');
|
||||
});
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
description: 'borken',
|
||||
status: 'failed',
|
||||
failedExpectations: [
|
||||
jasmine.objectContaining({
|
||||
message: jasmine.stringContaining('Error: nope')
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
// Errors in subsequent suites should also be reported
|
||||
reporter.suiteDone.calls.reset();
|
||||
env.parallelReset();
|
||||
env.describe('zarro boogs', function() {
|
||||
throw new Error('nor that either');
|
||||
});
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
||||
jasmine.objectContaining({
|
||||
description: 'zarro boogs',
|
||||
status: 'failed',
|
||||
failedExpectations: [
|
||||
jasmine.objectContaining({
|
||||
message: jasmine.stringContaining('Error: nor that either')
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
// Failure state should not persist across resets
|
||||
reporter.suiteDone.calls.reset();
|
||||
env.parallelReset();
|
||||
env.describe('actually works', function() {
|
||||
env.it('a spec', function() {});
|
||||
});
|
||||
await env.execute();
|
||||
|
||||
expect(reporter.suiteDone).toHaveBeenCalledOnceWith(
|
||||
jasmine.objectContaining({
|
||||
description: 'actually works',
|
||||
status: 'passed',
|
||||
failedExpectations: []
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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 });
|
||||
});
|
||||
@@ -621,12 +621,17 @@ describe('spec running', function() {
|
||||
actions.push('spec3');
|
||||
});
|
||||
|
||||
spyOn(jasmineUnderTest.getEnv(), 'deprecated');
|
||||
|
||||
await env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
|
||||
expect(actions).toEqual(['spec2', 'spec3', 'spec1']);
|
||||
expect(jasmineUnderTest.getEnv().deprecated).toHaveBeenCalledWith(
|
||||
'The specified spec/suite order splits up a suite, running unrelated specs in the middle of it. This will become an error in a future release.'
|
||||
);
|
||||
});
|
||||
|
||||
it('refuses to re-enter suites with a beforeAll', function() {
|
||||
it('refuses to re-enter suites with a beforeAll', async function() {
|
||||
const actions = [];
|
||||
let spec1;
|
||||
let spec2;
|
||||
@@ -648,13 +653,12 @@ describe('spec running', function() {
|
||||
actions.push('spec3');
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
}).toThrowError(/beforeAll/);
|
||||
const promise = env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
await expectAsync(promise).toBeRejectedWithError(/beforeAll/);
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
|
||||
it('refuses to re-enter suites with a afterAll', function() {
|
||||
it('refuses to re-enter suites with a afterAll', async function() {
|
||||
const actions = [];
|
||||
let spec1;
|
||||
let spec2;
|
||||
@@ -676,9 +680,8 @@ describe('spec running', function() {
|
||||
actions.push('spec3');
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
}).toThrowError(/afterAll/);
|
||||
const promise = env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
await expectAsync(promise).toBeRejectedWithError(/afterAll/);
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -868,7 +871,6 @@ describe('spec running', function() {
|
||||
const actions = [];
|
||||
|
||||
env.describe('Something', function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
env.beforeEach(function(innerDone) {
|
||||
actions.push('beforeEach');
|
||||
}, 1);
|
||||
|
||||
@@ -161,6 +161,63 @@ describe('DiffBuilder', function() {
|
||||
expect(diffBuilder.getMessage()).toEqual(expectedMsg);
|
||||
});
|
||||
|
||||
it('handles cases where only the expected has a custom object formatter', function() {
|
||||
const formatter = function(x) {
|
||||
if (typeof x === 'number') {
|
||||
return '[number:' + x + ']';
|
||||
}
|
||||
};
|
||||
const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder({
|
||||
prettyPrinter: prettyPrinter
|
||||
});
|
||||
|
||||
diffBuilder.setRoots('five', 4);
|
||||
diffBuilder.recordMismatch();
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual(
|
||||
"Expected 'five' to equal [number:4]."
|
||||
);
|
||||
});
|
||||
|
||||
it('handles cases where only the actual has a custom object formatter', function() {
|
||||
const formatter = function(x) {
|
||||
if (typeof x === 'number') {
|
||||
return '[number:' + x + ']';
|
||||
}
|
||||
};
|
||||
const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder({
|
||||
prettyPrinter: prettyPrinter
|
||||
});
|
||||
|
||||
diffBuilder.setRoots(5, 'four');
|
||||
diffBuilder.recordMismatch();
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual(
|
||||
"Expected [number:5] to equal 'four'."
|
||||
);
|
||||
});
|
||||
|
||||
it('handles complex cases where only one side has a custom object formatter', function() {
|
||||
const formatter = function(x) {
|
||||
if (typeof x === 'number') {
|
||||
return '[number:' + x + ']';
|
||||
}
|
||||
};
|
||||
const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder({
|
||||
prettyPrinter: prettyPrinter
|
||||
});
|
||||
|
||||
diffBuilder.setRoots(5, { foo: 'bar', fnord: { graults: ['wombat'] } });
|
||||
diffBuilder.recordMismatch();
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual(
|
||||
"Expected [number:5] to equal Object({ foo: 'bar', fnord: Object({ graults: [ 'wombat' ] }) })."
|
||||
);
|
||||
});
|
||||
|
||||
it('builds diffs involving asymmetric equality testers that implement valuesForDiff_ at the root', function() {
|
||||
const prettyPrinter = jasmineUnderTest.makePrettyPrinter([]),
|
||||
diffBuilder = new jasmineUnderTest.DiffBuilder({
|
||||
|
||||
@@ -38,6 +38,8 @@ describe('toBePending', function() {
|
||||
return matcher.compare(actual);
|
||||
}
|
||||
|
||||
expect(f).toThrowError('Expected toBePending to be called on a promise.');
|
||||
expect(f).toThrowError(
|
||||
'Expected toBePending to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,6 +28,8 @@ describe('toBeRejected', function() {
|
||||
return matcher.compare(actual);
|
||||
}
|
||||
|
||||
expect(f).toThrowError('Expected toBeRejected to be called on a promise.');
|
||||
expect(f).toThrowError(
|
||||
'Expected toBeRejected to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -232,7 +232,7 @@ describe('#toBeRejectedWithError', function() {
|
||||
}
|
||||
|
||||
expect(f).toThrowError(
|
||||
'Expected toBeRejectedWithError to be called on a promise.'
|
||||
'Expected toBeRejectedWithError to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,7 +83,7 @@ describe('#toBeRejectedWith', function() {
|
||||
}
|
||||
|
||||
expect(f).toThrowError(
|
||||
'Expected toBeRejectedWith to be called on a promise.'
|
||||
'Expected toBeRejectedWith to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,6 +35,8 @@ describe('toBeResolved', function() {
|
||||
return matcher.compare(actual);
|
||||
}
|
||||
|
||||
expect(f).toThrowError('Expected toBeResolved to be called on a promise.');
|
||||
expect(f).toThrowError(
|
||||
'Expected toBeResolved to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('#toBeResolvedTo', function() {
|
||||
}
|
||||
|
||||
expect(f).toThrowError(
|
||||
'Expected toBeResolvedTo to be called on a promise.'
|
||||
'Expected toBeResolvedTo to be called on a promise but was on a string.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -250,10 +250,6 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
it('passes for equivalent Promises (GitHub issue #1314)', function() {
|
||||
if (typeof Promise === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
const p1 = new Promise(function() {}),
|
||||
p2 = new Promise(function() {}),
|
||||
matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
@@ -263,14 +259,13 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
describe('when running in a browser', function() {
|
||||
function isNotRunningInBrowser() {
|
||||
return typeof document === 'undefined';
|
||||
}
|
||||
beforeEach(function() {
|
||||
if (typeof document === 'undefined') {
|
||||
pending('This test only runs in browsers');
|
||||
}
|
||||
});
|
||||
|
||||
it('passes for equivalent DOM nodes', function() {
|
||||
if (isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
const a = document.createElement('div');
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
|
||||
@@ -285,9 +280,6 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
it('passes for equivalent objects from different frames', function() {
|
||||
if (isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
@@ -299,9 +291,6 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
it('fails for DOM nodes with different attributes or child nodes', function() {
|
||||
if (isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const a = document.createElement('div');
|
||||
a.setAttribute('test-attr', 'attr-value');
|
||||
@@ -325,14 +314,13 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
describe('when running in Node', function() {
|
||||
function isNotRunningInNode() {
|
||||
return typeof require !== 'function';
|
||||
}
|
||||
beforeEach(function() {
|
||||
if (typeof require !== 'function') {
|
||||
pending('This test only runs in Node');
|
||||
}
|
||||
});
|
||||
|
||||
it('passes for equivalent objects from different vm contexts', function() {
|
||||
if (isNotRunningInNode()) {
|
||||
return;
|
||||
}
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const vm = require('vm');
|
||||
const sandbox = {
|
||||
@@ -344,9 +332,6 @@ describe('matchersUtil', function() {
|
||||
});
|
||||
|
||||
it('passes for equivalent arrays from different vm contexts', function() {
|
||||
if (isNotRunningInNode()) {
|
||||
return;
|
||||
}
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const vm = require('vm');
|
||||
const sandbox = {
|
||||
@@ -757,7 +742,9 @@ describe('matchersUtil', function() {
|
||||
const a2 = new TypedArrayCtor(2);
|
||||
a1[0] = a2[0] = 0;
|
||||
a1[1] = a2[1] = 1;
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(true);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder();
|
||||
expect(matchersUtil.equals(a1, a2, diffBuilder)).toBe(true);
|
||||
jasmine.debugLog('Diff: ' + diffBuilder.getMessage());
|
||||
}
|
||||
);
|
||||
|
||||
@@ -766,7 +753,9 @@ describe('matchersUtil', function() {
|
||||
const a1 = new TypedArrayCtor(2);
|
||||
const a2 = new TypedArrayCtor(1);
|
||||
a1[0] = a1[1] = a2[0] = 0;
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(false);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder();
|
||||
expect(matchersUtil.equals(a1, a2, diffBuilder)).toBe(false);
|
||||
jasmine.debugLog('Diff: ' + diffBuilder.getMessage());
|
||||
});
|
||||
|
||||
it(
|
||||
@@ -777,7 +766,9 @@ describe('matchersUtil', function() {
|
||||
const a2 = new TypedArrayCtor(1);
|
||||
a1[0] = 0;
|
||||
a2[0] = 1;
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(false);
|
||||
const diffBuilder = new jasmineUnderTest.DiffBuilder();
|
||||
expect(matchersUtil.equals(a1, a2, diffBuilder)).toBe(false);
|
||||
jasmine.debugLog('Diff: ' + diffBuilder.getMessage());
|
||||
}
|
||||
);
|
||||
|
||||
@@ -824,9 +815,7 @@ describe('matchersUtil', function() {
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const a1 = new TypedArrayCtor(2);
|
||||
const a2 = new TypedArrayCtor(2);
|
||||
// eslint-disable-next-line compat/compat
|
||||
a1[0] = a2[0] = BigInt(0);
|
||||
// eslint-disable-next-line compat/compat
|
||||
a1[1] = a2[1] = BigInt(1);
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(true);
|
||||
}
|
||||
@@ -837,7 +826,6 @@ describe('matchersUtil', function() {
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const a1 = new TypedArrayCtor(2);
|
||||
const a2 = new TypedArrayCtor(1);
|
||||
// eslint-disable-next-line compat/compat
|
||||
a1[0] = a1[1] = a2[0] = BigInt(0);
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(false);
|
||||
});
|
||||
@@ -849,9 +837,7 @@ describe('matchersUtil', function() {
|
||||
const matchersUtil = new jasmineUnderTest.MatchersUtil();
|
||||
const a1 = new TypedArrayCtor(2);
|
||||
const a2 = new TypedArrayCtor(2);
|
||||
// eslint-disable-next-line compat/compat
|
||||
a1[0] = a1[1] = a2[0] = BigInt(0);
|
||||
// eslint-disable-next-line compat/compat
|
||||
a2[1] = BigInt(1);
|
||||
expect(matchersUtil.equals(a1, a2)).toBe(false);
|
||||
}
|
||||
|
||||
57
spec/core/matchers/toBeNullishSpec.js
Normal file
57
spec/core/matchers/toBeNullishSpec.js
Normal file
@@ -0,0 +1,57 @@
|
||||
describe('toBeNullish', function() {
|
||||
it('passes for null values', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(null);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it('passes for undefined values', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(void 0);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it('fails when matching defined values', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare('foo');
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
describe('falsy values', () => {
|
||||
it('fails for 0', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(0);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('fails for -0', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(-0);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('fails for empty string', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare('');
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('fails for false', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(false);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('fails for NaN', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(NaN);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it('fails for 0n', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toBeNullish();
|
||||
const result = matcher.compare(BigInt(0));
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user