├── .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 | --------------------------------------------------------------------------------