├── .circleci
└── config.yml
├── .editorconfig
├── .github
└── CONTRIBUTING.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── RELEASE.md
├── bin
├── jasmine.js
└── worker.js
├── eslint.config.mjs
├── lib
├── command.js
├── examples
│ └── jasmine.mjs
├── exit_handler.js
├── filters
│ ├── path_spec_filter.js
│ └── regex_spec_filter.js
├── global_setup_or_teardown_runner.js
├── jasmine.js
├── loader.js
├── parallel_runner.js
├── parallel_worker.js
├── randomize.js
├── reporters
│ └── console_reporter.js
├── runner_base.js
└── unWindows.js
├── package.json
├── release_notes
├── 2.1.0.md
├── 2.1.1.md
├── 2.2.0.md
├── 2.2.1.md
├── 2.3.0.md
├── 2.3.1.md
├── 2.3.2.md
├── 2.4.0.md
├── 2.4.1.md
├── 2.5.0.md
├── 2.5.1.md
├── 2.5.2.md
├── 2.5.3.md
├── 2.6.0.md
├── 2.7.0.md
├── 2.8.0.md
├── 2.9.0.md
├── 2.99.md
├── 3.0.md
├── 3.1.0.md
├── 3.10.0.md
├── 3.2.0.md
├── 3.3.0.md
├── 3.3.1.md
├── 3.4.0.md
├── 3.5.0.md
├── 3.6.0.md
├── 3.6.1.md
├── 3.6.2.md
├── 3.6.3.md
├── 3.6.4.md
├── 3.7.0.md
├── 3.8.0.md
├── 3.9.0.md
├── 3.99.0.md
├── 4.0.0.md
├── 4.0.1.md
├── 4.0.2.md
├── 4.1.0.md
├── 4.2.0.md
├── 4.2.1.md
├── 4.3.0.md
├── 4.4.0.md
├── 4.5.0.md
├── 4.6.0.md
├── 5.0.0-alpha.0.md
├── 5.0.0-alpha.1.md
├── 5.0.0-beta.0.md
├── 5.0.0.md
├── 5.0.1.md
├── 5.0.2.md
├── 5.1.0.md
├── 5.2.0.md
├── 5.3.0.md
├── 5.3.1.md
├── 5.4.0.md
├── 5.5.0.md
├── 5.6.0.md
├── 5.7.0.md
└── 5.7.1.md
└── spec
├── command_spec.js
├── filters
└── regex_spec_filter_spec.js
├── fixtures
├── badReporter.js
├── cjs-load-exception
│ ├── jasmine.json
│ └── throws_on_load.js
├── cjs-syntax-error
│ ├── jasmine.json
│ └── syntax_error.js
├── customReporter.js
├── customReporter.mjs
├── defaultProgrammaticFail.js
├── dontExitOnCompletion.js
├── env-config
│ ├── aSpec.js
│ └── jasmine.json
├── esm-importing-commonjs-syntax-error
│ ├── intermediate.js
│ ├── jasmine.json
│ ├── spec.mjs
│ └── syntax_error.js
├── esm-indirect-error
│ ├── jasmine.json
│ ├── spec.mjs
│ └── throws.mjs
├── esm-load-exception
│ ├── jasmine.json
│ └── throws_on_load.mjs
├── esm-reporter-packagejson
│ ├── customReporter.js
│ ├── jasmine.json
│ └── package.json
├── esm-syntax-error
│ ├── jasmine.json
│ └── syntax_error.mjs
├── esm
│ ├── commonjs_helper.js
│ ├── commonjs_sentinel.js
│ ├── commonjs_spec.js
│ ├── esm_helper.mjs
│ ├── esm_sentinel.mjs
│ ├── esm_spec.mjs
│ ├── jasmine.mjs
│ └── name_reporter.js
├── example
│ ├── lib
│ │ └── jasmine_examples
│ │ │ ├── Bar.js
│ │ │ └── Foo.js
│ └── spec
│ │ ├── helpers
│ │ └── jasmine_examples
│ │ │ └── SpecHelper.js
│ │ └── jasmine_examples
│ │ └── FooSpec.js
├── global_setup_failure
│ ├── jasmine.js
│ └── spec.js
├── global_setup_success
│ ├── jasmine.js
│ └── spec.js
├── global_teardown_failure
│ ├── jasmine.js
│ └── spec.js
├── global_teardown_success
│ ├── global_setup_success
│ │ ├── jasmine.js
│ │ └── spec.js
│ ├── jasmine.js
│ └── spec.js
├── global_teardown_unhandled
│ ├── jasmine.js
│ └── spec.js
├── import-jsx
│ ├── jasmine.json
│ └── spec.jsx
├── jasmine_spec
│ ├── c.js
│ ├── d.js
│ ├── e.js
│ └── f.js
├── js-loader-default
│ ├── anEsModule.js
│ ├── anEsModuleSpec.js
│ ├── anEsRequire.js
│ ├── jasmine.json
│ └── package.json
├── js-loader-import
│ ├── anEsModule.js
│ ├── anEsModuleSpec.js
│ ├── anEsRequire.js
│ ├── anotherEsModuleSpec.js
│ ├── jasmine.json
│ └── package.json
├── js-loader-require
│ ├── aRequire.js
│ ├── aSpec.js
│ └── jasmine.json
├── no-globals-parallel
│ ├── aHelper.js
│ ├── aSpec.js
│ └── runner.js
├── no-globals
│ ├── aSpec.js
│ └── runner.js
├── noisy_require.js
├── parallel_before_after
│ ├── helper.js
│ ├── jasmine.json
│ └── spec.js
├── parallel_filter
│ ├── jasmine.json
│ ├── spec1.js
│ └── spec2.js
├── parallel_helper_load_exception
│ ├── helper.js
│ ├── jasmine.json
│ └── spec.js
├── parallel_helpers
│ ├── helper1.js
│ ├── jasmine.json
│ ├── spec1.js
│ └── spec2.js
├── parallel_invalid_afterEach
│ ├── jasmine.json
│ └── spec.js
├── parallel_invalid_beforeEach
│ ├── jasmine.json
│ └── spec.js
├── parallel_jsLoader
│ ├── a%20spec.js
│ └── jasmine.json
├── parallel_no_specs
│ ├── jasmine.json
│ └── spec1.js
├── parallel_pass
│ ├── jasmine.json
│ ├── spec1.js
│ └── spec2.js
├── parallel_requires
│ ├── jasmine.json
│ ├── requireMe.js
│ ├── spec1.js
│ └── spec2.js
├── parallel_spec_fail
│ ├── jasmine.json
│ ├── spec1.js
│ └── spec2.js
├── parallel_spec_load_exception
│ ├── jasmine.json
│ └── spec.js
├── parallel_suite_fail
│ ├── jasmine.json
│ ├── spec1.js
│ └── spec2.js
├── parallel_suite_incomplete
│ └── jasmine.json
├── premature_exit
│ ├── jasmine.json
│ └── spec.js
├── promiseFailure.js
├── promiseIncomplete.js
├── promiseSuccess.js
├── require_tester.js
├── sample_project
│ └── spec
│ │ ├── fixture_spec.js
│ │ ├── helper.js
│ │ ├── other_fixture_spec.js
│ │ └── support
│ │ ├── jasmine.json
│ │ ├── jasmine_alternate.cjs
│ │ ├── jasmine_alternate.json
│ │ └── jasmine_alternate.mjs
└── topLevelAwaitSentinel.mjs
├── global_setup_or_teardown_runner_spec.js
├── integration_spec.js
├── jasmine_spec.js
├── loader_spec.js
├── npm_package_spec.js
├── parallel_runner_spec.js
├── parallel_worker_spec.js
├── path_spec_filter_spec.js
├── poll.js
├── reporters
└── console_reporter_spec.js
├── shared_runner_behaviors.js
└── support
└── jasmine.json
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Run tests against supported Node versions
2 |
3 | version: 2.1
4 |
5 | orbs:
6 | win: circleci/windows@5.0.0
7 | node: circleci/node@5.0.2
8 |
9 | executors:
10 | node24:
11 | docker:
12 | - image: cimg/node:24.0.0
13 | working_directory: ~/workspace
14 | node22:
15 | docker:
16 | - image: cimg/node:22.0.0
17 | working_directory: ~/workspace
18 | node20:
19 | docker:
20 | - image: cimg/node:20.0.0
21 | working_directory: ~/workspace
22 | node18:
23 | docker:
24 | - image: cimg/node:18.0.0
25 | working_directory: ~/workspace
26 |
27 | jobs:
28 | test:
29 | parameters:
30 | executor:
31 | type: executor
32 | executor: << parameters.executor >>
33 | steps:
34 | - checkout
35 | - run:
36 | name: Report Node and NPM versions
37 | command: echo "Using Node $(node --version) and NPM $(npm --version)"
38 | - run:
39 | name: Install dependencies
40 | command: npm install
41 | - run:
42 | name: Run tests
43 | command: npm test
44 | test_win:
45 | executor:
46 | name: win/default
47 | shell: bash.exe
48 | steps:
49 | - checkout
50 | - run:
51 | name: Install Node.js
52 | command: nvm install 18.0.0 && nvm use 18.0.0
53 | - run:
54 | name: Report Node and NPM versions
55 | command: echo "Using Node $(node --version) and NPM $(npm --version)"
56 | - run:
57 | name: Install dependencies
58 | command: npm install
59 | - run:
60 | name: Run tests
61 | command: npm test
62 |
63 | workflows:
64 | version: 2
65 | push: &push_workflow
66 | jobs:
67 | - test:
68 | matrix:
69 | parameters:
70 | executor:
71 | - node24
72 | - node22
73 | - node20
74 | - node18
75 | - test_win
76 | cron:
77 | <<: *push_workflow
78 | triggers:
79 | - schedule:
80 | # Times are UTC.
81 | cron: "0 10 * * *"
82 | filters:
83 | branches:
84 | only:
85 | - main
86 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = lf
4 | insert_final_newline = true
5 |
6 | [*.{js, json, yml}]
7 | indent_style = space
8 | indent_size = 2
9 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Jasmine
2 |
3 | ## Bug reports
4 |
5 | Bug reports are welcome, but please help us help you by:
6 |
7 | * Searching for existing issues (including closed issues) that are similar to
8 | yours
9 | * Reading the [FAQ](https://jasmine.github.io/pages/faq.html)
10 | * Providing enough information for someone else to to understand and reproduce
11 | the problem. In most cases that includes a clear description of what you're
12 | trying to do, the version of each Jasmine package that you're using, the Node
13 | version, and a minimal but complete code sample that demonstrates the problem.
14 |
15 | ## Contributing documentation
16 |
17 | We welcome efforts to improve Jasmine's documentation. The source code for the
18 | documentation site is at .
19 |
20 | ## Contributing code
21 |
22 | Contributions are welcome, but we don't say yes to every idea. We recommend
23 | opening an issue to propose your idea before starting work, to reduce the risk
24 | of getting a "no" at the pull request stage.
25 |
26 | Don't have an idea of your own but want to help solve problems for other
27 | people? That's great! Have a look at the list of
28 | [issues tagged "help needed"](https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Ajasmine+sort%3Aupdated-desc).
29 |
30 | ### The nuts and bolts of preparing a pull request
31 |
32 | Jasmine is mature software that's downloaded millions of times a week and
33 | supported by a tiny group of people in their free time. Anything that breaks
34 | things for existing users or makes Jasmine harder to maintain is a tough sell.
35 |
36 | Before submitting a PR, please check that:
37 |
38 | * You aren't introducing any breaking changes
39 | * `npm test` succeeds: tests pass, there are no eslint or prettier errors,
40 | and the exit status is 0
41 | * Your change is well tested: you're reasonably confident that the tests will
42 | fail if somebody breaks your new functionality in the future
43 | * Your code matches the style of the surrounding code
44 |
45 |
46 | We use Circle CI to test pull requests against a variety of operating systems
47 | and Node versions. Please check back after submitting your PR and make sure
48 | that the build succeeded.
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | lib-cov
3 | lcov.info
4 | *.seed
5 | *.log
6 | *.csv
7 | *.dat
8 | *.out
9 | *.pid
10 | *.gz
11 | *.sw?
12 |
13 | pids
14 | logs
15 | results
16 | build
17 | .grunt
18 |
19 | node_modules
20 | package-lock.json
21 | yarn.lock
22 | .DS_Store
23 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jasmine-maintainers@googlegroups.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2019 Pivotal Labs
2 | Copyright (c) 2014-2025 The Jasmine developers
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Jasmine Package
2 |
3 | The `jasmine` package is a command line interface and supporting code for running
4 | [Jasmine](https://github.com/jasmine/jasmine) specs under Node.
5 |
6 | The core of jasmine lives at https://github.com/jasmine/jasmine and is `jasmine-core` in npm.
7 |
8 | ## Contents
9 |
10 | This package allows you to run Jasmine specs for your Node.js code. The output will be displayed in your terminal by default.
11 |
12 | ## Documentation
13 |
14 | https://jasmine.github.io/setup/nodejs.html
15 |
16 | ## Quick Start
17 |
18 | Installation:
19 |
20 | ```sh
21 | npm install --save-dev jasmine
22 | ```
23 |
24 | To initialize a project for Jasmine:
25 |
26 | ```sh
27 | npx jasmine init
28 | ````
29 |
30 | To seed your project with some examples:
31 |
32 | ```sh
33 | npx jasmine examples
34 | ````
35 |
36 | To run your test suite:
37 |
38 | ```sh
39 | npx jasmine
40 | ````
41 |
42 | ## ES and CommonJS module compatibility
43 |
44 | Jasmine is compatible with both ES modules and CommonJS modules. See the
45 | [setup guide](https://jasmine.github.io/setup/nodejs.html) for more information.
46 |
47 |
48 | ## Node version compatibility
49 |
50 | Jasmine supports Node 18*, 20, 22, and 24.
51 |
52 | \* Environments that are past end of life are supported on a best-effort basis.
53 | They may be dropped in a future minor release of Jasmine if continued support
54 | becomes impractical.
55 |
56 | ## Support
57 |
58 | Documentation: [jasmine.github.io](https://jasmine.github.io)
59 | Please file issues here at GitHub.
60 |
61 | Copyright (c) 2014-2019 Pivotal Labs
62 | Copyright (c) 2014-2025 The Jasmine developers
63 | This software is licensed under the MIT License.
64 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # How to work on a Jasmine Release
2 |
3 | ## Prepare the release
4 | When ready to release - specs are all green and the stories are done:
5 |
6 | 1. If this is a major or minor release, publish the corresponding release of
7 | `jasmine-core` as described in that repo's `RELEASE.md`.
8 | 2. Create release notes using the Anchorman gem.
9 | 3. In `package.json`, update both the package version and the `jasmine-core`
10 | dependency version. This package should depend on the same major and minor
11 | version of `jasmine-core`. For instance, 4.1.1 should depend on
12 | `"jasmine-core": "~4.1.0"`.
13 | 4. Commit and push.
14 | 5. Wait for Circle CI to go green again.
15 |
16 | ## Publish the NPM package
17 |
18 | 1. Create a tag for the version, e.g. `git tag v4.4.0`.
19 | 2. Push the tag: `git push --tags`
20 | 3. Publish the NPM package: `npm publish`.
21 |
22 | ### Publish the GitHub release
23 |
24 | 1. Visit the GitHub releases page and find the tag just published.
25 | 2. Paste in a link to the correct release notes for this release.
26 | 3. If it is a pre-release, mark it as such.
27 | 4. Publish the release.
28 |
--------------------------------------------------------------------------------
/bin/jasmine.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const path = require('path');
4 | const os = require('os');
5 | const process = require('process');
6 | const Command = require('../lib/command');
7 | const Jasmine = require('../lib/jasmine');
8 | const ParallelRunner = require("../lib/parallel_runner");
9 |
10 | const examplesDir = path.join(path.dirname(require.resolve('jasmine-core')), 'jasmine-core', 'example', 'node_example');
11 | const command = new Command(path.resolve(), examplesDir, {
12 | Jasmine,
13 | ParallelRunner,
14 | print: console.log,
15 | terminalColumns: process.stdout.columns,
16 | platform: os.platform,
17 | });
18 |
19 | command.run(process.argv.slice(2))
20 | .catch(e => {
21 | console.error(e);
22 | process.exit(1);
23 | });
24 |
--------------------------------------------------------------------------------
/bin/worker.js:
--------------------------------------------------------------------------------
1 | const cluster = require('node:cluster');
2 | const ParallelWorker = require('../lib/parallel_worker');
3 | const Loader = require('../lib/loader');
4 |
5 | new ParallelWorker({
6 | loader: new Loader(),
7 | process,
8 | clusterWorker: cluster.worker
9 | });
10 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig, globalIgnores } from "eslint/config";
2 |
3 | export default defineConfig([globalIgnores([
4 | "spec/fixtures/cjs-syntax-error/syntax_error.js",
5 | "spec/fixtures/esm-importing-commonjs-syntax-error/syntax_error.js",
6 | "spec/fixtures/js-loader-import/*.js",
7 | "spec/fixtures/js-loader-default/*.js",
8 | "spec/fixtures/esm-reporter-packagejson/customReporter.js",
9 | ]), {
10 | languageOptions: {
11 | ecmaVersion: 11,
12 | sourceType: "script",
13 | },
14 |
15 | rules: {
16 | "no-unused-vars": ["error", {
17 | args: "none",
18 | }],
19 |
20 | "block-spacing": "error",
21 | "func-call-spacing": ["error", "never"],
22 | "key-spacing": "error",
23 | "no-tabs": "error",
24 | "no-whitespace-before-property": "error",
25 | semi: ["error", "always"],
26 | "space-before-blocks": "error",
27 | },
28 | }]);
--------------------------------------------------------------------------------
/lib/command.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const os = require('os');
4 | const unWindows = require('./unWindows');
5 |
6 | exports = module.exports = Command;
7 |
8 | const subCommands = {
9 | init: {
10 | description: 'initialize jasmine',
11 | action: initJasmine
12 | },
13 | examples: {
14 | description: 'install examples',
15 | action: installExamples
16 | },
17 | help: {
18 | description: 'show help',
19 | action: help,
20 | alias: '-h'
21 | },
22 | version: {
23 | description: 'show jasmine and jasmine-core versions',
24 | action: version,
25 | alias: '-v'
26 | },
27 | enumerate: {
28 | description: 'enumerate suites and specs',
29 | action: enumerate
30 | }
31 | };
32 |
33 | function Command(projectBaseDir, examplesDir, deps) {
34 | const {print, platform, terminalColumns, Jasmine, ParallelRunner} = deps;
35 | const isWindows = platform() === 'win32';
36 |
37 | this.projectBaseDir = isWindows ? unWindows(projectBaseDir) : projectBaseDir;
38 | this.specDir = `${this.projectBaseDir}/spec`;
39 |
40 | const command = this;
41 |
42 | this.run = async function(args) {
43 | setEnvironmentVariables(args);
44 |
45 | let commandToRun;
46 | Object.keys(subCommands).forEach(function(cmd) {
47 | const commandObject = subCommands[cmd];
48 | if (args.indexOf(cmd) >= 0) {
49 | commandToRun = commandObject;
50 | } else if (commandObject.alias && args.indexOf(commandObject.alias) >= 0) {
51 | commandToRun = commandObject;
52 | }
53 | });
54 |
55 | if (commandToRun) {
56 | await commandToRun.action({
57 | Jasmine,
58 | projectBaseDir,
59 | specDir: command.specDir,
60 | examplesDir: examplesDir,
61 | print,
62 | terminalColumns
63 | });
64 | } else {
65 | const options = parseOptions(args, isWindows);
66 | if (options.usageErrors.length > 0) {
67 | process.exitCode = 1;
68 |
69 | for (const e of options.usageErrors) {
70 | print(e);
71 | }
72 |
73 | print('');
74 | help({print, terminalColumns});
75 | } else {
76 | await runJasmine(Jasmine, ParallelRunner, projectBaseDir, options);
77 | }
78 | }
79 | };
80 | }
81 |
82 | function isFileArg(arg) {
83 | return arg.indexOf('--') !== 0 && !isEnvironmentVariable(arg);
84 | }
85 |
86 | function parseOptions(argv, isWindows) {
87 | let files = [];
88 | let helpers = [];
89 | let requires = [];
90 | let unknownOptions = [];
91 | let usageErrors = [];
92 | let color = process.stdout.isTTY || false;
93 | let reporter;
94 | let configPath;
95 | let filterRegex;
96 | let filterPath;
97 | let failFast;
98 | let random;
99 | let seed;
100 | let numWorkers = 1;
101 | let verbose = false;
102 |
103 | for (const arg of argv) {
104 | if (arg === '--no-color') {
105 | color = false;
106 | } else if (arg === '--color') {
107 | color = true;
108 | } else if (arg.match("^--filter=")) {
109 | filterRegex = arg.match("^--filter=(.*)")[1];
110 | } else if (arg.match("^--filter-path=(.*)")) {
111 | const json = arg.match("^--filter-path=(.*)")[1];
112 | try {
113 | filterPath = JSON.parse(json);
114 | } catch {
115 | usageErrors.push('Invalid filter path: ' + json);
116 | }
117 |
118 | if (!(filterPath instanceof Array)) {
119 | usageErrors.push('Invalid filter path: ' + json);
120 | }
121 | } else if (arg.match("^--helper=")) {
122 | helpers.push(arg.match("^--helper=(.*)")[1]);
123 | } else if (arg.match("^--require=")) {
124 | requires.push(arg.match("^--require=(.*)")[1]);
125 | } else if (arg === '--fail-fast') {
126 | failFast = true;
127 | } else if (arg.match("^--random=")) {
128 | random = arg.match("^--random=(.*)")[1] === 'true';
129 | } else if (arg.match("^--seed=")) {
130 | seed = arg.match("^--seed=(.*)")[1];
131 | } else if (arg.match("^--config=")) {
132 | configPath = arg.match("^--config=(.*)")[1];
133 | } else if (arg.match("^--reporter=")) {
134 | reporter = arg.match("^--reporter=(.*)")[1];
135 | } else if (arg.match("^--parallel=(.*)")) {
136 | const w = arg.match("^--parallel=(.*)")[1];
137 | if (w === 'auto') {
138 | // A reasonable default in most situations
139 | numWorkers = os.cpus().length -1;
140 | } else {
141 | numWorkers = parseFloat(w);
142 | if (isNaN(numWorkers) || numWorkers < 2 || numWorkers !== Math.floor(numWorkers)) {
143 | usageErrors.push('Argument to --parallel= must be an integer greater than 1');
144 | }
145 | }
146 | } else if (arg === '--verbose') {
147 | verbose = true;
148 | } else if (arg === '--') {
149 | break;
150 | } else if (isFileArg(arg)) {
151 | files.push(isWindows ? unWindows(arg) : arg);
152 | } else if (!isEnvironmentVariable(arg)) {
153 | unknownOptions.push(arg);
154 | }
155 | }
156 |
157 | if (numWorkers > 1 && filterPath) {
158 | usageErrors.push('--filter-path is not supported in parallel mode.');
159 | }
160 |
161 | if (unknownOptions.length > 0) {
162 | usageErrors.push('Unknown options: ' + unknownOptions.join(', '));
163 | }
164 |
165 | return {
166 | color,
167 | configPath,
168 | filterRegex,
169 | filterPath,
170 | failFast,
171 | helpers,
172 | requires,
173 | reporter,
174 | files,
175 | random,
176 | seed,
177 | numWorkers,
178 | verbose,
179 | usageErrors
180 | };
181 | }
182 |
183 | async function runJasmine(Jasmine, ParallelRunner, projectBaseDir, options) {
184 | let runner;
185 |
186 | if (options.numWorkers > 1) {
187 | runner = new ParallelRunner({
188 | projectBaseDir,
189 | numWorkers: options.numWorkers
190 | });
191 | } else {
192 | runner = new Jasmine({
193 | projectBaseDir
194 | });
195 | }
196 |
197 | runner.verbose(options.verbose);
198 | await runner.loadConfigFile(options.configPath || process.env.JASMINE_CONFIG_PATH);
199 |
200 | if (options.failFast !== undefined) {
201 | runner.configureEnv({
202 | stopSpecOnExpectationFailure: options.failFast,
203 | stopOnSpecFailure: options.failFast
204 | });
205 | }
206 |
207 | if (options.seed !== undefined) {
208 | runner.seed(options.seed);
209 | }
210 |
211 | if (options.random !== undefined) {
212 | runner.randomizeTests(options.random);
213 | }
214 |
215 | if (options.helpers !== undefined && options.helpers.length) {
216 | runner.addMatchingHelperFiles(options.helpers);
217 | }
218 |
219 | if (options.requires !== undefined && options.requires.length) {
220 | runner.addRequires(options.requires);
221 | }
222 |
223 | if (options.reporter !== undefined) {
224 | await registerReporter(options.reporter, runner);
225 | }
226 |
227 | runner.showColors(options.color);
228 |
229 | let filter;
230 |
231 | if (options.filterRegex) {
232 | filter = options.filterRegex;
233 | } else if (options.filterPath) {
234 | filter = {path: options.filterPath};
235 | }
236 |
237 | try {
238 | await runner.execute(options.files, filter);
239 | } catch (error) {
240 | console.error(error);
241 | process.exit(1);
242 | }
243 | }
244 |
245 | async function registerReporter(reporterModuleName, runner) {
246 | let Reporter;
247 |
248 | try {
249 | Reporter = await runner.loader.load(resolveReporter(reporterModuleName));
250 | } catch (e) {
251 | throw new Error('Failed to load reporter module '+ reporterModuleName +
252 | '\nUnderlying error: ' + e.stack + '\n(end underlying error)');
253 | }
254 |
255 | let reporter;
256 |
257 | try {
258 | reporter = new Reporter();
259 | } catch (e) {
260 | throw new Error('Failed to instantiate reporter from '+ reporterModuleName +
261 | '\nUnderlying error: ' + e.stack + '\n(end underlying error)');
262 |
263 | }
264 | runner.clearReporters();
265 | runner.addReporter(reporter);
266 | }
267 |
268 | function resolveReporter(nameOrPath) {
269 | if (nameOrPath.startsWith('./') || nameOrPath.startsWith('../')) {
270 | return path.resolve(nameOrPath);
271 | } else {
272 | return nameOrPath;
273 | }
274 | }
275 |
276 | function initJasmine(options) {
277 | const print = options.print;
278 | const destDir = path.join(options.specDir, 'support/');
279 | makeDirStructure(destDir);
280 | const destPath = path.join(destDir, 'jasmine.mjs');
281 |
282 | if (fs.existsSync(destPath)) {
283 | print('spec/support/jasmine.mjs already exists in your project.');
284 | } else {
285 | const contents = fs.readFileSync(
286 | path.join(__dirname, '../lib/examples/jasmine.mjs'), 'utf-8');
287 | fs.writeFileSync(destPath, contents);
288 | }
289 | }
290 |
291 | function installExamples(options) {
292 | const specDir = options.specDir;
293 | const projectBaseDir = options.projectBaseDir;
294 | const examplesDir = options.examplesDir;
295 |
296 | makeDirStructure(path.join(specDir, 'support'));
297 | makeDirStructure(path.join(specDir, 'jasmine_examples'));
298 | makeDirStructure(path.join(specDir, 'helpers', 'jasmine_examples'));
299 | makeDirStructure(path.join(projectBaseDir, 'lib', 'jasmine_examples'));
300 |
301 | copyFiles(
302 | path.join(examplesDir, 'spec', 'helpers', 'jasmine_examples'),
303 | path.join(specDir, 'helpers', 'jasmine_examples'),
304 | new RegExp(/[Hh]elper\.js/)
305 | );
306 |
307 | copyFiles(
308 | path.join(examplesDir, 'lib', 'jasmine_examples'),
309 | path.join(projectBaseDir, 'lib', 'jasmine_examples'),
310 | new RegExp(/\.js/)
311 | );
312 |
313 | copyFiles(
314 | path.join(examplesDir, 'spec', 'jasmine_examples'),
315 | path.join(specDir, 'jasmine_examples'),
316 | new RegExp(/[Ss]pec.js/)
317 | );
318 | }
319 |
320 | function help(deps) {
321 | const print = deps.print;
322 | let terminalColumns = deps.terminalColumns || 80;
323 |
324 | print(wrap(terminalColumns, 'Usage: jasmine [command] [options] [files] [--]'));
325 | print('');
326 | print('Commands:');
327 | Object.keys(subCommands).forEach(function(cmd) {
328 | let commandNameText = cmd;
329 | if(subCommands[cmd].alias) {
330 | commandNameText = commandNameText + ',' + subCommands[cmd].alias;
331 | }
332 | print(wrapWithIndent(terminalColumns, lPad(commandNameText, 10) + ' ', subCommands[cmd].description));
333 | });
334 | print('');
335 | print(wrap(terminalColumns, 'If no command is given, Jasmine specs will be run.'));
336 | print('');
337 | print('');
338 |
339 | print('Options:');
340 |
341 | const options = [
342 | { syntax: '--parallel=N', help: 'Run in parallel with N workers' },
343 | { syntax: '--parallel=auto', help: 'Run in parallel with an automatically chosen number of workers' },
344 | { syntax: '--no-color', help: 'turn off color in spec output' },
345 | { syntax: '--color', help: 'force turn on color in spec output' },
346 | { syntax: '--filter=', help: 'filter specs to run only those that match the given regular expression' },
347 | { syntax: '--filter-path=', help: 'run only the spec or suite that matches ' +
348 | 'the given path, e.g. ' +
349 | '--filter-path=\'["parent suite name","child suite name","spec name"]\'' },
350 | { syntax: '--helper=', help: 'load helper files that match the given string' },
351 | { syntax: '--require=', help: 'load module that matches the given string' },
352 | { syntax: '--fail-fast', help: 'stop Jasmine execution on spec failure' },
353 | { syntax: '--config=', help: 'path to the Jasmine configuration file' },
354 | { syntax: '--reporter=', help: 'path to reporter to use instead of the default Jasmine reporter' },
355 | { syntax: '--verbose', help: 'print information that may be useful for debugging configuration' },
356 | { syntax: '--', help: 'marker to signal the end of options meant for Jasmine' },
357 | ];
358 |
359 | for (const o of options) {
360 | print(wrapWithIndent(terminalColumns, lPad(o.syntax, 18) + ' ', o.help));
361 | }
362 |
363 | print('');
364 | print(wrap(terminalColumns,
365 | 'The given arguments take precedence over options in your jasmine.json.'));
366 | print(wrap(terminalColumns,
367 | 'The path to your optional jasmine.json can also be configured by setting the JASMINE_CONFIG_PATH environment variable.'));
368 | }
369 |
370 | function wrapWithIndent(cols, prefix, suffix) {
371 | const lines = wrap2(cols - prefix.length, suffix);
372 | const indent = lPad('', prefix.length);
373 | return prefix + lines.join('\n' + indent);
374 | }
375 |
376 | function wrap(cols, input) {
377 | return wrap2(cols, input).join('\n');
378 | }
379 |
380 | function wrap2(cols, input) {
381 | let lines = [];
382 | let start = 0;
383 |
384 | while (start < input.length) {
385 | const splitAt = indexOfLastSpaceInRange(start, start + cols, input);
386 |
387 | if (splitAt === -1 || input.length - start <= cols) {
388 | lines.push(input.substring(start));
389 | break;
390 | } else {
391 | lines.push(input.substring(start, splitAt));
392 | start = splitAt + 1;
393 | }
394 | }
395 |
396 | return lines;
397 | }
398 |
399 | function indexOfLastSpaceInRange(start, end, s) {
400 | for (let i = end; i >= start; i--) {
401 | if (s[i] === ' ') {
402 | return i;
403 | }
404 | }
405 |
406 | return -1;
407 | }
408 |
409 | function version(options) {
410 | const print = options.print;
411 | print('jasmine v' + require('../package.json').version);
412 | const jasmine = new options.Jasmine();
413 | print('jasmine-core v' + jasmine.coreVersion());
414 | }
415 |
416 | async function enumerate(options) {
417 | const runner = new options.Jasmine({projectBaseDir: options.projectBaseDir});
418 | await runner.loadConfigFile(options.configPath || process.env.JASMINE_CONFIG_PATH);
419 |
420 | if (options.helpers !== undefined && options.helpers.length) {
421 | runner.addMatchingHelperFiles(options.helpers);
422 | }
423 |
424 | if (options.requires !== undefined && options.requires.length) {
425 | runner.addRequires(options.requires);
426 | }
427 |
428 | const suites = await runner.enumerate();
429 | options.print(JSON.stringify(suites, null, ' '));
430 | }
431 |
432 | function lPad(str, length) {
433 | if (str.length >= length) {
434 | return str;
435 | } else {
436 | return lPad(' ' + str, length);
437 | }
438 | }
439 |
440 | function copyFiles(srcDir, destDir, pattern) {
441 | const srcDirFiles = fs.readdirSync(srcDir);
442 | srcDirFiles.forEach(function(file) {
443 | if (file.search(pattern) !== -1) {
444 | fs.writeFileSync(path.join(destDir, file), fs.readFileSync(path.join(srcDir, file)));
445 | }
446 | });
447 | }
448 |
449 | function makeDirStructure(absolutePath) {
450 | const splitPath = absolutePath.split(path.sep);
451 | splitPath.forEach(function(dir, index) {
452 | if(index > 1) {
453 | const fullPath = path.join(splitPath.slice(0, index).join('/'), dir);
454 | if (!fs.existsSync(fullPath)) {
455 | fs.mkdirSync(fullPath);
456 | }
457 | }
458 | });
459 | }
460 |
461 | function isEnvironmentVariable(arg) {
462 | if (arg.match(/^--/)) {
463 | return false;
464 | }
465 |
466 | return arg.match(/(.*)=(.*)/);
467 | }
468 |
469 | function setEnvironmentVariables(args) {
470 | args.forEach(function (arg) {
471 | const regExpMatch = isEnvironmentVariable(arg);
472 | if(regExpMatch) {
473 | const key = regExpMatch[1];
474 | const value = regExpMatch[2];
475 | process.env[key] = value;
476 | }
477 | });
478 | }
479 |
--------------------------------------------------------------------------------
/lib/examples/jasmine.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | spec_dir: "spec",
3 | spec_files: [
4 | "**/*[sS]pec.?(m)js"
5 | ],
6 | helpers: [
7 | "helpers/**/*.?(m)js"
8 | ],
9 | env: {
10 | stopSpecOnExpectationFailure: false,
11 | random: true,
12 | forbidDuplicateNames: true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/exit_handler.js:
--------------------------------------------------------------------------------
1 | class ExitHandler {
2 | constructor(onExit) {
3 | this._onExit = onExit;
4 | }
5 |
6 | install() {
7 | process.on('exit', this._onExit);
8 | }
9 |
10 | uninstall() {
11 | process.removeListener('exit', this._onExit);
12 | }
13 | }
14 |
15 | module.exports = ExitHandler;
16 |
--------------------------------------------------------------------------------
/lib/filters/path_spec_filter.js:
--------------------------------------------------------------------------------
1 | module.exports = exports = pathSpecFilter;
2 |
3 | function pathSpecFilter(filterPath) {
4 | return function(spec) {
5 | const specPath = spec.getPath();
6 |
7 | if (filterPath.length > specPath.length) {
8 | return false;
9 | }
10 |
11 | for (let i = 0; i < filterPath.length; i++) {
12 | if (specPath[i] !== filterPath[i]) {
13 | return false;
14 | }
15 | }
16 |
17 | return true;
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/lib/filters/regex_spec_filter.js:
--------------------------------------------------------------------------------
1 | module.exports = exports = regexSpecFilter;
2 |
3 | function regexSpecFilter(filterString) {
4 | const filterPattern = new RegExp(filterString);
5 |
6 | return function(spec) {
7 | return filterPattern.test(spec.getFullName());
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/lib/global_setup_or_teardown_runner.js:
--------------------------------------------------------------------------------
1 | // Functionally similar to wrapping a single fn in a QueueRunner
2 | // (except for the lack of callback support), but considerably simpler
3 | class GlobalSetupOrTeardownRunner {
4 | async run(name, fn, timeoutMs) {
5 | await withTimeout(name, timeoutMs, async function() {
6 | await withGlobalErrorHandling(name, fn);
7 | });
8 | }
9 | }
10 |
11 | async function withGlobalErrorHandling(name, fn) {
12 | process.on('uncaughtException', onUncaughtException);
13 | process.on('unhandledRejection', onUnhandledRejection);
14 | let globalError = null;
15 |
16 | try {
17 | await fn();
18 | } finally {
19 | process.off('uncaughtException', onUncaughtException);
20 | process.off('unhandledRejection', onUnhandledRejection);
21 | }
22 |
23 | if (globalError) {
24 | throw globalError;
25 | }
26 |
27 | function onUncaughtException(e) {
28 | globalError = new Error(`Unhandled exception during ${name}`, {
29 | cause: e
30 | });
31 | }
32 |
33 | function onUnhandledRejection(e) {
34 | globalError = new Error(`Unhandled promise rejection during ${name}`, {
35 | cause: e
36 | });
37 | }
38 | }
39 |
40 | async function withTimeout(name, timeoutMs, fn) {
41 | timeoutMs = timeoutMs || 5000;
42 | const maybePromise = fn();
43 | const timedOut = {};
44 | const timeoutPromise = new Promise(function(res) {
45 | setTimeout(function() {
46 | res(timedOut);
47 | }, timeoutMs);
48 | });
49 |
50 | const result = await Promise.race([maybePromise, timeoutPromise]);
51 |
52 | if (result === timedOut) {
53 | throw new Error(`${name} timed out after ${timeoutMs} milliseconds`);
54 | }
55 | }
56 |
57 | module.exports = GlobalSetupOrTeardownRunner;
58 |
--------------------------------------------------------------------------------
/lib/jasmine.js:
--------------------------------------------------------------------------------
1 | const ExitHandler = require('./exit_handler');
2 | const regexSpecFilter = require('./filters/regex_spec_filter');
3 | const pathSpecFilter = require('./filters/path_spec_filter');
4 | const RunnerBase = require('./runner_base');
5 |
6 | /**
7 | * Options for the {@link Jasmine} constructor
8 | * @name JasmineOptions
9 | * @interface
10 | */
11 | /**
12 | * The path to the project's base directory. This can be absolute or relative
13 | * to the current working directory. If it isn't specified, the current working
14 | * directory will be used.
15 | * @name JasmineOptions#projectBaseDir
16 | * @type (string | undefined)
17 | */
18 | /**
19 | * Whether to create the globals (describe, it, etc) that make up Jasmine's
20 | * spec-writing interface. If it is set to false, the spec-writing interface
21 | * can be accessed via jasmine-core's `noGlobals` method, e.g.:
22 | *
23 | * `const {describe, it, expect, jasmine} = require('jasmine-core').noGlobals();`
24 | *
25 | * @name JasmineOptions#globals
26 | * @type (boolean | undefined)
27 | * @default true
28 | */
29 |
30 | /**
31 | * @classdesc Configures, builds, and executes a Jasmine test suite.
See also {@link ParallelRunner} which provides equivalent functionality for parallel execution.
32 | * @param {(JasmineOptions | undefined)} options
33 | * @constructor
34 | * @name Jasmine
35 | * @extends Runner
36 | * @example
37 | * const Jasmine = require('jasmine');
38 | * const runner = new Jasmine();
39 | */
40 | class Jasmine extends RunnerBase {
41 | constructor(options) {
42 | options = options || {};
43 | super(options);
44 | const jasmineCore = options.jasmineCore || require('jasmine-core');
45 |
46 | if (options.globals === false) {
47 | this.jasmine = jasmineCore.noGlobals().jasmine;
48 | } else {
49 | this.jasmine = jasmineCore.boot(true);
50 | }
51 |
52 | /**
53 | * The Jasmine environment.
54 | * @name Jasmine#env
55 | * @readonly
56 | * @see {@link https://jasmine.github.io/api/edge/Env.html|Env}
57 | * @type {Env}
58 | */
59 | this.env = this.jasmine.getEnv({suppressLoadErrors: true});
60 | this.reportersCount = 0;
61 | this.exit = process.exit;
62 | this.addReporter(this.reporter_);
63 |
64 | /**
65 | * @function
66 | * @name Jasmine#coreVersion
67 | * @return {string} The version of jasmine-core in use
68 | */
69 | this.coreVersion = function() {
70 | return jasmineCore.version();
71 | };
72 |
73 | // Public. See RunnerBase.
74 | this.exitOnCompletion = true;
75 | }
76 |
77 | /**
78 | * Sets whether to randomize the order of specs.
79 | * @function
80 | * @name Jasmine#randomizeTests
81 | * @param {boolean} value Whether to randomize
82 | */
83 | randomizeTests(value) {
84 | this.env.configure({random: value});
85 | }
86 |
87 | /**
88 | * Sets the random seed.
89 | * @function
90 | * @name Jasmine#seed
91 | * @param {number} seed The random seed
92 | */
93 | seed(value) {
94 | this.env.configure({seed: value});
95 | }
96 |
97 | // Public. See RunnerBase jsdocs.
98 | addReporter(reporter) {
99 | this.env.addReporter(reporter);
100 | this.reportersCount++;
101 | }
102 |
103 | // Public. See RunnerBase jsdocs.
104 | clearReporters() {
105 | this.env.clearReporters();
106 | this.reportersCount = 0;
107 | }
108 |
109 | /**
110 | * Provide a fallback reporter if no other reporters have been specified.
111 | * @function
112 | * @name Jasmine#provideFallbackReporter
113 | * @param reporter The fallback reporter
114 | * @see custom_reporter
115 | */
116 | provideFallbackReporter(reporter) {
117 | this.env.provideFallbackReporter(reporter);
118 | }
119 |
120 | /**
121 | * Add custom matchers for the current scope of specs.
122 | *
123 | * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
124 | * @function
125 | * @name Jasmine#addMatchers
126 | * @param {Object} matchers - Keys from this object will be the new matcher names.
127 | * @see custom_matcher
128 | */
129 | addMatchers(matchers) {
130 | this.env.addMatchers(matchers);
131 | }
132 |
133 | async loadSpecs() {
134 | await this._loadFiles(this.specFiles);
135 | }
136 |
137 | async loadHelpers() {
138 | await this._loadFiles(this.helperFiles);
139 | }
140 |
141 | async _loadFiles(files) {
142 | for (const file of files) {
143 | await this.loader.load(file);
144 | }
145 | }
146 |
147 | async loadRequires() {
148 | await this._loadFiles(this.requires);
149 | }
150 |
151 | configureEnv(envConfig) {
152 | this.env.configure(envConfig);
153 | }
154 |
155 | /**
156 | * Sets whether to cause specs to only have one expectation failure.
157 | * @function
158 | * @name Jasmine#stopSpecOnExpectationFailure
159 | * @param {boolean} value Whether to cause specs to only have one expectation
160 | * failure
161 | */
162 | stopSpecOnExpectationFailure(value) {
163 | this.env.configure({stopSpecOnExpectationFailure: value});
164 | }
165 |
166 | /**
167 | * Sets whether to stop execution of the suite after the first spec failure.
168 | * @function
169 | * @name Jasmine#stopOnSpecFailure
170 | * @param {boolean} value Whether to stop execution of the suite after the
171 | * first spec failure
172 | */
173 | stopOnSpecFailure(value) {
174 | this.env.configure({stopOnSpecFailure: value});
175 | }
176 |
177 | /**
178 | * Runs the test suite.
179 | *
180 | * _Note_: Set {@link Jasmine#exitOnCompletion|exitOnCompletion} to false if you
181 | * intend to use the returned promise. Otherwise, the Node process will
182 | * ordinarily exit before the promise is settled.
183 | * @param {Array.} [files] Spec files to run instead of the previously
184 | * configured set
185 | * @param {string|RegExp|object} [filter] Optional specification of what specs to run.
186 | * Can be a RegExp, a string, or an object. If it's a RegExp, it will be matched
187 | * against the full names of specs. If it's a string, it will be converted to
188 | * a RegExp and then handled in the same way. If it's
189 | * an object, it should have a path property whose value is an array of spec
190 | * or suite descriptions.
191 | * Regex used to filter specs. If specified, only
192 | * specs with matching full names will be run.
193 | * @return {Promise} Promise that is resolved when the suite completes.
194 | * @example
195 | * // Run all specs
196 | * await jasmine.execute();
197 | *
198 | * // Run just spec/someSpec.js
199 | * await jasmine.execute(['spec/someSpec.js']);
200 | *
201 | * // Run all specs with full paths starting with "a suite a child suite"
202 | * await jasmine.execute(null, '^a suite a child suite');
203 | *
204 | * // Run all specs that are inside a suite named "a child suite" that is
205 | * // a child of a top-level suite named "a suite"
206 | * await jasmine.execute(null, {path: ['a suite', 'a child suite']});
207 | */
208 | async execute(files, filter) {
209 | await this.loadRequires();
210 | await this.loadHelpers();
211 | if (!this.defaultReporterConfigured) {
212 | this.configureDefaultReporter({
213 | showColors: this.showingColors,
214 | alwaysListPendingSpecs: this.alwaysListPendingSpecs_
215 | });
216 | }
217 |
218 | if (filter) {
219 | if (typeof filter === 'string' || filter instanceof RegExp) {
220 | this.env.configure({
221 | specFilter: regexSpecFilter(filter)
222 | });
223 | } else if (filter.path) {
224 | this.env.configure({
225 | specFilter: pathSpecFilter(filter.path)
226 | });
227 | } else {
228 | throw new Error('Unrecognized filter type');
229 | }
230 | }
231 |
232 | if (files && files.length > 0) {
233 | if (this.isVerbose_) {
234 | console.log('Overriding previous specDir and specFiles because a list of spec files was provided on the command line or as an argument to Jasmine#execute');
235 | }
236 |
237 | this.specDir = '';
238 | this.specFiles = [];
239 | this.addMatchingSpecFiles(files);
240 | }
241 |
242 | const prematureExitHandler = new ExitHandler(() => this.exit(4));
243 | prematureExitHandler.install();
244 | let overallResult;
245 |
246 | try {
247 | await this.withinGlobalSetup_(async () => {
248 | await this.loadSpecs();
249 | overallResult = await this.env.execute();
250 | });
251 | } finally {
252 | await this.flushOutput();
253 | prematureExitHandler.uninstall();
254 | }
255 |
256 | if (this.exitOnCompletion) {
257 | this.exit(RunnerBase.exitCodeForStatus(overallResult.overallStatus));
258 | }
259 |
260 | return overallResult;
261 | }
262 |
263 | /**
264 | * Returns a tree of suites and specs without actually running the specs.
265 | * @return {Promise}
266 | */
267 | async enumerate() {
268 | await this.loadRequires();
269 | await this.loadHelpers();
270 | await this.loadSpecs();
271 |
272 | return this.env.topSuite().children.map(toEnumerateResult);
273 | }
274 | }
275 |
276 | function toEnumerateResult(suiteOrSpecMeta) {
277 | // Omit parent links to avoid JSON serialization failure due to circular
278 | // references. Omit IDs since they aren't stable across executions. Add
279 | // type information to make interpreting the output easier.
280 |
281 | /**
282 | * @interface EnumeratedSuiteOrSpec
283 | * @property {string} type - 'suite' or 'spec'
284 | * @property {EnumeratedSuiteOrSpec[]} [children] - Only defined for suites
285 | */
286 | const result = {
287 | description: suiteOrSpecMeta.description
288 | };
289 |
290 | if (suiteOrSpecMeta.children === undefined) {
291 | result.type = 'spec';
292 | } else {
293 | result.type = 'suite';
294 | result.children = suiteOrSpecMeta.children.map(toEnumerateResult);
295 | }
296 |
297 | return result;
298 | }
299 |
300 | module.exports = Jasmine;
301 | module.exports.ConsoleReporter = require('./reporters/console_reporter');
302 |
--------------------------------------------------------------------------------
/lib/loader.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const url = require('url');
3 |
4 | class Loader {
5 | constructor(options) {
6 | options = options || {};
7 | this.require_ = options.requireShim || requireShim;
8 | this.import_ = options.importShim || importShim;
9 | this.resolvePath_ = options.resolvePath || path.resolve.bind(path);
10 | this.alwaysImport = true;
11 | }
12 |
13 | load(modulePath) {
14 | if ((this.alwaysImport && !modulePath.endsWith('.json')) || modulePath.endsWith('.mjs')) {
15 | const importSpecifier = this.resolveImportSpecifier_(modulePath);
16 |
17 | return this.import_(importSpecifier)
18 | .then(
19 | mod => mod.default,
20 | e => {
21 | if (e.code === 'ERR_UNKNOWN_FILE_EXTENSION') {
22 | // Extension isn't supported by import, e.g. .jsx. Fall back to
23 | // require(). This could lead to confusing error messages if someone
24 | // tries to use ES module syntax without transpiling in a file with
25 | // an unsupported extension, but it shouldn't break anything and it
26 | // should work well in the normal case where the file is loadable
27 | // as a CommonJS module, either directly or with the help of a
28 | // loader like `@babel/register`.
29 | return this.require_(modulePath);
30 | } else {
31 | return Promise.reject(fixupImportException(e, modulePath));
32 | }
33 | }
34 | );
35 | } else {
36 | return new Promise(resolve => {
37 | const result = this.require_(modulePath);
38 | resolve(result);
39 | });
40 | }
41 | }
42 |
43 | resolveImportSpecifier_(modulePath) {
44 | const isNamespaced = modulePath.startsWith('@');
45 | const isRelative = modulePath.startsWith('.');
46 | const hasExtension = /\.[A-Za-z]+/.test(modulePath);
47 |
48 | const resolvedModulePath = hasExtension || isRelative
49 | ? this.resolvePath_(modulePath)
50 | : modulePath;
51 |
52 | if (isNamespaced || ! hasExtension) {
53 | return resolvedModulePath;
54 | }
55 |
56 | // The ES module spec requires import paths to be valid URLs. As of v14,
57 | // Node enforces this on Windows but not on other OSes. On OS X, import
58 | // paths that are URLs must not contain parent directory references.
59 | return url.pathToFileURL(resolvedModulePath).toString();
60 | }
61 | }
62 |
63 | function requireShim(modulePath) {
64 | return require(modulePath);
65 | }
66 |
67 | function importShim(modulePath) {
68 | return import(modulePath);
69 | }
70 |
71 |
72 | function fixupImportException(e, importedPath) {
73 | // When an ES module has a syntax error, the resulting exception does not
74 | // include the filename, which the user will need to debug the problem. We
75 | // need to fix those up to include the filename. However, other kinds of load-
76 | // time errors *do* include the filename and usually the line number. We need
77 | // to leave those alone.
78 | //
79 | // Some examples of load-time errors that we need to deal with:
80 | // 1. Syntax error in an ESM spec:
81 | // SyntaxError: missing ) after argument list
82 | // at Loader.moduleStrategy (node:internal/modules/esm/translators:147:18)
83 | // at async link (node:internal/modules/esm/module_job:64:21)
84 | //
85 | // 2. Syntax error in an ES module imported from an ESM spec. This is exactly
86 | // the same as #1: there is no way to tell which file actually has the syntax
87 | // error.
88 | //
89 | // 3. Syntax error in a CommonJS module imported by an ES module:
90 | // /path/to/commonjs_with_syntax_error.js:2
91 | //
92 | //
93 | //
94 | // SyntaxError: Unexpected end of input
95 | // at Object.compileFunction (node:vm:355:18)
96 | // at wrapSafe (node:internal/modules/cjs/loader:1038:15)
97 | // at Module._compile (node:internal/modules/cjs/loader:1072:27)
98 | // at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
99 | // at Module.load (node:internal/modules/cjs/loader:988:32)
100 | // at Function.Module._load (node:internal/modules/cjs/loader:828:14)
101 | // at ModuleWrap. (node:internal/modules/esm/translators:201:29)
102 | // at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
103 | // at async Loader.import (node:internal/modules/esm/loader:178:24)
104 | // at async file:///path/to/esm_that_imported_cjs.mjs:2:11
105 | //
106 | // Note: For Jasmine's purposes, case 3 only occurs in Node >= 14.8. Older
107 | // versions don't support top-level await, without which it's not possible to
108 | // load a CommonJS module from an ES module at load-time. The entire content
109 | // above, including the file path and the three blank lines, is part of the
110 | // error's `stack` property. There may or may not be any stack trace after the
111 | // SyntaxError line, and if there's a stack trace it may or may not contain
112 | // any useful information.
113 | //
114 | // 4. Any other kind of exception thrown at load time
115 | //
116 | // Error: nope
117 | // at Object. (/path/to/file_throwing_error.js:1:7)
118 | // at Module._compile (node:internal/modules/cjs/loader:1108:14)
119 | // at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
120 | // at Module.load (node:internal/modules/cjs/loader:988:32)
121 | // at Function.Module._load (node:internal/modules/cjs/loader:828:14)
122 | // at ModuleWrap. (node:internal/modules/esm/translators:201:29)
123 | // at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
124 | // at async Loader.import (node:internal/modules/esm/loader:178:24)
125 | // at async file:///path_to_file_importing_broken_file.mjs:1:1
126 | //
127 | // We need to replace the error with a useful one in cases 1 and 2, but not in
128 | // cases 3 and 4. Distinguishing among them can be tricky. Simple heuristics
129 | // like checking the stack trace for the name of the file we imported fail
130 | // because it often shows up even when the error was elsewhere, e.g. at the
131 | // bottom of the stack traces in the examples for cases 3 and 4 above. To add
132 | // to the fun, file paths in errors on Windows can be either Windows style
133 | // paths (c:\path\to\file.js) or URLs (file:///c:/path/to/file.js).
134 |
135 | if (!(e instanceof SyntaxError)) {
136 | return e;
137 | }
138 |
139 | const escapedWin = escapeStringForRegexp(importedPath.replace(/\//g, '\\'));
140 | const windowsPathRegex = new RegExp('[a-zA-z]:\\\\([^\\s]+\\\\|)' + escapedWin);
141 | const windowsUrlRegex = new RegExp('file:///[a-zA-z]:\\\\([^\\s]+\\\\|)' + escapedWin);
142 | const anyUnixPathFirstLineRegex = /^\/[^\s:]+:\d/;
143 | const anyWindowsPathFirstLineRegex = /^[a-zA-Z]:(\\[^\s\\:]+)+:/;
144 |
145 | if (e.message.indexOf(importedPath) !== -1
146 | || e.stack.indexOf(importedPath) !== -1
147 | || e.stack.match(windowsPathRegex) || e.stack.match(windowsUrlRegex)
148 | || e.stack.match(anyUnixPathFirstLineRegex)
149 | || e.stack.match(anyWindowsPathFirstLineRegex)) {
150 | return e;
151 | } else {
152 | return new Error(
153 | `While loading ${importedPath}: ${e.constructor.name}: ${e.message}`,
154 | {cause: e}
155 | );
156 | }
157 | }
158 |
159 | // Adapted from Sindre Sorhus's escape-string-regexp (MIT license)
160 | function escapeStringForRegexp(string) {
161 | // Escape characters with special meaning either inside or outside character sets.
162 | // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
163 | return string
164 | .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
165 | .replace(/-/g, '\\x2d');
166 | }
167 |
168 | module.exports = Loader;
169 |
--------------------------------------------------------------------------------
/lib/parallel_runner.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const cluster = require('node:cluster');
3 | const RunnerBase = require('./runner_base');
4 | const randomize = require('./randomize');
5 |
6 | /**
7 | * Options for the {@link ParallelRunner} constructor
8 | * @name ParallelRunnerOptions
9 | * @interface
10 | */
11 | /**
12 | * The path to the project's base directory. This can be absolute or relative
13 | * to the current working directory. If it isn't specified, the current working
14 | * directory will be used.
15 | * @name ParallelRunnerOptions#projectBaseDir
16 | * @type (string | undefined)
17 | */
18 | /**
19 | * The number of worker processes to use.
20 | * @name ParallelRunnerOptions#numWorkers
21 | * @type (number | undefined)
22 | * @default 2
23 | */
24 | /**
25 | * Whether to create the globals (describe, it, etc) that make up Jasmine's
26 | * spec-writing interface. If it is set to false, the spec-writing interface
27 | * can be accessed in workers via jasmine-core's `noGlobals` method, e.g.:
28 | *
29 | * `const {describe, it, expect, jasmine} = require('jasmine-core').noGlobals();`
30 | *
31 | * @name ParallelRunnerOptions#globals
32 | * @type (boolean | undefined)
33 | * @default true
34 | */
35 |
36 | /**
37 | * @classdesc Configures, builds, and executes a Jasmine test suite in parallel.
38 | * @param {(ParallelRunnerOptions | undefined)} options
39 | * @constructor
40 | * @name ParallelRunner
41 | * @extends Runner
42 | * @example
43 | * const ParallelRunner = require('jasmine/parallel');
44 | * const runner = new ParallelRunner({numWorkers: 3});
45 | */
46 | class ParallelRunner extends RunnerBase {
47 | constructor(options) {
48 | super(options);
49 | this.cluster_ = options.cluster || cluster;
50 | this.workerDone_ = {};
51 | this.numWorkers_ = options.numWorkers || 2;
52 |
53 | let jasmineCore;
54 |
55 | if (options.jasmineCore) {
56 | // Use the provided core in all processes. This is mainly for use by
57 | // jasmine-core's own test suite.
58 | jasmineCore = options.jasmineCore;
59 | this.jasmineCorePath_ = jasmineCore.files.self;
60 | } else {
61 | jasmineCore = require('jasmine-core');
62 | }
63 |
64 | const bootedCore = jasmineCore.boot();
65 | const ParallelReportDispatcher = options.ParallelReportDispatcher ||
66 | bootedCore.ParallelReportDispatcher;
67 | this.reportDispatcher_ = new ParallelReportDispatcher(error => {
68 | console.error(error);
69 | this.hasUnhandledErrors_ = true;
70 | });
71 | this.reportDispatcher_.addReporter(this.reporter_);
72 | this.timer_ = new bootedCore.Timer();
73 |
74 | // Public. See RunnerBase jsdocs.
75 | this.exitOnCompletion = true;
76 | this.exit = process.exit;
77 | this.reportedFatalErrors_ = [];
78 | }
79 |
80 | // Public. See RunnerBase jsdocs.
81 | clearReporters() {
82 | this.reportDispatcher_.clearReporters();
83 | }
84 |
85 | randomizeTests(value) {
86 | if (!value) {
87 | throw new Error('Randomization cannot be disabled in parallel mode');
88 | }
89 | }
90 |
91 | seed(value) {
92 | throw new Error('Random seed cannot be set in parallel mode');
93 | }
94 |
95 | // Public. See RunnerBase jsdocs.
96 | addReporter(reporter, errorContext) {
97 | if (!reporter.reporterCapabilities?.parallel) {
98 | if (!errorContext) {
99 | errorContext = 'this reporter';
100 | }
101 | throw new Error(
102 | `Can't use ${errorContext} because it doesn't support parallel mode. ` +
103 | '(Add reporterCapabilities: {parallel: true} if the reporter meets ' +
104 | 'the requirements for parallel mode.)'
105 | );
106 | }
107 | this.reportDispatcher_.addReporter(reporter);
108 | }
109 |
110 | /**
111 | * Runs the test suite.
112 | *
113 | * _Note_: Set {@link Runner#exitOnCompletion|exitOnCompletion} to false if you
114 | * intend to use the returned promise. Otherwise, the Node process will
115 | * ordinarily exit before the promise is settled.
116 | * @param {Array.} [files] Spec files to run instead of the previously
117 | * configured set
118 | * @param {string} [filterString] Regex used to filter specs. If specified, only
119 | * specs with matching full names will be run.
120 | * @return {Promise} Promise that is resolved when the suite completes.
121 | */
122 | async execute(files, filterString) {
123 | if (this.isVerbose_) {
124 | console.log(`Running in parallel with ${this.numWorkers_} workers`);
125 | }
126 | if (this.startedExecuting_) {
127 | throw new Error('Parallel runner instance can only be executed once');
128 | }
129 |
130 | this.startedExecuting_ = true;
131 | const explicitFailPromise = new Promise((res, rej) => {
132 | this.failExecution_ = rej;
133 | });
134 |
135 | try {
136 | return await Promise.race([
137 | explicitFailPromise,
138 | this.execute2_(files, filterString)
139 | ]);
140 | } finally {
141 | await this.flushOutput();
142 | }
143 | }
144 |
145 | async execute2_(files, filterString) {
146 | if (!this.defaultReporterConfigured) {
147 | this.configureDefaultReporter({
148 | showColors: this.showingColors,
149 | alwaysListPendingSpecs: this.alwaysListPendingSpecs_
150 | });
151 | }
152 |
153 | if (files && files.length > 0) {
154 | if (this.isVerbose_) {
155 | console.log('Overriding previous specDir and specFiles because a list of spec files was provided on the command line or as an argument to ParallelRunner#execute');
156 | }
157 |
158 | this.specDir = '';
159 | this.specFiles = [];
160 | this.addMatchingSpecFiles(files);
161 | }
162 |
163 | this.executionState_ = {
164 | hasFailures: false,
165 | hasSpecs: false,
166 | failedExpectations: [],
167 | deprecationWarnings: []
168 | };
169 | let jasmineDoneInfo;
170 | await this.withinGlobalSetup_(async () => {
171 | this.timer_.start();
172 |
173 | // Prevent Node from exiting if all workers shut down unexpectedly, such as
174 | // if a helper fails to load. The time interval is arbitrary.
175 | const keepalive = setInterval(function () {
176 | }, 100000);
177 | try {
178 | await this.createWorkers_(filterString);
179 | this.reportDispatcher_.installGlobalErrors();
180 | await this.reportDispatcher_.jasmineStarted({
181 | // Omit totalSpecsDefined because we don't know how many there are.
182 | // Omit order because it's not currently something the user can control
183 | // in parallel mode.
184 | parallel: true
185 | });
186 | await this.runSpecFiles_();
187 | await this.shutDownWorkers_();
188 | jasmineDoneInfo = await this.reportJasmineDone_();
189 | this.reportDispatcher_.uninstallGlobalErrors();
190 | } finally {
191 | clearInterval(keepalive);
192 | }
193 | });
194 |
195 | if (this.exitOnCompletion) {
196 | if (this.hasUnhandledErrors_) {
197 | this.exit(1);
198 | } else {
199 | this.exit(RunnerBase.exitCodeForStatus(jasmineDoneInfo.overallStatus));
200 | }
201 | }
202 |
203 | if (this.hasUnhandledErrors_) {
204 | throw new Error(
205 | 'Unhandled exceptions, unhandled promise rejections, or reporter ' +
206 | 'errors were encountered during execution'
207 | );
208 | }
209 |
210 | return jasmineDoneInfo;
211 | }
212 |
213 | async createWorkers_(filterString) {
214 | const workerPath = path.join(__dirname, '../bin/worker.js');
215 | this.cluster_.setupPrimary({exec: workerPath});
216 | const configPromises = [];
217 |
218 | const workerConfig = {
219 | spec_dir: this.specDir,
220 | helpers: this.helperFiles,
221 | requires: this.requires,
222 | filter: filterString,
223 | globals: this.globals_,
224 | env: this.envConfig_,
225 | };
226 |
227 | if (!this.loader.alwaysImport) {
228 | workerConfig.jsLoader = 'require';
229 | }
230 |
231 | if (this.jasmineCorePath_) {
232 | workerConfig.jasmineCorePath = this.jasmineCorePath_;
233 | }
234 |
235 | for (let i = 0; i < this.numWorkers_; i++) {
236 | const worker = this.cluster_.fork();
237 |
238 | worker.on('exit', () => {
239 | if (!this.workerDone_[worker.id]) {
240 | this.fatalError_('Jasmine worker process unexpectedly exited', undefined, 4);
241 | }
242 | });
243 |
244 | configPromises.push(new Promise(resolve => {
245 | // Wait for the worker to acknowledge that it's booted so that we don't
246 | // tell it to run specs while it's booting.
247 | let booted = false;
248 | worker.on('message', msg => {
249 | switch (msg.type) {
250 | case 'booted':
251 | booted = true;
252 | resolve();
253 | break;
254 |
255 | case 'fatalError':
256 | this.fatalError_(formatErrorFromWorker(msg.error, msg.error.message));
257 | break;
258 |
259 | default:
260 | if (!booted) {
261 | console.error('Got unexpected message from Jasmine worker during boot:', msg);
262 | }
263 | break;
264 | }
265 | });
266 |
267 | const msg = {type: 'configure', configuration: workerConfig};
268 | worker.send(msg);
269 | }));
270 | }
271 |
272 | await Promise.all(configPromises);
273 | }
274 |
275 | shutDownWorkers_() {
276 | return new Promise(resolve => {
277 | this.cluster_.disconnect(resolve);
278 | });
279 | }
280 |
281 | async runSpecFiles_() {
282 | this.specFiles = randomize(this.specFiles);
283 | this.nextSpecFileIx_ = 0;
284 | const workerPromises = Object.values(this.cluster_.workers)
285 | .map(worker => this.runWorker_(worker));
286 | await Promise.all(workerPromises);
287 | }
288 |
289 | async runWorker_(worker) {
290 | return new Promise(resolve => {
291 | const runNextSpecFile = () => {
292 | if (this.exiting_) {
293 | return;
294 | }
295 |
296 | const moreFiles = this.nextSpecFileIx_ < this.specFiles.length;
297 | const stopOnSpecFailure = this.envConfig_ ? this.envConfig_.stopOnSpecFailure : false;
298 |
299 | if (moreFiles && !(this.executionState_.hasFailures && stopOnSpecFailure)) {
300 | const filePath = this.specFiles[this.nextSpecFileIx_++];
301 | worker.send({type: 'runSpecFile', filePath});
302 | } else {
303 | this.workerDone_[worker.id] = true;
304 | resolve();
305 | }
306 | };
307 |
308 | worker.on('message', msg => {
309 | switch (msg.type) {
310 | case 'specFileDone':
311 | if (msg.incompleteCode !== 'noSpecsFound') {
312 | this.executionState_.hasSpecs = true;
313 | }
314 |
315 | if (msg.incompleteCode && msg.incompleteCode !== 'noSpecsFound') {
316 | this.executionState_.incompleteCode = msg.incompleteCode;
317 | this.executionState_.incompleteReason = msg.incompleteReason;
318 | }
319 |
320 | this.executionState_.failedExpectations = [
321 | ...this.executionState_.failedExpectations,
322 | ...msg.failedExpectations
323 | ];
324 | this.executionState_.deprecationWarnings = [
325 | ...this.executionState_.deprecationWarnings,
326 | ...msg.deprecationWarnings
327 | ];
328 | runNextSpecFile();
329 | break;
330 |
331 | case 'specFileLoadError':
332 | this.addTopLevelError_('load',
333 | `Error loading ${msg.filePath}`, msg.error);
334 | runNextSpecFile();
335 | break;
336 |
337 | case 'uncaughtException':
338 | this.addTopLevelError_('lateError',
339 | 'Uncaught exception in worker process', msg.error);
340 | break;
341 |
342 | case 'unhandledRejection':
343 | this.addTopLevelError_('lateError',
344 | 'Unhandled promise rejection in worker process', msg.error);
345 | break;
346 |
347 | case 'reporterEvent':
348 | this.handleReporterEvent_(msg.eventName, msg.payload);
349 | break;
350 |
351 | case 'fatalError':
352 | // Handled elsewhere
353 | break;
354 |
355 | default:
356 | console.error('Got unknown message from Jasmine worker:', msg);
357 | }
358 | });
359 | runNextSpecFile();
360 | });
361 | }
362 |
363 | configureEnv(envConfig) {
364 | if (envConfig.specFilter) {
365 | // specFilter is a function and we can't serialize those
366 | throw new Error('The specFilter config property is not supported in ' +
367 | 'parallel mode');
368 | }
369 |
370 | if (this.startedExecuting_) {
371 | throw new Error("Can't call configureEnv() after execute()");
372 | }
373 |
374 | this.envConfig_ = envConfig;
375 | }
376 |
377 | handleReporterEvent_(eventName, payload) {
378 | switch (eventName) {
379 | case 'jasmineStarted':
380 | case 'jasmineDone':
381 | break;
382 |
383 | case 'specDone':
384 | case 'suiteDone':
385 | if (payload.status === 'failed') {
386 | this.executionState_.hasFailures = true;
387 | }
388 | this.reportDispatcher_[eventName](payload);
389 | break;
390 |
391 | default:
392 | this.reportDispatcher_[eventName](payload);
393 | }
394 | }
395 |
396 | async reportJasmineDone_() {
397 | const event = {
398 | totalTime: this.timer_.elapsed(),
399 | numWorkers: this.numWorkers_,
400 | failedExpectations: this.executionState_.failedExpectations,
401 | deprecationWarnings: this.executionState_.deprecationWarnings,
402 | };
403 |
404 | if (this.executionState_.hasFailures
405 | || this.executionState_.failedExpectations.length > 0) {
406 | event.overallStatus = 'failed';
407 | } else if (this.executionState_.incompleteCode) {
408 | event.overallStatus = 'incomplete';
409 | event.incompleteCode = this.executionState_.incompleteCode;
410 | event.incompleteReason = this.executionState_.incompleteReason;
411 | } else if (!this.executionState_.hasSpecs) {
412 | event.overallStatus = 'incomplete';
413 | event.incompleteCode = 'noSpecsFound';
414 | event.incompleteReason = 'No specs found';
415 | } else {
416 | event.overallStatus = 'passed';
417 | }
418 |
419 | await this.reportDispatcher_.jasmineDone(event);
420 | return event;
421 | }
422 |
423 | fatalError_(msg, msgWithoutStack, optionalExitCode) {
424 | if (!msgWithoutStack) {
425 | msgWithoutStack = msg;
426 | }
427 |
428 | this.exiting_ = true;
429 |
430 | // Some errors may be reported by each worker. Print them only once.
431 | if (!this.reportedFatalErrors_.includes(msg)) {
432 | console.error(msg);
433 | this.reportedFatalErrors_.push(msg);
434 | }
435 |
436 | this.cluster_.disconnect(() => {
437 | if (this.exitOnCompletion) {
438 | this.exit(optionalExitCode || 1);
439 | }
440 |
441 | this.failExecution_(
442 | new Error('Fatal error in Jasmine worker process: ' + msgWithoutStack)
443 | );
444 | });
445 | }
446 |
447 | addTopLevelError_(globalErrorType, msgPrefix, serializedError) {
448 | // Match how jasmine-core reports these in non-parallel situations
449 | this.executionState_.failedExpectations.push({
450 | actual: '',
451 | expected: '',
452 | globalErrorType,
453 | matcherName: '',
454 | message: `${msgPrefix}: ${serializedError.message}`,
455 | passed: false,
456 | stack: serializedError.stack,
457 | });
458 | }
459 | }
460 |
461 | function formatErrorFromWorker(error) {
462 | // error isn't an Error instance (those don't survive IPC) so we have
463 | // to do some extra work to make it display nicely.
464 | const lines = ['Fatal error in worker: '+ error.message];
465 | const stack = error.stack.split('\n');
466 | let i = 0;
467 |
468 | if (stack[0].indexOf(error.message) !== 0) {
469 | i = 1;
470 | }
471 |
472 | for (; i < stack.length; i++) {
473 | lines.push(stack[i]);
474 | }
475 |
476 | return lines.join('\n');
477 | }
478 |
479 | module.exports = ParallelRunner;
480 |
--------------------------------------------------------------------------------
/lib/parallel_worker.js:
--------------------------------------------------------------------------------
1 | const regexSpecFilter = require("./filters/regex_spec_filter");
2 |
3 | class ParallelWorker {
4 | constructor(options) {
5 | this.loader_= options.loader;
6 | this.clusterWorker_ = options.clusterWorker;
7 |
8 | this.clusterWorker_.on('message', msg => {
9 | switch (msg.type) {
10 | case 'configure':
11 | this.configure(msg.configuration);
12 | break;
13 |
14 | case 'runSpecFile':
15 | this.runSpecFile(msg.filePath);
16 | break;
17 |
18 | default:
19 | console.error('Jasmine worker got an unrecognized message:', msg);
20 | }
21 | });
22 |
23 | // Install global error handlers now, before jasmine-core is booted.
24 | // That allows jasmine-core to override them with its own more specific
25 | // handling. These handlers will take care of errors that occur in between
26 | // spec files.
27 | for (const errorType of ['uncaughtException', 'unhandledRejection']) {
28 | options.process.on(errorType, error => {
29 | const sent = sendIfConnected(this.clusterWorker_, {
30 | type: errorType,
31 | error: serializeError(error)
32 | });
33 |
34 | if (!sent) {
35 | console.error(`${errorType} in Jasmine worker process after disconnect:`,
36 | error);
37 | console.error('This error cannot be reported properly because it ' +
38 | 'happened after the worker process was disconnected.'
39 | );
40 | }
41 | });
42 | }
43 | }
44 |
45 | configure(options) {
46 | this.loader_.alwaysImport = options.jsLoader !== 'require';
47 | this.envPromise_ = this.loader_.load(options.jasmineCorePath || 'jasmine-core')
48 | .then(core => {
49 | let env;
50 |
51 | if (options.globals === false) {
52 | env = core.noGlobals().jasmine.getEnv();
53 | } else {
54 | const bootedCore = core.boot(core);
55 | env = bootedCore.getEnv();
56 | }
57 |
58 | env.addReporter(forwardingReporter(this.clusterWorker_));
59 | env.addReporter({
60 | jasmineDone: event => this.jasmineDoneEvent_ = event
61 | });
62 |
63 | if (options.env) {
64 | env.configure(options.env);
65 | }
66 |
67 | if (options.filter) {
68 | env.configure({
69 | specFilter: regexSpecFilter(options.filter)
70 | });
71 | }
72 |
73 | return this.loadFiles_(options.requires || [])
74 | .then(() => {
75 | env.setParallelLoadingState('helpers');
76 | return this.loadFiles_(options.helpers);
77 | })
78 | .then(() => {
79 | env.setParallelLoadingState('specs');
80 | this.clusterWorker_.send({type: 'booted'});
81 | return env;
82 | });
83 | })
84 | .catch(error => {
85 | this.clusterWorker_.send({
86 | type: 'fatalError',
87 | error: serializeError(error)
88 | });
89 | });
90 | }
91 |
92 | async loadFiles_(files) {
93 | for (const file of files) {
94 | await this.loader_.load(file);
95 | }
96 | }
97 |
98 | runSpecFile(specFilePath) {
99 | (async () => {
100 | this.jasmineDoneEvent_ = null;
101 | let env = await this.envPromise_;
102 | env.parallelReset();
103 |
104 | try {
105 | await this.loader_.load(specFilePath);
106 | } catch (error) {
107 | this.clusterWorker_.send({
108 | type: 'specFileLoadError',
109 | filePath: specFilePath,
110 | error: serializeError(error)
111 | });
112 | return;
113 | }
114 |
115 | await env.execute();
116 |
117 | if (!this.clusterWorker_.isConnected()) {
118 | return;
119 | }
120 |
121 | this.clusterWorker_.send({
122 | type: 'specFileDone',
123 | overallStatus: this.jasmineDoneEvent_.overallStatus,
124 | incompleteCode: this.jasmineDoneEvent_.incompleteCode,
125 | incompleteReason: this.jasmineDoneEvent_.incompleteReason,
126 | failedExpectations: this.jasmineDoneEvent_.failedExpectations,
127 | deprecationWarnings: this.jasmineDoneEvent_.deprecationWarnings,
128 | });
129 | })();
130 | }
131 | }
132 |
133 | function serializeError(error) {
134 | return {
135 | message: error.message,
136 | stack: error.stack
137 | };
138 | }
139 |
140 | function forwardingReporter(clusterWorker) {
141 | const reporter = {};
142 | const eventNames = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone'];
143 |
144 | for (const eventName of eventNames) {
145 | reporter[eventName] = function (payload) {
146 | const msg = {
147 | type: 'reporterEvent',
148 | eventName,
149 | payload: {
150 | ...payload,
151 | // IDs we get from -core are only unique within this process.
152 | // Make them globally unique by prepending the worker ID.
153 | id: `${clusterWorker.id}-${payload.id}`
154 | }
155 | };
156 |
157 | try {
158 | sendIfConnected(clusterWorker, msg);
159 | } catch (e) {
160 | if (e instanceof TypeError) {
161 | msg.payload = fixNonSerializableReporterEvent(payload);
162 | sendIfConnected(clusterWorker, msg);
163 | } else {
164 | throw e;
165 | }
166 | }
167 | };
168 | }
169 |
170 | return reporter;
171 | }
172 |
173 | function sendIfConnected(clusterWorker, msg) {
174 | if (clusterWorker.isConnected()) {
175 | try {
176 | clusterWorker.send(msg);
177 | return true;
178 | } catch (e) {
179 | // EPIPE may be thrown if the worker receives a disconnect between
180 | // the calls to isConnected() and send() above.
181 | if (e.code !== 'EPIPE') {
182 | throw e;
183 | }
184 | }
185 | }
186 |
187 | return false;
188 | }
189 |
190 | function fixNonSerializableReporterEvent(payload) {
191 | payload = {...payload};
192 |
193 | for (const ak of ['passedExpectations', 'failedExpectations']) {
194 | if (payload[ak]) {
195 | payload[ak] = payload[ak].map(function(expectation) {
196 | expectation = {...expectation};
197 |
198 | for (const vk of ['expected', 'actual']) {
199 | try {
200 | JSON.stringify(expectation[vk]);
201 | // eslint-disable-next-line no-unused-vars
202 | } catch (ex) {
203 | expectation[vk] = '';
204 | }
205 | }
206 |
207 | return expectation;
208 | });
209 | }
210 | }
211 |
212 | return payload;
213 | }
214 |
215 |
216 | module.exports = ParallelWorker;
217 |
--------------------------------------------------------------------------------
/lib/randomize.js:
--------------------------------------------------------------------------------
1 | module.exports = function randomOrder(items) {
2 | const seed = generateSeed();
3 | const copy = items.slice();
4 | copy.sort(function (a, b) {
5 | return jenkinsHash(seed + a) - jenkinsHash(seed + b);
6 | });
7 | return copy;
8 | };
9 |
10 | function generateSeed() {
11 | return String(Math.random()).slice(-5);
12 | }
13 |
14 | // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
15 | // used to get a different output when the key changes slightly.
16 | // We use your return to sort the children randomly in a consistent way when
17 | // used in conjunction with a seed
18 |
19 | function jenkinsHash(key) {
20 | let hash, i;
21 | for (hash = i = 0; i < key.length; ++i) {
22 | hash += key.charCodeAt(i);
23 | hash += hash << 10;
24 | hash ^= hash >> 6;
25 | }
26 | hash += hash << 3;
27 | hash ^= hash >> 11;
28 | hash += hash << 15;
29 | return hash;
30 | }
31 |
--------------------------------------------------------------------------------
/lib/reporters/console_reporter.js:
--------------------------------------------------------------------------------
1 | module.exports = exports = ConsoleReporter;
2 |
3 | /**
4 | * @classdesc A reporter that prints spec and suite results to the console.
5 | * A ConsoleReporter is installed by default.
6 | *
7 | * @constructor
8 | * @example
9 | * const {ConsoleReporter} = require('jasmine');
10 | * const reporter = new ConsoleReporter();
11 | */
12 | function ConsoleReporter() {
13 | let print = function() {},
14 | showColors = false,
15 | specCount,
16 | executableSpecCount,
17 | failureCount,
18 | failedSpecs = [],
19 | pendingSpecs = [],
20 | alwaysListPendingSpecs = true,
21 | ansi = {
22 | green: '\x1B[32m',
23 | red: '\x1B[31m',
24 | yellow: '\x1B[33m',
25 | none: '\x1B[0m'
26 | },
27 | failedSuites = [],
28 | stackFilter = stack => stack;
29 |
30 | /**
31 | * Configures the reporter.
32 | * @function
33 | * @name ConsoleReporter#setOptions
34 | * @param {ConsoleReporterOptions} options
35 | */
36 | this.setOptions = function(options) {
37 | if (options.print) {
38 | print = options.print;
39 | }
40 |
41 | /**
42 | * @interface ConsoleReporterOptions
43 | */
44 | /**
45 | * Whether to colorize the output
46 | * @name ConsoleReporterOptions#showColors
47 | * @type Boolean|undefined
48 | * @default false
49 | */
50 | showColors = options.showColors || false;
51 | if (options.stackFilter) {
52 | stackFilter = options.stackFilter;
53 | }
54 | /**
55 | * A function that takes a random seed and returns the command to reproduce
56 | * that seed. Use this to customize the output when using ConsoleReporter
57 | * in a different command line tool.
58 | * @name ConsoleReporterOptions#randomSeedReproductionCmd
59 | * @type Function|undefined
60 | */
61 | if (options.randomSeedReproductionCmd) {
62 | this.randomSeedReproductionCmd = options.randomSeedReproductionCmd;
63 | }
64 |
65 | /**
66 | * Whether to list pending specs even if there are failures.
67 | * @name ConsoleReporterOptions#alwaysListPendingSpecs
68 | * @type Boolean|undefined
69 | * @default true
70 | */
71 | if (options.alwaysListPendingSpecs !== undefined) {
72 | alwaysListPendingSpecs = options.alwaysListPendingSpecs;
73 | }
74 | };
75 |
76 | this.jasmineStarted = function(options) {
77 | specCount = 0;
78 | executableSpecCount = 0;
79 | failureCount = 0;
80 | if (options && options.order && options.order.random) {
81 | print('Randomized with seed ' + options.order.seed);
82 | printNewline();
83 | }
84 | print('Started');
85 | printNewline();
86 | };
87 |
88 | this.jasmineDone = function(result) {
89 | if (result.failedExpectations) {
90 | failureCount += result.failedExpectations.length;
91 | }
92 |
93 | printNewline();
94 | printNewline();
95 | if (failedSpecs.length > 0) {
96 | print('Failures:');
97 | }
98 | for (let i = 0; i < failedSpecs.length; i++) {
99 | specFailureDetails(failedSpecs[i], i + 1);
100 | }
101 |
102 | for(let i = 0; i < failedSuites.length; i++) {
103 | suiteFailureDetails(failedSuites[i]);
104 | }
105 |
106 | if (result && result.failedExpectations && result.failedExpectations.length > 0) {
107 | suiteFailureDetails({ fullName: 'top suite', ...result });
108 | }
109 |
110 | if (alwaysListPendingSpecs || result.overallStatus === 'passed') {
111 | if (pendingSpecs.length > 0) {
112 | print("Pending:");
113 | }
114 | for (let i = 0; i < pendingSpecs.length; i++) {
115 | pendingSpecDetails(pendingSpecs[i], i + 1);
116 | }
117 | }
118 |
119 | if(specCount > 0) {
120 | printNewline();
121 |
122 | if(executableSpecCount !== specCount) {
123 | print('Ran ' + executableSpecCount + ' of ' + specCount + plural(' spec', specCount));
124 | printNewline();
125 | }
126 | let specCounts = executableSpecCount + ' ' + plural('spec', executableSpecCount) + ', ' +
127 | failureCount + ' ' + plural('failure', failureCount);
128 |
129 | if (pendingSpecs.length) {
130 | specCounts += ', ' + pendingSpecs.length + ' pending ' + plural('spec', pendingSpecs.length);
131 | }
132 |
133 | print(specCounts);
134 | } else {
135 | print('No specs found');
136 | }
137 |
138 | printNewline();
139 |
140 | if (result.numWorkers) {
141 | print('Ran in parallel with ' + result.numWorkers + ' workers');
142 | printNewline();
143 | }
144 |
145 | const seconds = result ? result.totalTime / 1000 : 0;
146 | print('Finished in ' + seconds + ' ' + plural('second', seconds));
147 | printNewline();
148 |
149 | if (result && result.overallStatus === 'incomplete') {
150 | print('Incomplete: ' + result.incompleteReason);
151 | printNewline();
152 | }
153 |
154 | if (result && result.order && result.order.random) {
155 | print('Randomized with seed ' + result.order.seed);
156 | print(' (' + this.randomSeedReproductionCmd(result.order.seed) + ')');
157 | printNewline();
158 | }
159 | };
160 |
161 | this.randomSeedReproductionCmd = function(seed) {
162 | return 'jasmine --random=true --seed=' + seed;
163 | };
164 |
165 | this.specDone = function(result) {
166 | specCount++;
167 |
168 | if (result.status == 'pending') {
169 | pendingSpecs.push(result);
170 | executableSpecCount++;
171 | print(colored('yellow', '*'));
172 | return;
173 | }
174 |
175 | if (result.status == 'passed') {
176 | executableSpecCount++;
177 | print(colored('green', '.'));
178 | return;
179 | }
180 |
181 | if (result.status == 'failed') {
182 | failureCount++;
183 | failedSpecs.push(result);
184 | executableSpecCount++;
185 | print(colored('red', 'F'));
186 | }
187 | };
188 |
189 | this.suiteDone = function(result) {
190 | if (result.failedExpectations && result.failedExpectations.length > 0) {
191 | failureCount++;
192 | failedSuites.push(result);
193 | }
194 | };
195 |
196 | this.reporterCapabilities = {parallel: true};
197 |
198 | return this;
199 |
200 | function printNewline() {
201 | print('\n');
202 | }
203 |
204 | function colored(color, str) {
205 | return showColors ? (ansi[color] + str + ansi.none) : str;
206 | }
207 |
208 | function plural(str, count) {
209 | return count == 1 ? str : str + 's';
210 | }
211 |
212 | function repeat(thing, times) {
213 | const arr = [];
214 | for (let i = 0; i < times; i++) {
215 | arr.push(thing);
216 | }
217 | return arr;
218 | }
219 |
220 | function indent(str, spaces) {
221 | const lines = (str || '').split('\n');
222 | const newArr = [];
223 | for (let i = 0; i < lines.length; i++) {
224 | newArr.push(repeat(' ', spaces).join('') + lines[i]);
225 | }
226 | return newArr.join('\n');
227 | }
228 |
229 | function specFailureDetails(result, failedSpecNumber) {
230 | printNewline();
231 | print(failedSpecNumber + ') ');
232 | print(result.fullName);
233 | printFailedExpectations(result);
234 |
235 | if (result.debugLogs) {
236 | printNewline();
237 | print(indent('Debug logs:', 2));
238 | printNewline();
239 |
240 | for (const entry of result.debugLogs) {
241 | print(indent(`${entry.timestamp}ms: ${entry.message}`, 4));
242 | printNewline();
243 | }
244 | }
245 | }
246 |
247 | function suiteFailureDetails(result) {
248 | printNewline();
249 | print('Suite error: ' + result.fullName);
250 | printFailedExpectations(result);
251 | }
252 |
253 | function printFailedExpectations(result) {
254 | for (let i = 0; i < result.failedExpectations.length; i++) {
255 | const failedExpectation = result.failedExpectations[i];
256 | printNewline();
257 | print(indent('Message:', 2));
258 | printNewline();
259 | print(colored('red', indent(failedExpectation.message, 4)));
260 | printNewline();
261 | print(indent('Stack:', 2));
262 | printNewline();
263 | print(indent(stackFilter(failedExpectation.stack), 4));
264 | }
265 |
266 | // When failSpecWithNoExpectations = true and a spec fails because of no expectations found,
267 | // jasmine-core reports it as a failure with no message.
268 | //
269 | // Therefore we assume that when there are no failed or passed expectations,
270 | // the failure was because of our failSpecWithNoExpectations setting.
271 | //
272 | // Same logic is used by jasmine.HtmlReporter, see https://github.com/jasmine/jasmine/blob/main/src/html/HtmlReporter.js
273 | if (result.failedExpectations.length === 0 &&
274 | result.passedExpectations.length === 0) {
275 | printNewline();
276 | print(indent('Message:', 2));
277 | printNewline();
278 | print(colored('red', indent('Spec has no expectations', 4)));
279 | }
280 |
281 | printNewline();
282 | }
283 |
284 | function pendingSpecDetails(result, pendingSpecNumber) {
285 | printNewline();
286 | printNewline();
287 | print(pendingSpecNumber + ') ');
288 | print(result.fullName);
289 | printNewline();
290 | let pendingReason = "No reason given";
291 | if (result.pendingReason && result.pendingReason !== '') {
292 | pendingReason = result.pendingReason;
293 | }
294 | print(indent(colored('yellow', pendingReason), 2));
295 | printNewline();
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/lib/unWindows.js:
--------------------------------------------------------------------------------
1 | // glob interprets backslashes as escape sequences, not directory separators.
2 | // Convert them to slashes. Should only be called when running on Windows.
3 | module.exports = function unWindows(dir) {
4 | return dir.replace(/\\/g, '/');
5 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jasmine",
3 | "description": "CLI for Jasmine, a simple JavaScript testing framework for browsers and Node",
4 | "homepage": "http://jasmine.github.io/",
5 | "keywords": [
6 | "test",
7 | "testing",
8 | "jasmine",
9 | "tdd",
10 | "bdd"
11 | ],
12 | "license": "MIT",
13 | "version": "5.7.1",
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/jasmine/jasmine-npm"
17 | },
18 | "scripts": {
19 | "test": "node ./bin/jasmine.js",
20 | "posttest": "eslint \"bin/**/*.js\" \"lib/**/*.js\" \"spec/**/*.js\""
21 | },
22 | "exports": {
23 | ".": "./lib/jasmine.js",
24 | "./parallel": "./lib/parallel_runner.js"
25 | },
26 | "files": [
27 | "bin",
28 | "lib",
29 | "LICENSE",
30 | "package.json",
31 | "README.md"
32 | ],
33 | "dependencies": {
34 | "glob": "^10.2.2",
35 | "jasmine-core": "~5.7.0"
36 | },
37 | "bin": "./bin/jasmine.js",
38 | "main": "./lib/jasmine.js",
39 | "devDependencies": {
40 | "eslint": "^9.24.0",
41 | "rimraf": "^6.0.1",
42 | "shelljs": "^0.9.2"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/release_notes/2.1.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.1.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.1.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.1.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Stop using util.print as default print option.
12 | * Make the grunt task that runs the jasmine specs available by moving it to the `tasks` dir
13 | * Add cleaned up ConsoleReporter from jasmine-core to the npm.
14 |
15 | ## Pull Requests and Issues
16 |
17 | - Split paths with path.sep and parse arguments in a more compatible way.
18 | - Merges [#6](http://github.com/pivotal/jasmine-npm/issues/6) from @briandipalma
19 | - Allow the jasmine command to run only a specified set of files.
20 | - Fixes [#2](http://github.com/pivotal/jasmine-npm/issues/2)
21 | - Add ability to load jasmine config from a javascript object
22 | - Merges [#1](http://github.com/pivotal/jasmine-npm/issues/1)
23 |
24 | ------
25 |
26 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
27 |
--------------------------------------------------------------------------------
/release_notes/2.1.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.1.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This release improves the output of the ConsoleReporter.
6 |
7 | ## Changes
8 |
9 | * ConsoleReporter - Add red color to failure messages, add headings for message and stack, add failed spec number
10 | * Update travis badge
11 | * Add .idea/ to gitignore.
12 |
13 | ## Pull Requests and Issues
14 |
15 | - Improve error formatting
16 | - Fixes stack trace of Issue [#4](https://github.com/jasmine/jasmine-npm/issues/4), Merges [#13](https://github.com/jasmine/jasmine-npm/pull/13) from @wendorf
17 |
18 | ------
19 |
20 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
--------------------------------------------------------------------------------
/release_notes/2.2.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.2.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.2.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.2.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Show pending specs at the end of the suite
12 | * Don't package node_modules and release_notes directories
13 | * Uses more realistic folder structure for examples
14 |
15 | ------
16 |
17 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
18 |
--------------------------------------------------------------------------------
/release_notes/2.2.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.2.1 Release Notes
2 |
3 | ## Pull Requests & Issues
4 |
5 | * Use exit module instead of process.exit for Windows workaround
6 | - Fixes [#20](https://github.com/jasmine/jasmine-npm/issues/20)
7 |
8 | ------
9 |
10 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
11 |
--------------------------------------------------------------------------------
/release_notes/2.3.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.3.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.3.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.3.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Move mention of default command up near other commands in help
12 | * Document how to specify path to config file
13 | * Add docs for filter and stop spec execution
14 | * Allows the user to specify stop on execution behavior with a CLI param.
15 | * Gives the user the ability to stop execution on failure.
16 | * Adds version command to show the jasmine and jasmine-core versions.
17 | * Deprecates passing an onComplete to ConsoleReporter and as an option to configureDefaultReporter
18 | * Adds jasmine.onComplete that defines a callback for the exit code reporter to call
19 |
20 | ## Pull Requests & Issues
21 |
22 | * Use the exit module only in Windows with node version below v0.12.0. Use process.exit otherwise
23 | - Fixes [#40](https://github.com/jasmine/jasmine-npm/issues/40)
24 | - Fixes [#36](https://github.com/jasmine/jasmine-npm/issues/36)
25 |
26 | * Add -v and -h aliases to the CLI.
27 | - Fixes [#19](https://github.com/jasmine/jasmine-npm/issues/19)
28 |
29 | * Add filter by spec name
30 | - Merge [#35](https://github.com/jasmine/jasmine-npm/issues/35) from @just-boris
31 |
32 | * Update package.json license
33 | - Merge [#34](https://github.com/jasmine/jasmine-npm/issues/34) from @mikaturunen
34 |
35 | * Don't output ANSI escape sequences if stdout is not a terminal
36 | - Merge [#33](https://github.com/jasmine/jasmine-npm/issues/33) from @sgravrock
37 |
38 | * jasmine command only adds a default reporter if no other reporter is added.
39 | - Fixes [#28](https://github.com/jasmine/jasmine-npm/issues/28)
40 |
41 | * Load helper files even if files are specified on the command line
42 | - Fixes [#21](https://github.com/jasmine/jasmine-npm/issues/21)
43 | - Fixes [#28](https://github.com/jasmine/jasmine-npm/issues/28)
44 |
45 | * Allow custom stackFilter function
46 | - Merge [#27](https://github.com/jasmine/jasmine-npm/issues/27) from @hankduan
47 |
48 | ------
49 |
50 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
51 |
--------------------------------------------------------------------------------
/release_notes/2.3.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.3.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This patch release fixes a breaking change made in 2.3.0 related to default exiting of the process.
6 |
7 | ## Changes
8 |
9 |
10 | ## Pull Requests & Issues
11 |
12 | * Only use the default exiting if the default reporter is used.
13 | - Fixes [#43](https://github.com/jasmine/jasmine-npm/issues/43)
14 |
15 | ------
16 |
17 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
18 |
--------------------------------------------------------------------------------
/release_notes/2.3.2.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.3.2 Release Notes
2 |
3 | ## Pull Requests & Issues
4 |
5 | * Use JASMINE_CONFIG_PATH env in grunt task
6 | - Merges [#50](https://github.com/jasmine/jasmine-npm/issues/50) from @nesQuick
7 |
8 |
9 | * Add link to docs for jasmine.json
10 | - Fixes [#49](https://github.com/jasmine/jasmine-npm/issues/49)
11 |
12 | * Merge pull request #48 from LJWall/count-disabled
13 |
14 | Report "Ran X of Y specs" if some are disabled.
15 | - Merges [#48](https://github.com/jasmine/jasmine-npm/issues/48) from @ljwall
16 |
17 |
18 | ------
19 |
20 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
21 |
--------------------------------------------------------------------------------
/release_notes/2.4.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.4.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.4.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.4.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Enable the --random and --seed cli flags
12 | - Merges #55 from @marcioj
13 |
14 | ------
15 |
16 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
17 |
--------------------------------------------------------------------------------
/release_notes/2.4.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.4.1 Release Notes
2 |
3 | ## Pull Requests & Issues
4 |
5 | * Remove comments and generally fix example json file
6 | - Fixes [#60](https://github.com/jasmine/jasmine-npm/issues/60)
7 |
8 | ------
9 |
10 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
11 |
--------------------------------------------------------------------------------
/release_notes/2.5.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.5.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.5.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.5.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Report errors in global afterAlls
12 | * Retrieve the jasmine-core version through the interface
13 | * Run CI against multiple node versions
14 |
15 | ## Pull Requests & Issues
16 |
17 | * Added travis ci support for node 6
18 | - Merges [#79](https://github.com/jasmine/jasmine-npm/issues/79) from @amilajack
19 |
20 | * Added better install method to readme
21 | - Merges [#80](https://github.com/jasmine/jasmine-npm/issues/80) from @amilajack
22 |
23 | * Use jasmine-core's fallback reporter
24 | - Merges [#67](https://github.com/jasmine/jasmine-npm/issues/67) from @mauricioborges
25 | - Fixes [#66](https://github.com/jasmine/jasmine-npm/issues/66)
26 |
27 | * Allow to run without jasmine.json
28 | - Merges [#74](https://github.com/jasmine/jasmine-npm/issues/74) from @m7r
29 |
30 | * Default spec_dir if not provided
31 | - Merges [#70](https://github.com/jasmine/jasmine-npm/issues/70) from @dflynn15
32 | - Fixes [#69](https://github.com/jasmine/jasmine-npm/issues/69)
33 |
34 | * Proper handling of randomization args in config and command line
35 | - Merges [#65](https://github.com/jasmine/jasmine-npm/issues/65) from @marcioj
36 |
37 | * Resolve examples folder dynamically.
38 | - Merges [#64](https://github.com/jasmine/jasmine-npm/issues/64) from @danielsiwiec
39 | - Fixes [#63](https://github.com/jasmine/jasmine-npm/issues/63)
40 |
41 | ------
42 |
43 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
44 |
--------------------------------------------------------------------------------
/release_notes/2.5.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.5.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.5.1. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.5.1.md)
7 | for more information.
8 |
9 | ## Pull Requests & Issues
10 |
11 | * Update glob dependency
12 | - Fixes [#78](https://github.com/jasmine/jasmine-npm/issues/78)
13 | - Fixes [jasmine/jasmine#1148](https://github.com/jasmine/jasmine/issues/1148)
14 |
15 | * Only use the default exiting if the default reporter is used
16 | - Merges [#89](https://github.com/jasmine/jasmine-npm/issues/89) from @flore77
17 |
18 | * Update link to documentation in README.md
19 | - Merges [#87](https://github.com/jasmine/jasmine-npm/issues/87) from @gkalpak
20 |
21 |
22 | ------
23 |
24 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
25 |
--------------------------------------------------------------------------------
/release_notes/2.5.2.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.5.2 Release Notes
2 |
3 | ## Changes
4 |
5 | * Register ConsoleReporter immediately upon creation so it can be easily cleared
6 | - Fixes [#88](https://github.com/jasmine/jasmine-npm/issues/88)
7 |
8 |
9 | * Use default reporter in own tests
10 | - Merges [#88](https://github.com/jasmine/jasmine-npm/issues/88) from bcaudan
11 |
12 |
13 | ------
14 |
15 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
16 |
--------------------------------------------------------------------------------
/release_notes/2.5.3.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.5.3 Release Notes
2 |
3 | ## Pull Requests & Issues
4 |
5 | * A bunch of fixes to make the default reporter work better and accept the right configurations
6 | - Merge #98 from @cnishina
7 | - Fixes #95
8 | - Merges #100 from @tomv564
9 |
10 | * adding license file
11 | - Merges #101 from @julka
12 |
13 | * default console reporter hangs sometimes
14 | - Merge #84 from @ybian
15 | - Fixes #83
16 |
17 | * Enable regex filter by omitting automatic escaping
18 | - Merge #76 from @aaalsaleh
19 |
20 | * Allow adding a helper with a cli argument
21 | - Merges #75 from @m7r
22 |
23 |
24 | ------
25 |
26 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
27 |
--------------------------------------------------------------------------------
/release_notes/2.6.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.6.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.6.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.6.0.md)
7 | for more information.
8 |
9 | ## Pull Requests & Issues
10 |
11 | * Expose `closeReporters` methos in the wrapper
12 | - Merges #114 from @lonelyelk
13 | - Fixes jasmine/jasmine#1228
14 |
15 | * Try to detect a `exit` being called inside the suite
16 | - Fixes jasmine/jasmine#1273
17 |
18 | * Option to specify path to your jasmine.json
19 | - Merges #107 from @bcaudan
20 | - Fixes #85
21 |
22 | * Reject unknown CLI options
23 | - Merges #108 from @bcaudan
24 | - Fixes #53
25 |
26 | ------
27 |
28 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
29 |
--------------------------------------------------------------------------------
/release_notes/2.7.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.7.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.7.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.7.0.md)
7 | for more information.
8 |
9 | ## Pull Requests & Issues
10 |
11 | * Report the random seed at the beginning and end of execution to allow users to reproduce seed-dependent Jasmine crashes.
12 | - Merges [#120](https://github.com/jasmine/jasmine-npm/issues/120) from @sgravrock
13 |
14 | * Fix linebreak between jasmine config examples.
15 | - Merges [#122](https://github.com/jasmine/jasmine-npm/issues/122) from @donmccurdy
16 |
17 |
18 | ------
19 |
20 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
21 |
--------------------------------------------------------------------------------
/release_notes/2.8.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.8.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.8.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.8.0.md)
7 | for more information.
8 |
9 |
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/2.9.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 2.9.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 2.9.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/2.9.0.md)
7 | for more information.
8 |
9 |
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/2.99.md:
--------------------------------------------------------------------------------
1 | # Jasmine Npm 2.99 Release Notes
2 |
3 | ## Summary
4 |
5 | This release is part of the upgrade path to Jasmine 3.0. Please see the [release notes for Jasmine-Core](https://github.com/jasmine/jasmine/blob/master/release_notes/2.99.md)
6 |
7 | ## Changes
8 |
9 | * Report deprecation warnings in CI output
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/3.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.0 Release Notes
2 |
3 | ## Summary
4 |
5 | Jasmine 3.0 is a major release of Jasmine, and as such includes some breaking changes in addition to various new features.
6 |
7 | Please see the [release notes for Jasmine-Core](https://github.com/jasmine/jasmine/blob/master/release_notes/3.0.md)
8 |
9 | There is also a 2.99 release of Jasmine that will present deprecation warnings for suites that will encounter different behavior in 3.0.
10 |
11 | ## Changes
12 |
13 | * Support stopping jasmine execution on first spec failure via config object or with `--fail-fast` command line arg
14 | - Fixes [#16](https://github.com/jasmine/jasmine-npm/issues/16)
15 |
16 | * Add ability to pass `--reporter` on the command line
17 | - Fixes [jasmine/jasmine#1027](https://github.com/jasmine/jasmine/issues/1027)
18 |
19 | * Print full details for suite failures
20 |
21 | * Report how to re-run Jasmine with the current seed
22 |
23 | * Run specs in random order by default
24 |
25 | * Treat suites with focused specs as failures
26 |
27 | * Removed deprecated completion callback from console reporter
28 |
29 |
30 | ------
31 |
32 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
33 |
--------------------------------------------------------------------------------
/release_notes/3.1.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.1.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/3.1.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Tell Jasmine-core not to handle load errors itself
12 | - Fixes [jasmine/jasmine#1519](https://github.com/jasmine/jasmine/issues/1519)
13 |
14 | * better error reporting when an invalid --reporter is specified
15 |
16 | ------
17 |
18 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
19 |
--------------------------------------------------------------------------------
/release_notes/3.10.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.10 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 3.10.0. See the
4 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/main/release_notes/3.10.0.md)
5 | for more information.
6 |
7 | ## New features and bugfixes
8 |
9 | * Support for executing the suite multiple times
10 | * See the jasmine-core release notes for details
11 |
12 | * Display the top suite name as "top suite", not "undefined" when reporting
13 | suite-level failures
14 |
15 | * Fixed reporting of load-time errors from modules imported by specs
16 |
17 | * Made the promise returned from `Jasmine#execute` usable
18 | * Added an exitOnCompletion property to directly control whether Jasmine
19 | should make the Node process exit. Previously this could only be done by
20 | calling `Jasmine#onComplete`.
21 | * The promise returned from `Jasmine#execute` is resolved to the overall
22 | status.
23 |
24 | * Improved interface for programmatically adding files
25 | * Added Jasmine#addHelperFile
26 | * Added more clearly named synonyms for Jasmine#addSpecFiles and
27 | Jasmine#addHelperFiles, and marked the old ones deprecated
28 |
29 |
30 | ## Documentation improvements
31 |
32 | * Added jsdoc for `Jasmine#env`
33 |
34 |
35 | ## Internal updates
36 |
37 | * Pass stopOnSpecFailure and stopSpecOnExpectationFailure options to core,
38 | not the deprecated failFast and oneFailurePerSpec options
39 |
40 | * Replaced var with const and let
41 |
42 | * Test suite improvements
43 |
44 | ## Supported environments
45 |
46 | The jasmine NPM package has been tested on Node 12, 14, and 16. See the
47 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/3.10.0.md)
48 | for supported browsers.
49 |
50 | ------
51 |
52 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
53 |
--------------------------------------------------------------------------------
/release_notes/3.2.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.2 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.2.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/3.2.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Unknown command line options produce exit code 1
12 | - Merges [#138](https://github.com/jasmine/jasmine-npm/issues/138) from @enelson
13 | - Fixes [#137](https://github.com/jasmine/jasmine-npm/issues/137)
14 |
15 |
16 | * Add option "require(s)" to command line and config file
17 | - Merges [#136](https://github.com/jasmine/jasmine-npm/issues/136) from @liuxh0
18 | - Fixes [#135](https://github.com/jasmine/jasmine-npm/issues/135)
19 |
20 |
21 | * Add --color option
22 | - Merges [#132](https://github.com/jasmine/jasmine-npm/issues/132) from @susisu
23 |
24 |
25 | * fix --filter in README
26 | - Merges [#131](https://github.com/jasmine/jasmine-npm/issues/131) from @cancerberoSgx
27 |
28 |
29 | ------
30 |
31 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
32 |
--------------------------------------------------------------------------------
/release_notes/3.3.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.3 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.3.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/3.3.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Wait until streams are completed before exiting to prevent output cropping when jasmine is called form another process
12 | - Merges [#141](https://github.com/jasmine/jasmine-npm/issues/141) from @jkytomak
13 |
14 |
15 | * Allow excluding spec files and helper files
16 | - Merges [#140](https://github.com/jasmine/jasmine-npm/issues/140) from @liuxh0
17 | - Fixes [#128](https://github.com/jasmine/jasmine-npm/issues/128)
18 |
19 |
20 | ------
21 |
22 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
23 |
--------------------------------------------------------------------------------
/release_notes/3.3.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.3.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This is a bug fix release to clean up the deprecation warning introduced in 3.3.0
6 |
7 | ## Changes
8 |
9 | * Add `null` encoding when writing to streams on close
10 | - Fixes [jasmine/jasmine#1622](https://github.com/jasmine/jasmine/issues/1622)
11 |
12 | * Changes to avoid config deprecation warnings (from jasmine-core).
13 | - Merges [#147](https://github.com/jasmine/jasmine-npm/issues/147) from @claudiosdc
14 | - Fixes [#145](https://github.com/jasmine/jasmine-npm/issues/145)
15 |
16 | ------
17 |
18 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
19 |
--------------------------------------------------------------------------------
/release_notes/3.4.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.4 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.4.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/3.4.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Use `removeListener` instead of `off` since it always exists
12 |
13 | * moved exit listener add and removal to completion reporter
14 | - Merges [#149](https://github.com/jasmine/jasmine-npm/issues/149) from @battk
15 | - Fixes [#134](https://github.com/jasmine/jasmine-npm/issues/134)
16 | - Fixes [#125](https://github.com/jasmine/jasmine-npm/issues/125)
17 |
18 | * Update README.md
19 | - Merges [#146](https://github.com/jasmine/jasmine-npm/issues/146) from @strama4
20 |
21 | ------
22 |
23 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
24 |
--------------------------------------------------------------------------------
/release_notes/3.5.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.5 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.5.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/master/release_notes/3.5.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Use the total time from Jasmine-Core instead of calculating ourself
12 |
13 |
14 | ------
15 |
16 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
17 |
--------------------------------------------------------------------------------
/release_notes/3.6.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.6 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.6.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/main/release_notes/3.6.0.md)
7 | for more information.
8 |
9 | ## Changes
10 |
11 | * Removed unnecessary check for passedExpectations truthiness
12 |
13 | * Support 'failSpecWithNoExpectations' config option and include a message in the default ConsoleReporter when a spec contains no expectations
14 | * Merges [#157](https://github.com/jasmine/jasmine-npm/pull/157) from @coyoteecd
15 | * Fixes [#156](https://github.com/jasmine/jasmine-npm/issues/156)
16 |
17 | * Don't parse argv after --
18 | * Merges [#155](https://github.com/jasmine/jasmine-npm/pull/155) from @tharvik
19 |
20 | * Added support for running specs in parallel
21 | * Merges [#153](https://github.com/jasmine/jasmine-npm/pull/153) from @wood1986
22 |
23 | ------
24 |
25 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
26 |
--------------------------------------------------------------------------------
/release_notes/3.6.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.6.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This release fixes a bug in the multi-threading logic to ensure spec files are only loaded once
6 |
7 | ## Changes
8 |
9 |
10 | * Only load spec files once
11 | * Fixes #161
12 |
13 |
14 | ------
15 |
16 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
17 |
--------------------------------------------------------------------------------
/release_notes/3.6.2.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.6.2 Release Notes
2 |
3 | # Summary
4 |
5 | This release fixes an issue with load order of helper files introduced by switching globbing libraries
6 |
7 | # Changes
8 |
9 |
10 | Added support for ES modules
11 |
12 | * Fixes [#150](https://github.com/jasmine/jasmine-npm/issues/150).
13 | * Specs and helpers with names ending in .mjs are loaded as ES modules
14 | (`import("foo.mjs")`).
15 | * All other specs and helpers are loaded as CommonJS modules, as before
16 | (`require("foo.js")`).
17 | * If using ES modules with Node 10 or 11, run
18 | `node --experimental-modules /path/to/jasmine` instead of `jasmine`.
19 |
20 |
21 | Switch back to just plain `glob` for smaller dependency list
22 |
23 | * Fixes [#162](https://github.com/jasmine/jasmine-npm/issues/162)
24 |
25 | Remove code related to multiple workers as it never worked in the first place
26 |
27 | * See [#153](https://github.com/jasmine/jasmine-npm/issues/153)
28 | * Fixes [#163](https://github.com/jasmine/jasmine-npm/issues/163)
29 | * Fixes [#165](https://github.com/jasmine/jasmine-npm/issues/165)
30 | * See also discussion in [#162](https://github.com/jasmine/jasmine-npm/issues/162)
31 |
32 |
--------------------------------------------------------------------------------
/release_notes/3.6.3.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.6.3 Release Notes
2 |
3 | ## Summary
4 |
5 | This release fixes several bugs related to module loading.
6 |
7 | ## Changes
8 |
9 | Fixed ES module loading on Windows
10 |
11 | * Fixes [#169](https://github.com/jasmine/jasmine-npm/issues/169)
12 |
13 | Include the filename in the error when an ES module has syntax errors
14 |
15 | * Fixes [#168](https://github.com/jasmine/jasmine-npm/issues/168)
16 |
17 |
18 | Exit nonzero when a spec fails to load
19 |
20 | * Fixes [#167](https://github.com/jasmine/jasmine-npm/issues/167)
21 |
22 | Clarify which Node versions are supported
23 | * 10.x, 12.x, and 14.x are supported.
24 | * Odd-numbered major versions are very likely to work, but they aren't supported or tested against.
25 | * See the `engines` field in `package.json` in this and future releases for the current list.
26 |
--------------------------------------------------------------------------------
/release_notes/3.6.4.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.6.4 Release Notes
2 |
3 | ## Summary
4 |
5 | This is a bugfix release that removes the `engines` specification.
6 |
7 | ## Changes
8 |
9 | * Removed `engines` field from package.json
10 |
11 | The engines field was added in 3.6.3 in an attempt to better document the set
12 | of Node versions that Jasmine supports, but it's caused more problems than it
13 | solves. In particular, Yarn users receive an error rather than a warning when
14 | using a version of Node that works but isn't supported.
15 |
16 | See for a list of supported Node
17 | versions.
18 |
--------------------------------------------------------------------------------
/release_notes/3.7.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.7 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.7.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/main/release_notes/3.7.0.md)
7 | for more information.
8 |
9 |
--------------------------------------------------------------------------------
/release_notes/3.8.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.8 Release Notes
2 |
3 | ## Summary
4 |
5 | This release updates the jasmine-core dependency to 3.8.0. See the
6 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/main/release_notes/3.8.0.md)
7 | for more information.
8 |
9 | # New features and bug fixes
10 |
11 | * Opt-in support for ES modules with .js extension and package type `module`
12 | * All files are loaded using `import` if `"jsLoader": "import"` is set in
13 | the config file.
14 | * Only supported on Node >= 12.17.0. Older versions have missing or broken
15 | support for importing .js files.
16 | * Fixes [#170](https://github.com/jasmine/jasmine-npm/issues/170)
17 |
18 | * Allow the random seed reproduction command to be overridden
19 | * Needed by jasmine-browser-runner, which uses the ConsoleReporter but needs
20 | to tell the user to run a different command.
21 |
22 |
23 | # Documentation updates
24 |
25 | * Created an initial set of [API reference documentation](https://jasmine.github.io/api/npm/3.8/index)
26 |
27 |
28 | # Internal notes
29 |
30 | * Specify files to include in the NPM package rather than files to exclude
31 |
32 | * CI matrix updates
33 | * Added Node 16.
34 | * Added Node 12.0, 12.16, and 12.17 to ensure coverage of versions that do
35 | and don't have good support for importing .js files.
36 | * Removed Windows. We'll manually run the tests on Windows before each
37 | release, but we no longer have reliable access to a free Windows CI
38 | service.
39 |
40 | * Migrated from Travis to Circle CI
41 |
42 |
43 | ## Supported environments
44 |
45 | The jasmine NPM package has been tested on Node 12, 14, 16, and 18. See the
46 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/3.8.0.md)
47 | for supported browsers.
48 |
49 | ------
50 |
51 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
52 |
--------------------------------------------------------------------------------
/release_notes/3.9.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM Release Notes
2 |
3 | This release updates the jasmine-core dependency to 3.9.0. See the
4 | [jasmine-core release notes](https://github.com/pivotal/jasmine/blob/main/release_notes/3.9.0.md)
5 | for more information.
6 |
7 | ## New features and bug fixes
8 |
9 | * Allow arbitrary env configuration to be specified via the `env` config field
10 |
11 | This allows us to automatically support new env config properties in the
12 | future without any code changes.
13 |
14 | * Default to including .mjs as well as .js in newly generated config files
15 | * Fixes #176
16 |
17 | # Documentation improvements
18 |
19 | * Added jsdoc for Jasmine.prototype.configureDefaultReporter
20 | * Fixed copy-paste error in docs
21 | * Merges [#183](https://github.com/jasmine/jasmine-npm/pull/183) from @UziTech
22 |
23 | ## Internal notes
24 |
25 | * Removed vestigal code for old `timer` reporter option
26 |
27 |
28 | ------
29 |
30 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
31 |
--------------------------------------------------------------------------------
/release_notes/3.99.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 3.99.0 Release Notes
2 |
3 | This release adds deprecation warnings for breaking changes that will be
4 | introduced in Jasmine 4.0. Please see the
5 | [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
6 | for more information.
7 |
8 | ------
9 |
10 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
11 |
--------------------------------------------------------------------------------
/release_notes/4.0.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.0.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This is a major release. In addition to new features and bug fixes it contains
6 | a variety of breaking changes that are intended to improve ES module support,
7 | improve awkward or outdated interfaces, and make Jasmine easier to maintain
8 | and contribute to. If you're upgrading from Jasmine 3.x, we recommend installing
9 | 3.99 and fixing any deprecation warnings that it emits before updating to 4.0.
10 | See the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0)
11 | for more information. Be sure to read the release notes for `jasmine-core` 4.0.0
12 | as well.
13 |
14 | ## Highlights
15 |
16 | * The `jasmine-core` dependency has been updated to 4.0.0
17 | * ES module support is enabled by default.
18 | * Node 10 and 12.0-12.16 are no longer supported.
19 |
20 | ## Breaking changes
21 |
22 | * Node versions older than 12.17 are no longer supported because they have
23 | insufficient support for interop between ES modules and CommonJS modules.
24 |
25 | * Beginning with this release, everything not documented in the
26 | [API reference](https://jasmine.github.io/api/npm/4.0/Jasmine) is considered
27 | a private API.
28 |
29 | * ES module support is enabled by default, but can still be disabled by
30 | adding `jsLoader: "require"` to the configuration. `jsLoader: "import"` is
31 | now a no-op.
32 |
33 | This change breaks loading of files with extensions that aren't supported by
34 | dynamic `import()`, such as `.jsx`, although that has been subsequently fixed
35 | in 4.0.1. If you have specs or source files with such extensions, please
36 | update to at least 4.0.1. Alternately you can either rename the files to
37 | `.js` or add `jsLoader: "require"` to your Jasmine config file.
38 |
39 | * Config files can be ES modules. This is a breaking change because it requires
40 | `Jasmine#loadConfigFile` to be async.
41 |
42 | * The `--fail-fast` CLI flag now causes Jasmine to stop spec execution on the
43 | first expectation failure as well as stopping suite execution on the first
44 | spec failure.
45 |
46 | * The ambiguously named `--stop-on-failure` CLI flag is no longer supported.
47 |
48 | * Failure to load or instantiate a reporter is a fatal error, not just a warning.
49 |
50 | * Relative reporter paths are resolved based on the working directory rather
51 | than the location of the module inside Jasmine that calls `require()`.
52 |
53 | * The `jasmine` command now uses distinct exit codes for various types of non-success:
54 | * 1 for anything unexpected, i.e. Jasmine didn't run to completion
55 | * 2 for incomplete (focused specs/suites but no failures)
56 | * 3 for failed (spec/suite failures)
57 | * Other nonzero exit codes may be used for other purposes. Code that checks
58 | the exit code of the `jasmine` command should not treat any value other than
59 | 0 as success.
60 | * Fixes [#154](https://github.com/jasmine/jasmine-npm/issues/154).
61 |
62 | * `Jasmine#onComplete` is no longer supported. To run code after execution
63 | finishes, set the Jasmine instance's `exitOnCompletion` to false and use the
64 | promise returned by `Jasmine#execute`. See the
65 | [API reference for `execute`](https://jasmine.github.io/api/npm/4.0/Jasmine.html#execute)
66 | for more information.
67 |
68 | ## New features and bugfixes
69 |
70 | * Files listed in the `requires` config property can be ES modules
71 |
72 | * Reporters specified with `--reporter=` can be ES modules.
73 |
74 | * Allow use without creating globals.
75 | * See .
76 | * Fixes [jasmine/jasmine#1235](https://github.com/jasmine/jasmine/issues/1235).
77 |
78 | * Autodiscover spec/support/jasmine.js as well as spec/support/jasmine.json.
79 |
80 | * Moved `stopSpecOnExpectationFailure` and `random` to `env` in the sample
81 | config generated by `jasmine init`.
82 |
83 | * Top suite failures are included in the failure count displayed by the default
84 | `ConsoleReporter`.
85 |
86 | * Added support for the debug logging feature introduced in `jasmine-core` 4.0.0.
87 |
88 | * Fixed handling of module paths containing `..` on OS X.
89 |
90 | ## Internal improvements
91 |
92 | * Use the promise returned from `Env#execute` to determine when suite execution
93 | is finished and obtain the overall result.
94 |
95 | * Removed unnecessary code to filter Jasmine's frames from stack traces. The same
96 | filtering has been done in jasmine-core since 3.0.
97 |
98 | * Inlined loadConfig.js back into command.js to resolve naming conflicts.
99 |
100 | ## Supported environments
101 |
102 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, and 16.
103 |
104 |
105 | ------
106 |
107 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
108 |
--------------------------------------------------------------------------------
/release_notes/4.0.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.0.1 Release Notes
2 |
3 | ## Summary
4 |
5 | This release fixes loading of files with nonstandard extensions (e.g. .jsx,
6 | .coffee) in the default configuration by falling back to `require()` when
7 | `import()` fails because of an unsupported file extension. See
8 | [#188](https://github.com/jasmine/jasmine-npm/issues/188).
9 |
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/4.0.2.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.0.2 Release Notes
2 |
3 | This release fixes two bugs related to reporter loading.
4 |
5 | * Fixed loading of reporters in NPM packages (i.e. not a file path) in the
6 | default configuration
7 | * Fixes [#189](https://github.com/jasmine/jasmine-npm/issues/189)
8 |
9 | * The `jsLoader` configuration setting is followed when loading reporters
10 | * Merges [#190](https://github.com/jasmine/jasmine-npm/pull/190) from @ffortier
11 |
12 | ------
13 |
14 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
15 |
--------------------------------------------------------------------------------
/release_notes/4.1.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.1.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.1.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.1.0.md)
5 | for more information.
6 |
7 | ------
8 |
9 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
10 |
--------------------------------------------------------------------------------
/release_notes/4.2.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.2.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.2.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.2.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, 16, and 18.
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/4.2.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.2.1 Release Notes
2 |
3 | ## Bug Fixes
4 |
5 | * Fixed the `--helper` option
6 | * Merges [#198](https://github.com/jasmine/jasmine-npm/pull/198) from @lucaswerkmeister
7 | * Fixes [#197](https://github.com/jasmine/jasmine-npm/issues/197)
8 |
9 | ## Supported environments
10 |
11 | The jasmine package has been tested on Node 12.17-12.22, 14, 16, and 18.
12 |
13 | ------
14 |
15 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
16 |
--------------------------------------------------------------------------------
/release_notes/4.3.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.3.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.3.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.3.0.md)
5 | for more information.
6 |
7 | # New features
8 |
9 | * Added a config option to disable listing pending specs when there are failures
10 | * This can make failure output easier to read when there are also a number of
11 | pending specs. To use this feature, add `alwaysListPendingSpecs: false` to
12 | the config file or call `.alwaysListPendingSpecs(false)` on the `Jasmine`
13 | instance.
14 |
15 |
16 | ## Documentation updates
17 |
18 | * Added a contributing guide
19 | * Copied CODE_OF_CONDUCT from core repo
20 |
21 | ## Internal improvements
22 |
23 | * Converted `Jasmine` and `Loader` to ES6 classes
24 |
25 | ## Supported environments
26 |
27 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, 16, and 18.
28 |
29 |
30 |
31 | ------
32 |
33 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
34 |
--------------------------------------------------------------------------------
/release_notes/4.4.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.4.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.4.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.4.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, 16, and 18.
10 |
11 | ------
12 |
13 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
14 |
--------------------------------------------------------------------------------
/release_notes/4.5.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.5.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.5.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.5.0.md)
5 | for more information.
6 |
7 |
8 | ## New Features
9 |
10 | * Warn when backslashes are used in paths/globs on Windows
11 | * Backslashes behave inconsistently between OSes in the version of glob
12 | that Jasmine currently uses. The next major version of glob will treat
13 | them as escape sequences rather than path separators on all OSes.
14 |
15 | * Allow instantiated reporters to be provided in the configuration
16 | * This supports more complex scenarios than the --reporter= CLI flag
17 | (multiple reporters, reporters that need configuration, reporters
18 | that aren't default exports, etc) without requiring a switch to programmatic
19 | usage.
20 |
21 | ## Documentation Improvements
22 |
23 | * Fixed default value of Configuration#alwaysListPendingSpecs
24 |
25 | ## Supported environments
26 |
27 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, 16, and 18.
28 |
29 |
30 | ------
31 |
32 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
33 |
--------------------------------------------------------------------------------
/release_notes/4.6.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 4.6.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 4.6.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/4.6.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | The jasmine NPM package has been tested on Node 12.17-12.22, 14, 16, and 18.
10 |
11 |
12 | ------
13 |
14 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
15 |
--------------------------------------------------------------------------------
/release_notes/5.0.0-alpha.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.0.0-alpha.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This release adds support for parallel execution and updates file glob handling.
6 | See the
7 | [parallel documentation](https://jasmine.github.io/tutorials/running_specs_in_parallel)
8 | for more information about that feature. Please also read the
9 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/5.0/release_notes/5.0.0-alpha.0.md)
10 | for information about changes in that package, including breaking changes.
11 |
12 | ## Breaking changes
13 |
14 | * Node versions older than 16.14 are no longer supported.
15 | * Backslashes in the `specFiles` and `helperFiles` configuration properties are
16 | interpreted as the start of escape sequences on all OSes. Previous versions
17 | of Jasmine used a version of the `glob` package that treated them as directory
18 | separators on Windows and the start of escape sequences on other OSes.
19 |
20 | ## New features
21 |
22 | * Support for parallel execution
23 |
24 | ## Supported environments
25 |
26 | The jasmine package has been tested on 16.14+, and 18.
27 |
28 | ------
29 |
30 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
31 |
--------------------------------------------------------------------------------
/release_notes/5.0.0-alpha.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.0.0-alpha.1 Release Notes
2 |
3 | ## Breaking changes
4 |
5 | * Unknown args of the form `--foo=bar` are treated as errors, rather than a request
6 | to set the env variable `--foo` to `bar`.
7 | * `--parallel=1` is an error.
8 |
9 | ## New features and bug fixes
10 |
11 | * Reporter errors are handled in parallel mode
12 | * The underlying exception is included in in ESM import exceptions
13 |
14 | ## Internal improvements
15 |
16 | * Updated to Glob 9
17 | * Updated dev dependencies
18 |
19 | ## Supported environments
20 |
21 | The jasmine package has been tested on 16.14+, and 18.
22 |
23 | ------
24 |
25 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
26 |
--------------------------------------------------------------------------------
/release_notes/5.0.0-beta.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.0.0-beta.0 Release Notes
2 |
3 | This release adds the final pieces of support for parallel execution. There may
4 | be other changes before the final 5.0 release, but parallel support is now
5 | considered feature-complete. Please
6 | [open an issue](https://github.com/jasmine/jasmine-npm/issues/new) if you think
7 | anything's missing.
8 |
9 | ## Breaking changes
10 |
11 | * Dropped support for Node 16
12 |
13 | ## New Features
14 |
15 | * Added support for Node 20
16 | * Parallel: Report unhandled exceptions/rejections that occur between spec files
17 | * Parallel: `--parallel=auto` runs with an inferred number of workers
18 |
19 | The number of workers will be one less than the number of CPUs reported by
20 | Node. This is a reasonable default in most situations but may work poorly
21 | inside containers, since the number of CPUs reported by Node is based on the
22 | host machine's hardware and not the resources actually available in the
23 | container. Inside a container you are likely to get better results by
24 | explicitly specifying a number of workers instead, e.g. `--parallel=4`.
25 |
26 | * Parallel: Support use without globals
27 |
28 | To use this feature, include `globals: false` in the options passed to the
29 | [ParallelRunner constructor](https://jasmine.github.io/api/npm/5.0.0-beta.0/ParallelRunner.html).
30 |
31 | ## Internal Improvements
32 |
33 | * Updated to Glob 10
34 |
35 | ------
36 |
37 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
38 |
--------------------------------------------------------------------------------
/release_notes/5.0.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine NPM 5.0.0 Release Notes
2 |
3 | ## Summary
4 |
5 | This is a major release that includes breaking changes. It primarily adds
6 | support for parallel execution. Most users should be able to upgrade without
7 | changes, but please read the list of breaking changes below and see the
8 | [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0)
9 | for more information. Be sure to read the release notes for `jasmine-core`
10 | 5.0.0 as well.
11 |
12 | ## Breaking changes
13 |
14 | * Dropped support for Node 12, 14, and 16
15 | * Unknown CLI args of the form --foo=bar are treated as errors, not env vars
16 | * Backslashes in file globs (e.g. `spec_files`) are treated as escape characters
17 | on all platforms. Previously they were treated as directory separators on
18 | Windows and escape characters elsewhere.
19 |
20 | ## New features
21 |
22 | * Support for parallel execution
23 | See the [parallel guide](https://jasmine.github.io/tutorials/running_specs_in_parallel)
24 | for more information.
25 | * Support for Node 20
26 | * Include the underlying exception in ESM import exceptions
27 |
28 | ## Bug fixes
29 |
30 | * Fixed handling of special Glob syntax in project base dirs
31 | * Fixes [#206](https://github.com/jasmine/jasmine-npm/issues/206)
32 |
33 | ## Internal improvements
34 |
35 | * Updated dev dependencies
36 |
37 | ## Supported environments
38 |
39 | This package has been tested on Node 18 and 20.
40 |
41 | ------
42 |
43 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
44 |
--------------------------------------------------------------------------------
/release_notes/5.0.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.0.1 Release Notes
2 |
3 | ## Changes
4 |
5 | * Fixed state leak between multiple Jasmine instances run consecutively
6 |
7 | Fixes [#207](https://github.com/jasmine/jasmine-npm/issues/207)
8 |
9 | ## Supported environments
10 |
11 | The jasmine package has been tested on Node 18 and 20.
12 |
13 | ------
14 |
15 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
16 |
--------------------------------------------------------------------------------
/release_notes/5.0.2.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.0.2 Release Notes
2 |
3 | ## Changes
4 |
5 | * Fixed error when using the --require CLI argument
6 | * Fixes [#208](https://github.com/jasmine/jasmine-npm/issues/208)
7 |
8 |
9 | ## Supported environments
10 |
11 | The jasmine package has been tested on Node 18 and 20.
12 |
13 | ------
14 |
15 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
16 |
--------------------------------------------------------------------------------
/release_notes/5.1.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.1.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.1.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.1.0.md)
5 | for more information.
6 |
7 | ## Bug Fixes
8 |
9 | * Issue a deprecation warning if both jasmine.js and jasmine.json are found
10 |
11 | Jasmine incorrectly loads both files if they're both found. This will be
12 | fixed in the next major release.
13 |
14 | * Fixed support for importing namespaced modules e.g. @serenity-js/jasmine
15 |
16 | Fixes [#199](https://github.com/jasmine/jasmine-npm/issues/199)
17 |
18 | Merges [#209](https://github.com/jasmine/jasmine-npm/pull/209) from @jan-molak
19 |
20 | * Fixed config file detection when the Testdouble loader and possibly other
21 | custom ES module loaders are used
22 |
23 | ## Supported environments
24 |
25 | The jasmine package has been tested on Node 18 and 20.
26 |
27 | ------
28 |
29 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
30 |
--------------------------------------------------------------------------------
/release_notes/5.2.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.2.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.2.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.2.0.md)
5 | for more information.
6 |
7 | ## New Features
8 |
9 | * Wrap help text to the terminal width
10 | * --verbose flag to print configuration debugging info
11 | * Fixes [#211](https://github.com/jasmine/jasmine-npm/issues/211).
12 |
13 | ## Bug Fixes
14 |
15 | * Report parallel spec loading errors as suite errors rather than terminating early
16 | * Removed excess logging when parallel execution terminates early
17 |
18 | ## Documentation Improvements
19 |
20 | * Added Node 22 to supported environments
21 | * Fixed API docs for Runner#loadConfigFile
22 | * Removed obsolete bits from README
23 |
24 | ## Supported environments
25 |
26 | This version has been tested on Node 18, 20, and 22.
27 |
28 | ------
29 |
30 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
31 |
--------------------------------------------------------------------------------
/release_notes/5.3.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.3.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.3.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.3.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | This version has been tested on Node 18, 20, and 22.
10 |
11 |
--------------------------------------------------------------------------------
/release_notes/5.3.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.3.1 Release Notes
2 |
3 | This release fixes an error when reporting expectation results involving
4 | non-serializable objects in parallel mode. See
5 | [#212](https://github.com/jasmine/jasmine-npm/issues/212).
6 |
7 | ## Supported environments
8 |
9 | This version has been tested on Node 18, 20, and 22.
10 |
--------------------------------------------------------------------------------
/release_notes/5.4.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.4.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.4.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.4.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | This version has been tested on Node 18, 20, and 22.
10 |
11 |
--------------------------------------------------------------------------------
/release_notes/5.5.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.5.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.5.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.5.0.md)
5 | for more information.
6 |
7 | ## Changes
8 |
9 | * Support and generate .mjs config files
10 |
11 | * Set forbidDuplicateNames: true in newly generated configs
12 |
13 | ## Supported environments
14 |
15 | This version has been tested on Node 18, 20, and 22.
16 |
--------------------------------------------------------------------------------
/release_notes/5.6.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.6.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.6.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.6.0.md)
5 | for more information.
6 |
7 | ## Supported environments
8 |
9 | This version has been tested on Node 18, 20, and 22.
10 |
--------------------------------------------------------------------------------
/release_notes/5.7.0.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.7.0 Release Notes
2 |
3 | This release updates the jasmine-core dependency to 5.7.0. See the
4 | [jasmine-core release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/5.7.0.md)
5 | for more information.
6 |
7 | ## New features and bug fixes
8 |
9 | * Added `--filter-path=` option to do exact (non-regex) prefix filtering
10 | * Updated help text to clarify that `--filter=` takes a regex
11 | * Added `enumerate` subcommand to list suites and specs
12 |
13 | ## Internal improvements
14 |
15 | * Removed mostly-unmaintained dev dependency 'temp'
16 | * Updated to eslint 9
17 | * Updated dev dependency shelljs
18 |
19 | ## Supported environments
20 |
21 | This version has been tested on Node 18*, 20, and 22.
22 |
23 | \* Environments that are past end of life are supported on a best-effort basis.
24 | They may be dropped in a future minor release of Jasmine if continued support
25 | becomes impractical.
26 |
27 |
28 | ------
29 |
30 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
31 |
--------------------------------------------------------------------------------
/release_notes/5.7.1.md:
--------------------------------------------------------------------------------
1 | # Jasmine 5.7.1 Release Notes
2 |
3 | ## Bug fixes
4 |
5 | * Fixed handling of spec filters that are RegExp instances
6 |
7 | ## Supported environments
8 |
9 | This version has been tested on Node 18*, 20, and 22.
10 |
11 | \* Environments that are past end of life are supported on a best-effort basis.
12 | They may be dropped in a future minor release of Jasmine if continued support
13 | becomes impractical.
14 |
15 |
16 | ------
17 |
18 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
19 |
--------------------------------------------------------------------------------
/spec/filters/regex_spec_filter_spec.js:
--------------------------------------------------------------------------------
1 | const regexSpecFilter = require('../../lib/filters/regex_spec_filter');
2 |
3 | describe("regexSpecFilter", function() {
4 | it("should match when no string is provided", function() {
5 | const specFilter = regexSpecFilter();
6 |
7 | expect(specFilter({ getFullName: () => "foo" })).toBe(true);
8 | expect(specFilter({ getFullName: () => "*bar" })).toBe(true);
9 | });
10 |
11 | it("should match the provided string", function() {
12 | const specFilter = regexSpecFilter("foo?");
13 |
14 | expect(specFilter({ getFullName: () => "foo"})).toBe(true);
15 | expect(specFilter({ getFullName: () => "fo"})).toBe(true);
16 | expect(specFilter({ getFullName: () => "bar"})).toBe(false);
17 | });
18 |
19 | it("should match the provided regex", function() {
20 | const specFilter = regexSpecFilter(/foo?/);
21 |
22 | expect(specFilter({ getFullName: () => "foo"})).toBe(true);
23 | expect(specFilter({ getFullName: () => "fo"})).toBe(true);
24 | expect(specFilter({ getFullName: () => "bar"})).toBe(false);
25 | });
26 |
27 | it("should match by part of spec name", function() {
28 | const specFilter = regexSpecFilter("ba");
29 |
30 | expect(specFilter({ getFullName: () => "foo"})).toBe(false);
31 | expect(specFilter({ getFullName: () => "bar"})).toBe(true);
32 | expect(specFilter({ getFullName: () => "baz"})).toBe(true);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/spec/fixtures/badReporter.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/badReporter.js
--------------------------------------------------------------------------------
/spec/fixtures/cjs-load-exception/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "throws_on_load.js"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/cjs-load-exception/throws_on_load.js:
--------------------------------------------------------------------------------
1 | throw new Error("nope");
2 |
--------------------------------------------------------------------------------
/spec/fixtures/cjs-syntax-error/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "syntax_error.js"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/cjs-syntax-error/syntax_error.js:
--------------------------------------------------------------------------------
1 | function(
2 |
--------------------------------------------------------------------------------
/spec/fixtures/customReporter.js:
--------------------------------------------------------------------------------
1 | module.exports = function Report() {};
2 |
--------------------------------------------------------------------------------
/spec/fixtures/customReporter.mjs:
--------------------------------------------------------------------------------
1 | export default function Reporter() {}
2 |
3 | Reporter.prototype.jasmineDone = function() {
4 | console.log('customReporter.mjs jasmineDone');
5 | };
6 |
7 | Reporter.prototype.isCustomReporterDotMjs = true;
--------------------------------------------------------------------------------
/spec/fixtures/defaultProgrammaticFail.js:
--------------------------------------------------------------------------------
1 | const Jasmine = require('../..');
2 | const jasmine = new Jasmine();
3 |
4 | it('fails', function() {
5 | expect(1).toBe(2);
6 | });
7 |
8 | jasmine.execute();
9 |
--------------------------------------------------------------------------------
/spec/fixtures/dontExitOnCompletion.js:
--------------------------------------------------------------------------------
1 | const Jasmine = require('../..');
2 | const jasmine = new Jasmine();
3 |
4 | it('a spec', function() {});
5 |
6 | jasmine.exitOnCompletion = false;
7 | jasmine.execute().finally(function() {
8 | setTimeout(function() {
9 | console.log("in setTimeout cb");
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/spec/fixtures/env-config/aSpec.js:
--------------------------------------------------------------------------------
1 | for (let i = 1; i <= 5; i++) {
2 | it('spec 1', function() {
3 | console.log('in spec ' + i);
4 | });
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/env-config/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["aSpec.js"],
4 | "env": {
5 | "random": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-importing-commonjs-syntax-error/intermediate.js:
--------------------------------------------------------------------------------
1 | require('./syntax_error');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-importing-commonjs-syntax-error/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "spec.mjs"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-importing-commonjs-syntax-error/spec.mjs:
--------------------------------------------------------------------------------
1 | await import('./intermediate.js');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-importing-commonjs-syntax-error/syntax_error.js:
--------------------------------------------------------------------------------
1 | {
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-indirect-error/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "spec.mjs"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-indirect-error/spec.mjs:
--------------------------------------------------------------------------------
1 | import './throws.mjs';
2 |
3 | it('a spec', () => {});
4 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-indirect-error/throws.mjs:
--------------------------------------------------------------------------------
1 | throw new Error('nope');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-load-exception/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "throws_on_load.mjs"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-load-exception/throws_on_load.mjs:
--------------------------------------------------------------------------------
1 | throw new Error("nope");
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-reporter-packagejson/customReporter.js:
--------------------------------------------------------------------------------
1 | export default function Reporter() {}
2 |
3 | Reporter.prototype.jasmineDone = function() {
4 | console.log('customReporter.js jasmineDone');
5 | };
6 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-reporter-packagejson/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | ],
5 | "jsLoader": "import"
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-reporter-packagejson/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module"
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-syntax-error/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "syntax_error.mjs"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/esm-syntax-error/syntax_error.mjs:
--------------------------------------------------------------------------------
1 | function(
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/commonjs_helper.js:
--------------------------------------------------------------------------------
1 | console.log('commonjs_helper');
2 | require('./commonjs_sentinel');
3 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/commonjs_sentinel.js:
--------------------------------------------------------------------------------
1 | // An empty module that we can require, to see if require works.
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/commonjs_spec.js:
--------------------------------------------------------------------------------
1 | describe('A spec file ending in .js', function() {
2 | it('is required as a commonjs module', function() {
3 | require('./commonjs_sentinel');
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/esm_helper.mjs:
--------------------------------------------------------------------------------
1 | import './esm_sentinel.mjs';
2 | console.log('esm_helper');
3 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/esm_sentinel.mjs:
--------------------------------------------------------------------------------
1 | // An empty module that will fail if loaded via require(), due to its extension
2 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/esm_spec.mjs:
--------------------------------------------------------------------------------
1 | describe('A spec file ending in .mjs', function() {
2 | it('is imported as an es module', function() {
3 | // Node probably threw already if we tried to require this file,
4 | // but check anyway just to be sure.
5 | expect(function() {
6 | require('./commonjs_sentinel');
7 | }).toThrowError(/require is not defined/);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/jasmine.mjs:
--------------------------------------------------------------------------------
1 | const config = {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "commonjs_spec.js",
5 | "esm_spec.mjs"
6 | ],
7 | "helpers": [
8 | "name_reporter.js",
9 | "commonjs_helper.js",
10 | "esm_helper.mjs"
11 | ],
12 | "stopSpecOnExpectationFailure": false,
13 | "random": false
14 | };
15 | export default config;
16 |
--------------------------------------------------------------------------------
/spec/fixtures/esm/name_reporter.js:
--------------------------------------------------------------------------------
1 | console.log('name_reporter');
2 |
3 | beforeAll(function() {
4 | jasmine.getEnv().addReporter({
5 | specStarted: function (event) {
6 | console.log('Spec:', event.fullName);
7 | }
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/spec/fixtures/example/lib/jasmine_examples/Bar.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/example/lib/jasmine_examples/Bar.js
--------------------------------------------------------------------------------
/spec/fixtures/example/lib/jasmine_examples/Foo.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/example/lib/jasmine_examples/Foo.js
--------------------------------------------------------------------------------
/spec/fixtures/example/spec/helpers/jasmine_examples/SpecHelper.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/example/spec/helpers/jasmine_examples/SpecHelper.js
--------------------------------------------------------------------------------
/spec/fixtures/example/spec/jasmine_examples/FooSpec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/example/spec/jasmine_examples/FooSpec.js
--------------------------------------------------------------------------------
/spec/fixtures/global_setup_failure/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalSetup() {
5 | return Promise.reject(new Error('oops'));
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/spec/fixtures/global_setup_failure/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/global_setup_success/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalSetup() {
5 | console.log('in globalSetup');
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/spec/fixtures/global_setup_success/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_failure/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalTeardown() {
5 | return Promise.reject(new Error('oops'));
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_failure/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_success/global_setup_success/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalTeardown() {
5 | console.log('in globalTeardown');
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_success/global_setup_success/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_success/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalTeardown() {
5 | console.log('in globalTeardown');
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_success/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_unhandled/jasmine.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | spec_dir: '.',
3 | spec_files: ['spec.js'],
4 | globalTeardown() {
5 | setTimeout(function() {
6 | throw new Error('oops');
7 | });
8 | return new Promise(resolve => setTimeout(resolve));
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/spec/fixtures/global_teardown_unhandled/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/import-jsx/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": [
4 | "spec.jsx"
5 | ],
6 | "helpers": []
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/import-jsx/spec.jsx:
--------------------------------------------------------------------------------
1 | it('is a spec', function() {
2 | });
3 |
--------------------------------------------------------------------------------
/spec/fixtures/jasmine_spec/c.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/jasmine_spec/c.js
--------------------------------------------------------------------------------
/spec/fixtures/jasmine_spec/d.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/jasmine_spec/d.js
--------------------------------------------------------------------------------
/spec/fixtures/jasmine_spec/e.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/jasmine_spec/e.js
--------------------------------------------------------------------------------
/spec/fixtures/jasmine_spec/f.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/jasmine_spec/f.js
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-default/anEsModule.js:
--------------------------------------------------------------------------------
1 | export function foo() {
2 | return 42;
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-default/anEsModuleSpec.js:
--------------------------------------------------------------------------------
1 | import {foo} from './anEsModule.js';
2 |
3 | describe('foo', function() {
4 | it('returns 42', function() {
5 | expect(foo()).toEqual(42);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-default/anEsRequire.js:
--------------------------------------------------------------------------------
1 | import './anEsModule.js';
2 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-default/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["anEsModuleSpec.js"],
4 | "requires": ["../js-loader-default/anEsRequire.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-default/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module"
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/anEsModule.js:
--------------------------------------------------------------------------------
1 | export function foo() {
2 | return 42;
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/anEsModuleSpec.js:
--------------------------------------------------------------------------------
1 | import {foo} from './anEsModule.js';
2 |
3 | describe('foo', function() {
4 | it('returns 42', function() {
5 | expect(foo()).toEqual(42);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/anEsRequire.js:
--------------------------------------------------------------------------------
1 | import './anEsModule.js';
2 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/anotherEsModuleSpec.js:
--------------------------------------------------------------------------------
1 | import {foo} from './anEsModule.js';
2 |
3 | describe('foo', function() {
4 | it('returns 42', function() {
5 | expect(foo()).toEqual(42);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["anEsModuleSpec.js"],
4 | "requires": ["../js-loader-import/anEsRequire.js"],
5 | "jsLoader": "import"
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-import/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module"
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-require/aRequire.js:
--------------------------------------------------------------------------------
1 | if (!module.parent) {
2 | throw new Error('aRequire.js was loaded as an ES module');
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-require/aSpec.js:
--------------------------------------------------------------------------------
1 | describe('a file with js extension', function() {
2 | it('was loaded as a CommonJS module', function() {
3 | expect(module.parent).toBeTruthy();
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/spec/fixtures/js-loader-require/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["aSpec.js"],
4 | "requires": ["../spec/fixtures/js-loader-require/aRequire.js"],
5 | "jsLoader": "require"
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/no-globals-parallel/aHelper.js:
--------------------------------------------------------------------------------
1 | const {jasmine, beforeEach} = require('jasmine-core').noGlobals();
2 | beforeEach(function() {
3 | jasmine.addCustomEqualityTester(function(a, b) {
4 | if ((a === 1 && b === 2) || (a === 2 && b === 1)) {
5 | return true;
6 | }
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/spec/fixtures/no-globals-parallel/aSpec.js:
--------------------------------------------------------------------------------
1 | const jasmineInterface = require('jasmine-core').noGlobals();
2 | const {it, expect} = jasmineInterface;
3 |
4 | it('can use equality testers defined in a different file', function() {
5 | expect(1).toEqual(2);
6 | });
7 |
8 | it('does not add any globals', function() {
9 | const jasmineGlobals = Object.keys(jasmineInterface)
10 | .filter(k => global[k] !== undefined);
11 | expect(jasmineGlobals).toEqual([]);
12 | });
13 |
--------------------------------------------------------------------------------
/spec/fixtures/no-globals-parallel/runner.js:
--------------------------------------------------------------------------------
1 | const ParallelRunner = require('../../../lib/parallel_runner.js');
2 | const runner = new ParallelRunner({
3 | globals: false,
4 | numWorkers: 2
5 | });
6 | runner.addHelperFile('./aHelper.js');
7 | runner.addSpecFile('./aSpec.js');
8 | runner.execute();
9 |
--------------------------------------------------------------------------------
/spec/fixtures/no-globals/aSpec.js:
--------------------------------------------------------------------------------
1 | const {it, expect} = require('jasmine-core').noGlobals();
2 |
3 | it('can use equality testers defined in a different file', function() {
4 | expect(1).toEqual(2);
5 | });
6 |
--------------------------------------------------------------------------------
/spec/fixtures/no-globals/runner.js:
--------------------------------------------------------------------------------
1 | const initialGlobals = Object.keys(global);
2 | const Jasmine = require('../../../lib/jasmine.js');
3 | const {jasmine, beforeEach} = require('jasmine-core').noGlobals();
4 | beforeEach(function() {
5 | jasmine.addCustomEqualityTester(function(a, b) {
6 | if ((a === 1 && b === 2) || (a === 2 && b === 1)) {
7 | return true;
8 | }
9 | });
10 | });
11 |
12 | const runner = new Jasmine({globals: false});
13 | runner.addSpecFile('./aSpec.js');
14 | runner.exitOnCompletion = false;
15 | runner.execute().then(function() {
16 | const extraGlobals = Object.keys(global).filter(k => !initialGlobals.includes(k));
17 |
18 | if (extraGlobals.length === 0) {
19 | console.log('Globals OK');
20 | } else {
21 | console.log('Extra globals:', extraGlobals);
22 | }
23 | });
24 |
--------------------------------------------------------------------------------
/spec/fixtures/noisy_require.js:
--------------------------------------------------------------------------------
1 | console.log('noisy require was loaded');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_before_after/helper.js:
--------------------------------------------------------------------------------
1 | beforeEach(function() {
2 | console.log('beforeEach in helper ran');
3 | });
4 |
5 | afterEach(function() {
6 | console.log('afterEach in helper ran');
7 | });
8 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_before_after/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"],
4 | "helpers": ["helper.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_before_after/spec.js:
--------------------------------------------------------------------------------
1 | describe('a suite', function() {
2 | beforeEach(function() {
3 | console.log('beforeEach in describe ran');
4 | });
5 |
6 | afterEach(function() {
7 | console.log('afterEach in describe ran');
8 | });
9 |
10 | it('a spec', function() {});
11 | });
12 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_filter/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "jsLoader": "require",
3 | "spec_dir": ".",
4 | "spec_files": ["spec*.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_filter/spec1.js:
--------------------------------------------------------------------------------
1 | describe('suite 1', function() {
2 | it('foo', function() {
3 | expect(1).toBe(2);
4 | });
5 |
6 | it('bar', function() {
7 | expect(1).toBe(2);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_filter/spec2.js:
--------------------------------------------------------------------------------
1 | describe('suite 2', function() {
2 | it('foo', function() {
3 | expect(1).toBe(2);
4 | });
5 |
6 | it('bar', function() {
7 | expect(1).toBe(2);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helper_load_exception/helper.js:
--------------------------------------------------------------------------------
1 | throw new Error('nope');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helper_load_exception/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"],
4 | "helpers": ["helper.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helper_load_exception/spec.js:
--------------------------------------------------------------------------------
1 | it('is a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helpers/helper1.js:
--------------------------------------------------------------------------------
1 | global.helperLoaded = true;
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helpers/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"],
4 | "helpers": ["helper*.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helpers/spec1.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 1', function() {
2 | it('a spec', function() {
3 | expect(global.helperLoaded).toBeTrue();
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_helpers/spec2.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 2', function() {
2 | it('a spec', function() {
3 | expect(global.helperLoaded).toBeTrue();
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_invalid_afterEach/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_invalid_afterEach/spec.js:
--------------------------------------------------------------------------------
1 | afterEach(function() {
2 | console.log('top level afterEach in spec file ran');
3 | });
4 |
5 | it('a spec', function() {});
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_invalid_beforeEach/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_invalid_beforeEach/spec.js:
--------------------------------------------------------------------------------
1 | beforeEach(function() {
2 | console.log('top level beforeEach in spec file ran');
3 | });
4 |
5 | it('a spec', function() {});
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_jsLoader/a%20spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {});
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_jsLoader/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "jsLoader": "require",
3 | "spec_dir": ".",
4 | "spec_files": ["a%20spec.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_no_specs/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_no_specs/spec1.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/parallel_no_specs/spec1.js
--------------------------------------------------------------------------------
/spec/fixtures/parallel_pass/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_pass/spec1.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 1', function() {
2 | it('a spec', function() {});
3 | it('another spec', function() {});
4 | });
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_pass/spec2.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 2', function() {
2 | it('yet another spec', function() {});
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_requires/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"],
4 | "requires": ["./requireMe.js"]
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_requires/requireMe.js:
--------------------------------------------------------------------------------
1 | global.wasRequired = true;
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_requires/spec1.js:
--------------------------------------------------------------------------------
1 | it('spec 1', function() {
2 | expect(global.wasRequired).toBeTrue();
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_requires/spec2.js:
--------------------------------------------------------------------------------
1 | it('spec 2', function() {
2 | expect(global.wasRequired).toBeTrue();
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_spec_fail/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_spec_fail/spec1.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 1', function() {
2 | it('a spec', function() {});
3 | it('a failing spec', function() {
4 | expect(1).toBe(2);
5 | });
6 | });
7 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_spec_fail/spec2.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 2', function() {
2 | it('yet another spec', function() {});
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_spec_load_exception/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_spec_load_exception/spec.js:
--------------------------------------------------------------------------------
1 | throw new Error('nope');
2 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_suite_fail/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_suite_fail/spec1.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 1', function() {
2 | it('a spec', function() {});
3 |
4 | afterAll(function() {
5 | expect(1).toBe(2);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_suite_fail/spec2.js:
--------------------------------------------------------------------------------
1 | describe('Spec file 2', function() {
2 | it('yet another spec', function() {});
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/parallel_suite_incomplete/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec*.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/premature_exit/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": ".",
3 | "spec_files": ["spec.js"]
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/premature_exit/spec.js:
--------------------------------------------------------------------------------
1 | it('a spec', function() {
2 | process.exit(0);
3 | });
4 |
--------------------------------------------------------------------------------
/spec/fixtures/promiseFailure.js:
--------------------------------------------------------------------------------
1 | const Jasmine = require('../..');
2 | const jasmine = new Jasmine();
3 |
4 | it('a spec', function() {
5 | expect(1).toBe(2);
6 | });
7 |
8 | jasmine.exitOnCompletion = false;
9 | jasmine.execute().then(function(result) {
10 | if (result.overallStatus === 'failed') {
11 | console.log("Promise failure!");
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/spec/fixtures/promiseIncomplete.js:
--------------------------------------------------------------------------------
1 | const Jasmine = require('../..');
2 | const jasmine = new Jasmine();
3 |
4 | it('a spec', function() {});
5 |
6 | fit('another spec', function() {});
7 |
8 | jasmine.exitOnCompletion = false;
9 | jasmine.execute().then(function(result) {
10 | if (result.overallStatus === 'incomplete') {
11 | console.log("Promise incomplete!");
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/spec/fixtures/promiseSuccess.js:
--------------------------------------------------------------------------------
1 | const Jasmine = require('../..');
2 | const jasmine = new Jasmine();
3 |
4 | it('a spec', function() {});
5 |
6 | jasmine.exitOnCompletion = false;
7 | jasmine.execute().then(function(result) {
8 | if (result.overallStatus === 'passed') {
9 | console.log("Promise success!");
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/spec/fixtures/require_tester.js:
--------------------------------------------------------------------------------
1 | global.require_tester_was_loaded = true;
2 | module.exports = {};
3 |
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/fixture_spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/sample_project/spec/fixture_spec.js
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/helper.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/sample_project/spec/helper.js
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/other_fixture_spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasmine/jasmine-npm/4937540da3426dc00d1683e24c93c05de8605f21/spec/fixtures/sample_project/spec/other_fixture_spec.js
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/support/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "fixture_spec.js"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/support/jasmine_alternate.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "fixture_spec.js",
5 | "**/*spec.js"
6 | ],
7 | "helpers": [
8 | "helper.js"
9 | ],
10 | "requires": [
11 | "ts-node/register"
12 | ]
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/support/jasmine_alternate.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "fixture_spec.js",
5 | "**/*spec.js"
6 | ],
7 | "helpers": [
8 | "helper.js"
9 | ],
10 | "requires": [
11 | "ts-node/register"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/spec/fixtures/sample_project/spec/support/jasmine_alternate.mjs:
--------------------------------------------------------------------------------
1 | const config = {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "fixture_spec.js",
5 | "**/*spec.js"
6 | ],
7 | "helpers": [
8 | "helper.js"
9 | ],
10 | "requires": [
11 | "ts-node/register"
12 | ]
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/spec/fixtures/topLevelAwaitSentinel.mjs:
--------------------------------------------------------------------------------
1 | await Promise.resolve();
2 |
--------------------------------------------------------------------------------
/spec/global_setup_or_teardown_runner_spec.js:
--------------------------------------------------------------------------------
1 | const GlobalSetupOrTeardownRunner = require('../lib/global_setup_or_teardown_runner');
2 |
3 | describe('GlobalSetupOrTeardownRunner', function() {
4 | describe('#run', function() {
5 | it('waits for a promise-returning fn to complete', async function () {
6 | const subject = new GlobalSetupOrTeardownRunner();
7 | let resolve;
8 |
9 | const runPromise = subject.run('', function() {
10 | return new Promise(res => resolve = res);
11 | });
12 | await expectAsync(runPromise).toBePending();
13 |
14 | resolve();
15 | await runPromise;
16 | });
17 | });
18 |
19 | it('supports synchronous fns', async function() {
20 | const subject = new GlobalSetupOrTeardownRunner();
21 | await subject.run('', function() {});
22 | });
23 |
24 | it('fails if the fn throws synchronously', async function() {
25 | const subject = new GlobalSetupOrTeardownRunner();
26 | const error = new Error('nope');
27 | const runPromise = subject.run('', function() {
28 | throw error;
29 | });
30 | await expectAsync(runPromise).toBeRejectedWith(jasmine.is(error));
31 | });
32 |
33 | it('fails if the promise returned by the fn is rejected', async function () {
34 | const subject = new GlobalSetupOrTeardownRunner();
35 | const error = new Error('nope');
36 | const runPromise = subject.run('', function () {
37 | return Promise.reject(error);
38 | });
39 | await expectAsync(runPromise).toBeRejectedWith(jasmine.is(error));
40 | });
41 |
42 | it('fails if there is an unhandled exception', async function () {
43 | await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
44 | const subject = new GlobalSetupOrTeardownRunner();
45 | const innerError = new Error();
46 | const runPromise = subject.run('foo', function () {
47 | setTimeout(function () {
48 | throw innerError;
49 | });
50 |
51 | return new Promise(res => setTimeout(res));
52 | });
53 |
54 | await runPromise.then(
55 | () => Promise.reject('Expected promise to be rejected but it was resolved'),
56 | outerError => {
57 | expect(outerError.message).toEqual('Unhandled exception during foo');
58 | expect(outerError.cause).toBe(innerError);
59 | }
60 | );
61 |
62 | expect(globalErrorSpy).toHaveBeenCalledOnceWith(innerError);
63 | });
64 | });
65 |
66 | it('fails if there is an unhandled promise rejection', async function () {
67 | await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
68 | const subject = new GlobalSetupOrTeardownRunner();
69 | const innerError = new Error();
70 | const runPromise = subject.run('bar', function () {
71 | setTimeout(function () {
72 | Promise.reject(innerError);
73 | });
74 |
75 | return new Promise(res => setTimeout(res));
76 | });
77 |
78 | await runPromise.then(
79 | () => Promise.reject('Expected promise to be rejected but it was resolved'),
80 | outerError => {
81 | expect(outerError.message).toEqual('Unhandled promise rejection during bar');
82 | expect(outerError.cause).toBe(innerError);
83 | }
84 | );
85 |
86 | expect(globalErrorSpy).toHaveBeenCalledOnceWith(innerError);
87 | });
88 | });
89 |
90 | describe('Timeout handling', function() {
91 | const realSetTimeout = setTimeout;
92 |
93 | beforeEach(function() {
94 | jasmine.clock().install();
95 | });
96 |
97 | afterEach(function() {
98 | jasmine.clock().uninstall();
99 | });
100 |
101 | it('fails if the promise returned by the fn is not resolved within 5 seconds', async function () {
102 | const subject = new GlobalSetupOrTeardownRunner();
103 | const runPromise = subject.run('foo', function() {
104 | return new Promise(() => {});
105 | });
106 |
107 | jasmine.clock().tick(4999);
108 | await new Promise(res => realSetTimeout.call(null, res));
109 | await expectAsync(runPromise).toBePending();
110 |
111 | jasmine.clock().tick(1);
112 | await expectAsync(runPromise).toBeRejectedWithError(
113 | 'foo timed out after 5000 milliseconds'
114 | );
115 | });
116 |
117 | it('can use a custom timeout', async function() {
118 | const subject = new GlobalSetupOrTeardownRunner();
119 | const runPromise = subject.run('bar', function() {
120 | return new Promise(() => {});
121 | }, 10);
122 |
123 | jasmine.clock().tick(9);
124 | await new Promise(res => realSetTimeout.call(null, res));
125 | await expectAsync(runPromise).toBePending();
126 |
127 | jasmine.clock().tick(1);
128 | await expectAsync(runPromise).toBeRejectedWithError(
129 | 'bar timed out after 10 milliseconds'
130 | );
131 | });
132 | });
133 | });
134 |
--------------------------------------------------------------------------------
/spec/loader_spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const url = require('url');
3 | const Loader = require('../lib/loader');
4 |
5 | describe('loader', function() {
6 | afterEach(function() {
7 | delete global.require_tester_was_loaded;
8 | });
9 |
10 | it('sets alwaysImport to true by default', function() {
11 | expect(new Loader().alwaysImport).toBeTrue();
12 | });
13 |
14 | describe('#load', function() {
15 | describe('With alwaysImport: true', function() {
16 | describe('When the path ends in .mjs', function () {
17 | esModuleSharedExamples('mjs', true);
18 | });
19 |
20 | describe('When the path does not end in .mjs', function () {
21 | esModuleSharedExamples('js', true);
22 | });
23 |
24 | describe('When the extension is not supported by import()', function() {
25 | it('falls back to require()', async function() {
26 | const error = new TypeError();
27 | error.code = 'ERR_UNKNOWN_FILE_EXTENSION';
28 | const payload = {};
29 | const requireShim = jasmine.createSpy('requireShim')
30 | .and.returnValue(Promise.resolve(payload));
31 | const importShim = jasmine.createSpy('importShim')
32 | .and.returnValue(Promise.reject(error));
33 | const loader = new Loader({requireShim, importShim});
34 | loader.alwaysImport = true;
35 |
36 | const result = await loader.load('./spec.jsx');
37 |
38 | expect(result).toBe(payload);
39 | expect(requireShim).toHaveBeenCalled();
40 | expect(importShim).toHaveBeenCalled();
41 | });
42 | });
43 |
44 | it('imports non-local modules', async function() {
45 | const payload = {default: {}};
46 | const requireShim = jasmine.createSpy('requireShim');
47 | const importShim = jasmine.createSpy('importShim')
48 | .and.returnValue(Promise.resolve(payload));
49 | const loader = new Loader({requireShim, importShim});
50 | loader.alwaysImport = true;
51 |
52 | const result = await loader.load('some-module');
53 |
54 | expect(result).toBe(payload.default);
55 | expect(requireShim).not.toHaveBeenCalled();
56 | expect(importShim).toHaveBeenCalledWith('some-module');
57 | });
58 |
59 | it('imports namespaced modules', async function() {
60 | const payload = {default: {}};
61 | const requireShim = jasmine.createSpy('requireShim');
62 | const importShim = jasmine.createSpy('importShim')
63 | .and.returnValue(Promise.resolve(payload));
64 | const loader = new Loader({requireShim, importShim});
65 | loader.alwaysImport = true;
66 |
67 | const result = await loader.load('@namespace/some-module');
68 |
69 | expect(result).toBe(payload.default);
70 | expect(requireShim).not.toHaveBeenCalled();
71 | expect(importShim).toHaveBeenCalledWith('@namespace/some-module');
72 | });
73 |
74 | it('uses require to load JSON files', async function() {
75 | const requireShim = jasmine.createSpy('requireShim')
76 | .and.returnValue(Promise.resolve());
77 | const importShim = jasmine.createSpy('importShim');
78 | const loader = new Loader({requireShim, importShim});
79 | loader.alwaysImport = true;
80 |
81 | await expectAsync(loader.load('./jasmine.json')).toBeResolved();
82 |
83 | expect(requireShim).toHaveBeenCalledWith('./jasmine.json');
84 | expect(importShim).not.toHaveBeenCalled();
85 | });
86 | });
87 |
88 | describe('With alwaysImport: false', function() {
89 | describe('When the path ends in .mjs', function () {
90 | esModuleSharedExamples('mjs', false);
91 | });
92 |
93 | it('uses require to load JSON files', async function() {
94 | const requireShim = jasmine.createSpy('requireShim')
95 | .and.returnValue(Promise.resolve());
96 | const importShim = jasmine.createSpy('importShim');
97 | const loader = new Loader({requireShim, importShim});
98 | loader.alwaysImport = false;
99 |
100 | await expectAsync(loader.load('./jasmine.json')).toBeResolved();
101 |
102 | expect(requireShim).toHaveBeenCalledWith('./jasmine.json');
103 | expect(importShim).not.toHaveBeenCalled();
104 | });
105 |
106 | describe('When the path does not end in .mjs', function () {
107 | it('loads the file as a commonjs module', async function () {
108 | const requireShim = jasmine.createSpy('requireShim')
109 | .and.returnValue(Promise.resolve());
110 | const importShim = jasmine.createSpy('importShim');
111 | const loader = new Loader({requireShim, importShim});
112 | loader.alwaysImport = false;
113 |
114 | await expectAsync(loader.load('./foo/bar/baz')).toBeResolved();
115 |
116 | expect(requireShim).toHaveBeenCalledWith('./foo/bar/baz');
117 | expect(importShim).not.toHaveBeenCalled();
118 | });
119 |
120 | it('loads namespaced commonjs module', async function () {
121 | const requireShim = jasmine.createSpy('requireShim')
122 | .and.returnValue(Promise.resolve());
123 | const importShim = jasmine.createSpy('importShim');
124 | const loader = new Loader({requireShim, importShim});
125 | loader.alwaysImport = false;
126 |
127 | await expectAsync(loader.load('@namespace/some-module')).toBeResolved();
128 |
129 | expect(requireShim).toHaveBeenCalledWith('@namespace/some-module');
130 | expect(importShim).not.toHaveBeenCalled();
131 | });
132 |
133 | it('propagates the error when import fails', async function () {
134 | const underlyingError = new Error('nope');
135 | const requireShim = jasmine.createSpy('requireShim')
136 | .and.throwError(underlyingError);
137 | const importShim = jasmine.createSpy('importShim');
138 | const loader = new Loader({requireShim, importShim});
139 | loader.alwaysImport = false;
140 |
141 | await expectAsync(loader.load('foo')).toBeRejectedWith(underlyingError);
142 | });
143 | });
144 | });
145 | });
146 | });
147 |
148 | function esModuleSharedExamples(extension, alwaysImport) {
149 | async function testBasicEsModuleLoading(separator) {
150 | const requireShim = jasmine.createSpy('requireShim');
151 | let resolve;
152 | const importPromise = new Promise(function (res) {
153 | resolve = res;
154 | });
155 | const importShim = jasmine.createSpy('importShim')
156 | .and.returnValue(importPromise);
157 | const resolvePath = jasmine.createSpy('resolvePath')
158 | .and.returnValue('/the/path/to/the/module');
159 | const loader = new Loader({requireShim, importShim, resolvePath});
160 | loader.alwaysImport = alwaysImport;
161 |
162 | const requestedPath = ['foo', 'bar', `baz.${extension}`].join(separator);
163 | const loaderPromise = loader.load(requestedPath);
164 |
165 | expect(requireShim).not.toHaveBeenCalled();
166 | expect(resolvePath).toHaveBeenCalledWith(requestedPath);
167 | expect(importShim).toHaveBeenCalledWith(url.pathToFileURL('/the/path/to/the/module').toString());
168 | await expectAsync(loaderPromise).toBePending();
169 |
170 | resolve({});
171 |
172 | await expectAsync(loaderPromise).toBeResolved();
173 | }
174 |
175 | it('loads the file as an es module', async function () {
176 | await testBasicEsModuleLoading(path.sep);
177 | });
178 |
179 | it('supports /-separated paths', async function() {
180 | await testBasicEsModuleLoading('/');
181 | });
182 |
183 | it("adds the filename to ES module syntax errors", async function() {
184 | const underlyingError = new SyntaxError('some details but no filename, not even in the stack trace');
185 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
186 |
187 | try {
188 | await loader.load(`foo.${extension}`, alwaysImport);
189 | fail('Expected loader to throw but it did not');
190 | } catch (thrown) {
191 | expect(thrown.message).toEqual(
192 | `While loading foo.${extension}: SyntaxError: some details but no filename, not even in the stack trace`
193 | );
194 | expect(thrown.cause).toBe(underlyingError);
195 | }
196 | });
197 |
198 | it('does not modify errors that are not SyntaxError instances', async function() {
199 | const underlyingError = new Error('nope');
200 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
201 |
202 | await expectAsync(loader.load(`foo.${extension}`, alwaysImport)).toBeRejectedWith(underlyingError);
203 | });
204 |
205 | it('does not modify SyntaxErrors that mention the imported filename as a Unix-style path', async function() {
206 | const underlyingError = new SyntaxError('nope');
207 | underlyingError.stack = `/the/absolute/path/to/foo.${extension}:1\n` +
208 | '\n' +
209 | '\n' +
210 | '\n' +
211 | 'maybe some more stack\n';
212 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
213 |
214 | await expectAsync(loader.load(`path/to/foo.${extension}`, alwaysImport))
215 | .toBeRejectedWith(underlyingError);
216 | });
217 |
218 | it('does not modify SyntaxErrors that mention the imported filename as a Unix-style file URL', async function() {
219 | const underlyingError = new SyntaxError('nope');
220 | underlyingError.stack += `\n at async file:///the/absolute/path/to/foo.${extension}:1:1`;
221 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
222 |
223 | await expectAsync(loader.load(`path/to/foo.${extension}`, alwaysImport))
224 | .toBeRejectedWith(underlyingError);
225 | });
226 |
227 | it('does not modify SyntaxErrors that mention the imported filename as a Windows-style path', async function() {
228 | const underlyingError = new SyntaxError('nope');
229 | underlyingError.stack = `c:\\the\\absolute\\path\\to\\foo.${extension}:1\n` +
230 | '\n' +
231 | '\n' +
232 | '\n' +
233 | 'maybe some more stack\n';
234 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
235 |
236 | await expectAsync(loader.load(`path/to/foo.${extension}`, alwaysImport))
237 | .toBeRejectedWith(underlyingError);
238 | });
239 |
240 | it('does not modify SyntaxErrors that mention the imported filename as a Windows-style file URL', async function() {
241 | const underlyingError = new SyntaxError('nope');
242 | underlyingError.stack += `\n at async file:///c:/the/absolute/path/to/foo.${extension}:1:1`;
243 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
244 |
245 | await expectAsync(loader.load(`path/to/foo.${extension}`, alwaysImport))
246 | .toBeRejectedWith(underlyingError);
247 | });
248 |
249 | it('does not modify SyntaxErrors when the stack trace starts with any Unix-style path', async function() {
250 | const underlyingError = new SyntaxError('nope');
251 | underlyingError.stack = '/some/path/to/a/file.js:1\n\n\n\n' + underlyingError.stack;
252 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
253 |
254 | await expectAsync(loader.load(`path/to/some/other/file.${extension}`, alwaysImport))
255 | .toBeRejectedWith(underlyingError);
256 | });
257 |
258 | it('does not modify SyntaxErrors when the stack trace starts with any Windows-style path', async function() {
259 | const underlyingError = new SyntaxError('nope');
260 | underlyingError.stack = 'c:\\some\\path\\to\\a\\file.js:1\n\n\n\n' + underlyingError.stack;
261 | const loader = new Loader({importShim: () => Promise.reject(underlyingError)});
262 |
263 | await expectAsync(loader.load(`path/to/some/other/file.${extension}`, alwaysImport))
264 | .toBeRejectedWith(underlyingError);
265 | });
266 | }
267 |
--------------------------------------------------------------------------------
/spec/npm_package_spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const os = require('os');
4 | const shell = require('shelljs');
5 | const {rimrafSync} = require('rimraf');
6 |
7 | describe('npm package', function() {
8 | beforeAll(function() {
9 | const prefix = path.join(os.tmpdir(), 'jasmine-npm-package');
10 | this.tmpDir = fs.mkdtempSync(prefix);
11 |
12 | const pack = shell.exec('npm pack', { silent: true });
13 | this.tarball = pack.stdout.split('\n')[0];
14 |
15 | const untar = shell.exec('tar -xzf ' + this.tarball + ' -C ' + this.tmpDir, {
16 | silent: true
17 | });
18 | expect(untar.code).toBe(0);
19 | });
20 |
21 | beforeEach(function() {
22 | jasmine.addMatchers({
23 | toExistInPath: function() {
24 | return {
25 | compare: function(actual, expected) {
26 | const fullPath = path.resolve(expected, actual);
27 | return {
28 | pass: fs.existsSync(fullPath)
29 | };
30 | }
31 | };
32 | }
33 | });
34 | });
35 |
36 | afterAll(function() {
37 | fs.unlinkSync(this.tarball);
38 | rimrafSync(this.tmpDir);
39 | });
40 |
41 | it('has a jasmine script', function() {
42 | expect('package/bin/jasmine.js').toExistInPath(this.tmpDir);
43 | });
44 |
45 | it('has a jasmine module', function() {
46 | expect('package/lib/jasmine.js').toExistInPath(this.tmpDir);
47 | });
48 |
49 | it('contains only the expected root entries', function() {
50 | const files = fs.readdirSync(this.tmpDir);
51 | expect(files).toEqual(['package']);
52 | });
53 |
54 | it('contains only the expected entries in the package dir', function() {
55 | const files = fs.readdirSync(path.resolve(this.tmpDir, 'package'));
56 | files.sort();
57 | expect(files).toEqual([
58 | 'LICENSE',
59 | 'README.md',
60 | 'bin',
61 | 'lib',
62 | 'package.json',
63 | ]);
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/spec/path_spec_filter_spec.js:
--------------------------------------------------------------------------------
1 | const pathSpecFilter = require('../lib/filters/path_spec_filter');
2 |
3 | describe("pathSpecFilter", function() {
4 | it("matches a spec with the exact same path", function() {
5 | const specFilter = pathSpecFilter(["a", "b", "c"]);
6 | expect(specFilter(stubSpec(['a', 'b', 'c']))).toBeTrue();
7 | });
8 |
9 | it('matches a spec whose path has the filter path as a prefix', function() {
10 | const specFilter = pathSpecFilter(["a", "b"]);
11 | expect(specFilter(stubSpec(['a', 'b', 'c']))).toBeTrue();
12 | });
13 |
14 | it('does not match a spec with a different path', function() {
15 | const specFilter = pathSpecFilter(["a", "b", "c"]);
16 | expect(specFilter(stubSpec(['a', 'd', 'c']))).toBeFalse();
17 | });
18 |
19 | function stubSpec(path) {
20 | return {
21 | getPath() { return path; },
22 | // getFullName is required, but plays no role in filtering
23 | getFullName() { return ""; }
24 | };
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/spec/poll.js:
--------------------------------------------------------------------------------
1 | // Make sure we can still work if the mock clock is installed
2 | const realSetTimeout = setTimeout;
3 |
4 | async function poll(predicate) {
5 | return new Promise(function(resolve, reject) {
6 | function check() {
7 | try {
8 | if (predicate()) {
9 | resolve();
10 | } else {
11 | realSetTimeout(check);
12 | }
13 | } catch (e) {
14 | reject(e);
15 | }
16 | }
17 |
18 | check();
19 | });
20 | }
21 |
22 | async function shortPoll(predicate, description) {
23 | const timedOut = {};
24 | const timeoutPromise = new Promise(function(resolve) {
25 | realSetTimeout(function() {
26 | resolve(timedOut);
27 | }, 250);
28 | });
29 | const result = await Promise.race([timeoutPromise, poll(predicate)]);
30 |
31 | if (result === timedOut) {
32 | throw new Error(`Timed out waiting for ${description}`);
33 | }
34 | }
35 |
36 | module.exports = {poll, shortPoll};
37 |
--------------------------------------------------------------------------------
/spec/shared_runner_behaviors.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const Loader = require("../lib/loader");
3 |
4 | /*
5 | Preconditions that a beforeEach in the containing suite should provide:
6 | - this.testJasmine is the subject
7 | - this.testJasmine.exit is a spy
8 | - this.execute is a function that executes the env and returns a promise
9 | that resolves when it's done
10 |
11 | Not all shared behaviors are tested here. Many are separately tested in
12 | jasmine_spec.js and parallel_runner_spec.js because the code resulting
13 | from de-duplication would be excessively complex.
14 | */
15 | function sharedRunnerBehaviors(makeRunner) {
16 | describe('Shared runner behaviors', function () {
17 | it('sets projectBaseDir to the cwd by default', function () {
18 | expect(this.testJasmine.projectBaseDir).toEqual(
19 | path.resolve().replace(/\\/g, '/')
20 | );
21 | });
22 |
23 | describe('#addSpecFile', function () {
24 | it('adds the provided path to the list of spec files', function () {
25 | expect(this.testJasmine.specFiles).toEqual([]);
26 | this.testJasmine.addSpecFile('some/file/path.js');
27 | expect(this.testJasmine.specFiles).toEqual(['some/file/path.js']);
28 | });
29 | });
30 |
31 | describe('#addHelperFile', function () {
32 | it('adds the provided path to the list of helper files', function () {
33 | expect(this.testJasmine.helperFiles).toEqual([]);
34 | this.testJasmine.addHelperFile('some/file/path.js');
35 | expect(this.testJasmine.helperFiles).toEqual(['some/file/path.js']);
36 | });
37 | });
38 |
39 | describe('Methods that specify files via globs', function () {
40 | describe('#addMatchingSpecFiles', function () {
41 | hasCommonFileGlobBehavior('addMatchingSpecFiles', 'specFiles');
42 | });
43 |
44 | describe('#addMatchingHelperFiles', function () {
45 | hasCommonFileGlobBehavior('addMatchingHelperFiles', 'helperFiles');
46 | });
47 |
48 | function hasCommonFileGlobBehavior(method, destProp) {
49 | it('adds a file with an absolute path', function () {
50 | const aFile = path.join(this.testJasmine.projectBaseDir, this.testJasmine.specDir, 'spec/command_spec.js')
51 | .replace(/\\/g, '/');
52 | expect(this.testJasmine[destProp]).toEqual([]);
53 | this.testJasmine[method]([aFile]);
54 | const expectedPath = aFile.replace(/\\/g, '/');
55 | expect(this.testJasmine[destProp]).toEqual([
56 | pathEndingWith(expectedPath)
57 | ]);
58 | });
59 |
60 | it('adds files that match a glob pattern', function () {
61 | expect(this.testJasmine[destProp]).toEqual([]);
62 | this.testJasmine[method](['spec/fixtures/jasmine_spec/*.js']);
63 | expect(this.testJasmine[destProp].map(basename)).toEqual([
64 | 'c.js',
65 | 'd.js',
66 | 'e.js',
67 | 'f.js',
68 | ]);
69 | });
70 |
71 | it('can exclude files that match another glob', function () {
72 | expect(this.testJasmine[destProp]).toEqual([]);
73 | this.testJasmine[method]([
74 | 'spec/fixtures/jasmine_spec/*.js',
75 | '!spec/fixtures/jasmine_spec/c*'
76 | ]);
77 | expect(this.testJasmine[destProp].map(basename)).toEqual([
78 | 'd.js',
79 | 'e.js',
80 | 'f.js',
81 | ]);
82 | });
83 |
84 | it('adds new files to existing files', function () {
85 | // Don't use path.join because glob needs forward slashes
86 | // even on Windows
87 | const aFile = [
88 | this.testJasmine.projectBaseDir,
89 | this.testJasmine.specDir,
90 | 'spec/command_spec.js',
91 | ].join('/');
92 | this.testJasmine[destProp] = [aFile, 'b'];
93 | this.testJasmine[method](['spec/fixtures/jasmine_spec/*.js']);
94 | expect(this.testJasmine[destProp].map(basename)).toEqual([
95 | 'command_spec.js',
96 | 'b',
97 | 'c.js',
98 | 'd.js',
99 | 'e.js',
100 | 'f.js',
101 | ]);
102 | });
103 | }
104 |
105 | function basename(name) {
106 | return path.basename(name);
107 | }
108 | });
109 |
110 | describe('#configureDefaultReporter', function () {
111 | beforeEach(function () {
112 | if (!jasmine.isSpy(this.testJasmine.reporter_.setOptions)) {
113 | spyOn(this.testJasmine.reporter_, 'setOptions');
114 | }
115 | });
116 |
117 | it('sets the options on the console reporter', function () {
118 | const reporterOptions = {
119 | print: 'printer',
120 | showColors: true,
121 | };
122 |
123 | const expectedReporterOptions = Object.keys(reporterOptions).reduce(function (options, key) {
124 | options[key] = reporterOptions[key];
125 | return options;
126 | }, {});
127 |
128 | this.testJasmine.configureDefaultReporter(reporterOptions);
129 |
130 | expect(this.testJasmine.reporter_.setOptions).toHaveBeenCalledWith(expectedReporterOptions);
131 | });
132 |
133 | it('creates a reporter with a default option if an option is not specified', function () {
134 | const reporterOptions = {};
135 |
136 | this.testJasmine.configureDefaultReporter(reporterOptions);
137 |
138 | const expectedReporterOptions = {
139 | print: jasmine.any(Function),
140 | showColors: true,
141 | };
142 |
143 | expect(this.testJasmine.reporter_.setOptions).toHaveBeenCalledWith(expectedReporterOptions);
144 | });
145 | });
146 |
147 | describe('loading configurations', function () {
148 | beforeEach(function() {
149 | this.fixtureJasmine = makeRunner.call(this, {
150 | projectBaseDir: 'spec/fixtures/sample_project'
151 | });
152 | });
153 |
154 | describe('from an object', function () {
155 | beforeEach(function() {
156 | this.loader = this.fixtureJasmine.loader = jasmine.createSpyObj('loader', ['load']);
157 | });
158 |
159 | it('adds unique spec and helper files', function() {
160 | this.fixtureJasmine.loadConfig({
161 | spec_dir: 'spec',
162 | spec_files: [
163 | 'fixture_spec.js',
164 | '**/*spec.js'
165 | ],
166 | helpers: ["helper.js"]
167 | });
168 | expect(this.fixtureJasmine.specFiles).toEqual([
169 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js'),
170 | pathEndingWith('spec/fixtures/sample_project/spec/other_fixture_spec.js')
171 | ]);
172 | expect(this.fixtureJasmine.helperFiles).toEqual([
173 | pathEndingWith('spec/fixtures/sample_project/spec/helper.js'
174 | )]);
175 | });
176 |
177 | it('sets the spec dir to the provided value', function() {
178 | this.fixtureJasmine.loadConfig({spec_dir: 'spec'});
179 | expect(this.fixtureJasmine.specDir).toEqual('spec');
180 | });
181 |
182 | it('sets the spec dir to the empty string when unspecified', function() {
183 | this.fixtureJasmine.loadConfig({});
184 | expect(this.fixtureJasmine.specDir).toEqual('');
185 | });
186 |
187 | describe('with jsLoader: "require"', function () {
188 | it('tells the loader not to always import', async function() {
189 | this.fixtureJasmine.loadConfig({jsLoader: 'require'});
190 | expect(this.loader.alwaysImport).toBeFalse();
191 | });
192 | });
193 |
194 | describe('with jsLoader: "import"', function () {
195 | it('tells the loader to always import', async function() {
196 | this.fixtureJasmine.loadConfig({jsLoader: 'import'});
197 | expect(this.loader.alwaysImport).toBeTrue();
198 | });
199 | });
200 |
201 | describe('with jsLoader set to an invalid value', function () {
202 | it('throws an error', function() {
203 | expect(() => {
204 | this.fixtureJasmine.loadConfig({jsLoader: 'bogus'});
205 | }).toThrowError(/"bogus" is not a valid value/);
206 | });
207 | });
208 |
209 | describe('with jsLoader undefined', function () {
210 | it('tells the loader to always import', async function() {
211 | this.fixtureJasmine.loadConfig({});
212 | expect(this.loader.alwaysImport).toBeTrue();
213 | });
214 | });
215 |
216 | it('adds requires', function() {
217 | this.fixtureJasmine.loadConfig({
218 | spec_dir: 'spec',
219 | requires: ['ts-node/register']
220 | });
221 | expect(this.fixtureJasmine.requires).toEqual(['ts-node/register']);
222 | });
223 | });
224 |
225 | describe('from a file', function () {
226 | it('adds unique spec files', async function() {
227 | await this.fixtureJasmine.loadConfigFile('spec/support/jasmine_alternate.json');
228 | expect(this.fixtureJasmine.helperFiles).toEqual([
229 | pathEndingWith('spec/fixtures/sample_project/spec/helper.js')
230 | ]);
231 | expect(this.fixtureJasmine.requires).toEqual(['ts-node/register']);
232 | expect(this.fixtureJasmine.specFiles).toEqual([
233 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js'),
234 | pathEndingWith('spec/fixtures/sample_project/spec/other_fixture_spec.js')
235 | ]);
236 | });
237 |
238 | it('can use an ES module', async function() {
239 | await this.fixtureJasmine.loadConfigFile('spec/support/jasmine_alternate.mjs');
240 | expect(this.fixtureJasmine.helperFiles).toEqual([
241 | pathEndingWith('spec/fixtures/sample_project/spec/helper.js')
242 | ]);
243 | expect(this.fixtureJasmine.requires).toEqual(['ts-node/register']);
244 | expect(this.fixtureJasmine.specFiles).toEqual([
245 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js'),
246 | pathEndingWith('spec/fixtures/sample_project/spec/other_fixture_spec.js')
247 | ]);
248 | });
249 |
250 | it('can use a CommonJS module', async function() {
251 | await this.fixtureJasmine.loadConfigFile('spec/support/jasmine_alternate.cjs');
252 | expect(this.fixtureJasmine.helperFiles).toEqual([
253 | pathEndingWith('spec/fixtures/sample_project/spec/helper.js')
254 | ]);
255 | expect(this.fixtureJasmine.requires).toEqual(['ts-node/register']);
256 | expect(this.fixtureJasmine.specFiles).toEqual([
257 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js'),
258 | pathEndingWith('spec/fixtures/sample_project/spec/other_fixture_spec.js')
259 | ]);
260 | });
261 |
262 | it('loads the specified configuration file from an absolute path', async function() {
263 | const absoluteConfigPath = path.join(__dirname, 'fixtures/sample_project/spec/support/jasmine_alternate.json');
264 | await this.fixtureJasmine.loadConfigFile(absoluteConfigPath);
265 | expect(this.fixtureJasmine.helperFiles).toEqual([
266 | pathEndingWith('spec/fixtures/sample_project/spec/helper.js')
267 | ]);
268 | expect(this.fixtureJasmine.requires).toEqual(['ts-node/register']);
269 | expect(this.fixtureJasmine.specFiles).toEqual([
270 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js'),
271 | pathEndingWith('spec/fixtures/sample_project/spec/other_fixture_spec.js')
272 | ]);
273 | });
274 |
275 | it("throws an error if the specified configuration file doesn't exist", async function() {
276 | await expectAsync(this.fixtureJasmine.loadConfigFile('missing.json')).toBeRejected();
277 | });
278 |
279 | it("does not throw if the default configuration files don't exist", async function() {
280 | this.fixtureJasmine.projectBaseDir += '/missing';
281 | await expectAsync(this.fixtureJasmine.loadConfigFile()).toBeResolved();
282 | });
283 |
284 | describe('When the default .mjs configuration file exists', function() {
285 | it('loads the default .mjs configuration file', async function() {
286 | const config = require('./fixtures/sample_project/spec/support/jasmine.json');
287 | spyOn(Loader.prototype, 'load')
288 | .withArgs(jasmine.stringMatching(/jasmine\.mjs$/))
289 | .and.returnValue(Promise.resolve(config));
290 |
291 | await this.fixtureJasmine.loadConfigFile();
292 |
293 | expect(Loader.prototype.load).toHaveBeenCalledWith(jasmine.stringMatching(
294 | 'jasmine\.mjs$'
295 | ));
296 | expect(this.fixtureJasmine.specFiles).toEqual([
297 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js')
298 | ]);
299 | });
300 |
301 | it('does not also load the default .js or .json configuration files', async function() {
302 | spyOn(Loader.prototype, 'load')
303 | .withArgs(jasmine.stringMatching(/jasmine\.mjs$/))
304 | .and.returnValue(Promise.resolve({}));
305 |
306 | await this.fixtureJasmine.loadConfigFile();
307 |
308 | expect(Loader.prototype.load).not.toHaveBeenCalledWith(jasmine.stringMatching(
309 | 'jasmine\.js$'
310 | ));
311 | expect(Loader.prototype.load).not.toHaveBeenCalledWith(jasmine.stringMatching(
312 | 'jasmine\.json$'
313 | ));
314 | });
315 | });
316 |
317 | describe('When the default .mjs configuration file does not exist', function() {
318 | it('loads the default .json configuration file', async function () {
319 | await this.fixtureJasmine.loadConfigFile();
320 | expect(this.fixtureJasmine.specFiles).toEqual([
321 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js')
322 | ]);
323 | });
324 |
325 | it('loads the default .js configuration file', async function () {
326 | const config = require('./fixtures/sample_project/spec/support/jasmine.json');
327 | spyOn(Loader.prototype, 'load').and.callFake(function (path) {
328 | if (path.endsWith('jasmine.js')) {
329 | return Promise.resolve(config);
330 | } else {
331 | const e = new Error(`Module not found: ${path}`);
332 | e.code = 'MODULE_NOT_FOUND';
333 | return Promise.reject(e);
334 | }
335 | });
336 |
337 | await this.fixtureJasmine.loadConfigFile();
338 | expect(Loader.prototype.load).toHaveBeenCalledWith(jasmine.stringMatching(
339 | 'jasmine\.js$'
340 | ));
341 | expect(this.fixtureJasmine.specFiles).toEqual([
342 | pathEndingWith('spec/fixtures/sample_project/spec/fixture_spec.js')
343 | ]);
344 | });
345 |
346 | it('warns if default .js and .json config files are both found', async function () {
347 | spyOn(Loader.prototype, 'load').and.callFake(function (path) {
348 | if (path.endsWith('jasmine.js') || path.endsWith('jasmine.json')) {
349 | return Promise.resolve({});
350 | } else {
351 | const e = new Error(`Module not found: ${path}`);
352 | e.code = 'MODULE_NOT_FOUND';
353 | return Promise.reject(e);
354 | }
355 | });
356 | spyOn(console, 'warn');
357 |
358 | await this.fixtureJasmine.loadConfigFile();
359 |
360 | expect(console.warn).toHaveBeenCalledWith(
361 | 'Deprecation warning: Jasmine found and loaded both jasmine.js ' +
362 | 'and jasmine.json\nconfig files. In a future version, only the ' +
363 | 'first file found will be loaded.'
364 | );
365 | });
366 | });
367 | });
368 | });
369 |
370 | describe('#execute', function() {
371 | it('uses the default console reporter if no reporters were added', async function () {
372 | spyOn(this.testJasmine, 'configureDefaultReporter');
373 |
374 | await this.execute();
375 |
376 | expect(this.testJasmine.configureDefaultReporter).toHaveBeenCalledWith({
377 | showColors: true,
378 | alwaysListPendingSpecs: true
379 | });
380 | });
381 |
382 | it('configures the default console reporter with the right color settings', async function() {
383 | spyOn(this.testJasmine, 'configureDefaultReporter');
384 | this.testJasmine.showColors(false);
385 | this.testJasmine.alwaysListPendingSpecs(false);
386 |
387 | await this.execute();
388 |
389 | expect(this.testJasmine.configureDefaultReporter).toHaveBeenCalledWith({
390 | showColors: false,
391 | alwaysListPendingSpecs: false
392 | });
393 | });
394 |
395 | it('does not configure the default reporter if this was already done', async function() {
396 | this.testJasmine.configureDefaultReporter({showColors: false});
397 |
398 | spyOn(this.testJasmine, 'configureDefaultReporter');
399 |
400 | await this.execute();
401 |
402 | expect(this.testJasmine.configureDefaultReporter).not.toHaveBeenCalled();
403 | });
404 |
405 | describe('completion behavior', function() {
406 | beforeEach(function() {
407 | spyOn(this.testJasmine, 'exit');
408 | });
409 |
410 | describe('default', function() {
411 | it('exits successfully when the whole suite is green', async function () {
412 | await this.execute({overallStatus: 'passed'});
413 | expect(this.testJasmine.exit).toHaveBeenCalledWith(0);
414 | });
415 |
416 | it('exits with a distinct status code when anything in the suite is not green', async function () {
417 | await this.execute({overallStatus: 'failed'});
418 | expect(this.testJasmine.exit).toHaveBeenCalledWith(3);
419 | });
420 |
421 | it('exits with a distinct status code when anything in the suite is focused', async function() {
422 | await this.execute({overallStatus: 'incomplete'});
423 | expect(this.testJasmine.exit).toHaveBeenCalledWith(2);
424 | });
425 | });
426 |
427 | describe('When exitOnCompletion is set to false', function() {
428 | it('does not exit', async function() {
429 | this.testJasmine.exitOnCompletion = false;
430 | await this.execute();
431 | expect(this.testJasmine.exit).not.toHaveBeenCalled();
432 | });
433 | });
434 | });
435 | });
436 | });
437 | }
438 |
439 | function pathEndingWith(suffix) {
440 | // Match glob output from either Windows or other OSes.
441 | const pattern = '(^|[\\/\\\\])' + suffix.replace(/\//g, '[\\/\\\\]') + '$';
442 | return jasmine.stringMatching(new RegExp(pattern));
443 | }
444 |
445 | module.exports = {sharedRunnerBehaviors, pathEndingWith};
446 |
--------------------------------------------------------------------------------
/spec/support/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "*[sS]pec.js",
5 | "reporters/**/*[sS]pec.js",
6 | "filters/**/*[sS]pec.js"
7 | ],
8 | "helpers": [
9 | "helpers/**/*.js"
10 | ],
11 | "random": true,
12 | "alwaysListPendingSpecs": false
13 | }
14 |
--------------------------------------------------------------------------------