pax_global_header00006660000000000000000000000064141641363610014517gustar00rootroot0000000000000052 comment=98c2f019c6a523d6b40cd4f7e466c9543fdc1fa8 jasmine-4.0.0/000077500000000000000000000000001416413636100131465ustar00rootroot00000000000000jasmine-4.0.0/.circleci/000077500000000000000000000000001416413636100150015ustar00rootroot00000000000000jasmine-4.0.0/.circleci/config.yml000066400000000000000000000117531416413636100170000ustar00rootroot00000000000000# Run tests against supported Node versions, and (except for pull requests) # against supported browsers. version: 2.1 orbs: node: circleci/node@3.0.0 executors: node16: docker: - image: cimg/node:16.1.0-browsers working_directory: ~/workspace node14: docker: - image: circleci/node:14 working_directory: ~/workspace node12_latest: docker: - image: circleci/node:12 working_directory: ~/workspace node12_17: docker: - image: circleci/node:12.17 working_directory: ~/workspace jobs: build: parameters: executor: type: executor executor: << parameters.executor >> steps: - checkout - run: name: Report Node and NPM versions command: echo "Using Node $(node --version) and NPM $(npm --version)" - run: name: Install dependencies command: npm install - run: name: Build command: npm run build - persist_to_workspace: root: . paths: - . test_node: &test_node parameters: executor: type: executor executor: << parameters.executor >> steps: - attach_workspace: at: . - run: name: Run tests command: npm test test_browsers: &test_browsers executor: node14 environment: SKIP_JASMINE_BROWSER_FLAKES: "true" steps: - attach_workspace: at: . - run: name: Install Sauce Connect command: | cd /tmp curl https://saucelabs.com/downloads/sc-4.6.4-linux.tar.gz | tar zxf - chmod +x sc-4.6.4-linux/bin/sc mkdir ~/workspace/bin cp sc-4.6.4-linux/bin/sc ~/workspace/bin ~/workspace/bin/sc --version - run: name: Run tests command: | # Do everything in one step because Sauce Connect won't exit # cleanly if we kill it from a different step than it started in. export PATH=$PATH:$HOME/workspace/bin export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_BUILD_NUM scripts/start-sauce-connect sauce-pidfile set +o errexit scripts/run-all-browsers exitcode=$? set -o errexit scripts/stop-sauce-connect $(cat sauce-pidfile) exit $exitcode test_browser_flakes: <<: *test_browsers environment: SKIP_JASMINE_BROWSER_FLAKES: "false" workflows: version: 2 cron: triggers: - schedule: # Times are UTC. cron: "0 11 * * *" filters: branches: only: - main - "3.99" - "4.0" jobs: - build: executor: node16 name: build_node_16 - build: executor: node14 name: build_node_14 - build: executor: node12_latest name: build_node_12_latest - build: executor: node12_17 name: build_node_12_17 - test_node: executor: node16 name: test_node_16 requires: - build_node_16 - test_node: executor: node12_latest name: test_node_12_latest requires: - build_node_12_latest - test_node: executor: node12_17 name: test_node_12_17 requires: - build_node_12_17 - test_browsers: requires: - build_node_14 filters: branches: ignore: /pull\/.*/ # Don't run on pull requests. push: jobs: - build: executor: node16 name: build_node_16 - build: executor: node14 name: build_node_14 - build: executor: node12_latest name: build_node_12_latest - build: executor: node12_17 name: build_node_12_17 - test_node: executor: node16 name: test_node_16 requires: - build_node_16 - test_node: executor: node14 name: test_node_14 requires: - build_node_14 - test_node: executor: node12_latest name: test_node_12_latest requires: - build_node_12_latest - test_node: executor: node12_17 name: test_node_12_17 requires: - build_node_12_17 - test_browsers: requires: - build_node_14 filters: branches: ignore: /pull\/.*/ # Don't run on pull requests. browser-flakes: triggers: - schedule: # Times are UTC. cron: "0 10 * * *" filters: branches: only: - browser-flakes jobs: - build: executor: node14 name: build_node_14 - test_browser_flakes: requires: - build_node_14 filters: branches: ignore: /pull\/.*/ # Don't run on pull requests. jasmine-4.0.0/.editorconfig000066400000000000000000000001771416413636100156300ustar00rootroot00000000000000[*] charset = utf-8 end_of_line = lf insert_final_newline = true [*.{js, json, sh, yml}] indent_style = space indent_size = 2 jasmine-4.0.0/.gitattributes000066400000000000000000000000371416413636100160410ustar00rootroot00000000000000* text=auto eol=lf *.png -text jasmine-4.0.0/.github/000077500000000000000000000000001416413636100145065ustar00rootroot00000000000000jasmine-4.0.0/.github/CONTRIBUTING.md000066400000000000000000000124401416413636100167400ustar00rootroot00000000000000# Developing for Jasmine Core We welcome your contributions! Thanks for helping make Jasmine a better project for everyone. Please review the backlog and discussion lists before starting work. What you're looking for may already have been done. If it hasn't, the community can help make your contribution better. If you want to contribute but don't know what to work on, [issues tagged help needed](https://github.com/jasmine/jasmine/labels/help%20needed) should have enough detail to get started. ## Links - [Jasmine Google Group](http://groups.google.com/group/jasmine-js) - [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev) - [Jasmine backlog](https://www.pivotaltracker.com/n/projects/10606) ## Before Submitting a Pull Request 1. Ensure all specs are green in browsers *and* node. * Use `npm test` to test in Node. * Use `npm run serve` to test in browsers. 2. Fix any eslint or prettier errors reported at the end of `npm test`. Prettier errors can be automatically fixed by running `npm run cleanup`. 3. Build `jasmine.js` with `npm run build` and run all specs again. This ensures that your changes self-test well. 5. Revert your changes to `jasmine.js` and `jasmine-html.js`. When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master. We only accept green pull requests. If you see that the CI build failed, please fix it. Feel free to ask for help if you're stuck. ## Background ### Directory Structure * `/src` contains all of the source files * `/src/core` - generic source files * `/src/html` - browser-specific files * `/src/boot` - sources for boot files (see below) * `/spec` contains all of the tests * mirrors the source directory * there are some additional files * `/lib` contains the compiled copy of Jasmine. This is used to self-test and distributed as the `jasmine-core` Node, and Ruby packages. ### Self-testing Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test. The tests should always use `jasmineUnderTest` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa. ### `boot0.js` and `boot1.js` These files file does all of the setup necessary for Jasmine to work in a browser. They load all of the code, create an `Env`, attach the global functions, and build the reporter. It also sets up the execution of the `Env` - for browsers this is in `window.onload`. While the default in `lib` is appropriate for browsers, projects may wish to customize this file. ### Compatibility Jasmine runs in both Node and a variety of browsers. See the README for the list of currently supported environments. ## Development All source code belongs in `src/`. The `core/` directory contains the bulk of Jasmine's functionality. This code should remain browser- and environment-agnostic. If your feature or fix cannot be, as mentioned above, please degrade gracefully. Any code that depends on a browser (specifically, it expects `window` to be the global or `document` is present) should live in `src/html/`. ### Install Dev Dependencies Jasmine Core relies on Node.js. To install the Node dependencies, you will need Node.js and npm. $ npm install ...will install all of the node modules locally. Now run $ npm test ...you should see tests run and eslint checking formatting. ### How to write new Jasmine code Or, How to make a successful pull request * _Do not change the public interface_. Lots of projects depend on Jasmine and if you aren't careful you'll break them. * _Be environment agnostic_. Some people run their specs in browsers, others in Node. Jasmine should support them all as much as possible. * _Be browser agnostic_ - if you must rely on browser-specific functionality, please write it in a way that degrades gracefully. * _Write specs_ - Jasmine's a testing framework. Don't add functionality without test-driving it. * _Write code in the style of the rest of the repo_ - Jasmine should look like a cohesive whole. Key exceptions: * Use `const` or `let` for new variable declarations, even if nearby code uses `var`. * New async specs should usually be async/await or promise-returning, not callback based. * _Ensure the *entire* test suite is green_ in all the big browsers, Node, and ESLint/Prettier. Your contribution shouldn't break Jasmine for other users. Follow these tips and your pull request, patch, or suggestion is much more likely to be integrated. ### Running Specs Be sure to run the tests in at least one supported Node version and at least a couple of supported browsers. To run the tests in Node, simply use `npm test` as described above. To run the tests in a browser, run `npm run serve` and then visit `http://localhost:8888`. If you have the necessary Selenium drivers installed (e.g. geckodriver or chromedriver), you can also use Jasmine's CI tooling: $ JASMINE_BROWSER= npm run ci jasmine-4.0.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000043471416413636100172230ustar00rootroot00000000000000## Are you creating an issue in the correct repository? - When in doubt, create an issue here. - If you have an issue with the Jasmine docs, file an issue in the docs repo here: https://github.com/jasmine/jasmine.github.io - If you have an issue with TypeScript typings, start a discussion at [DefinitelyTpyed](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/new?category=issues-with-a-types-package) - This repository is for the core Jasmine framework - If you are using a test runner that wraps Jasmine, consider filing an issue with that library if appropriate: - [Jasmine npm](https://github.com/jasmine/jasmine-npm/issues) - [Jasmine browser runner](https://github.com/jasmine/jasmine-browser/issues) - [Jasmine gem](https://github.com/jasmine/jasmine-gem/issues) - [Jasmine py](https://github.com/jasmine/jasmine-py/issues) - [Gulp Jasmine Browser](https://github.com/jasmine/gulp-jasmine-browser/issues) - [Karma](https://github.com/karma-runner/karma/issues) - [Grunt Contrib Jasmine](https://github.com/gruntjs/grunt-contrib-jasmine/issues) ## Expected Behavior ## Current Behavior ## Possible Solution ## Suite that reproduces the behavior (for bugs) ```javascript describe("sample", function() { }); ``` ## Context ## Your Environment * Version used: * Environment name and version (e.g. Chrome 39, node.js 5.4): * Operating System and version (desktop or mobile): * Link to your project: jasmine-4.0.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000026211416413636100203100ustar00rootroot00000000000000 ## Description ## Motivation and Context ## How Has This Been Tested? ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have read the [**CONTRIBUTING**](https://github.com/jasmine/jasmine/blob/main/.github/CONTRIBUTING.md) guide. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. jasmine-4.0.0/.gitignore000066400000000000000000000004001416413636100151300ustar00rootroot00000000000000.idea/ .svn/ .DS_Store site/ .bundle/ .pairs .rvmrc .ruby-gemset .ruby-version *.gem .bundle tags Gemfile.lock package-lock.json yarn.lock pkg/* .sass-cache/* src/html/.sass-cache/* node_modules/ sauce_connect.log *.swp build/ dist nbproject/ *.iml .envrc jasmine-4.0.0/CODE_OF_CONDUCT.md000066400000000000000000000062411416413636100157500ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge 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. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities 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. 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. ## Scope 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. ## Enforcement 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. 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. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ jasmine-4.0.0/Gruntfile.js000066400000000000000000000035071416413636100154500ustar00rootroot00000000000000module.exports = function(grunt) { var pkg = require("./package.json"); global.jasmineVersion = pkg.version; grunt.initConfig({ pkg: pkg, concat: require('./grunt/config/concat.js'), sass: require('./grunt/config/sass.js'), compress: require('./grunt/config/compress.js'), cssUrlEmbed: require('./grunt/config/cssUrlEmbed.js') }); require('load-grunt-tasks')(grunt); grunt.loadTasks('grunt/tasks'); grunt.registerTask('default', ['sass:dist', "cssUrlEmbed"]); grunt.registerTask('buildDistribution', 'Builds and lints jasmine.js, jasmine-html.js, jasmine.css', [ 'sass:dist', "cssUrlEmbed", 'concat' ] ); grunt.registerTask("execSpecsInNode", "Run Jasmine core specs in Node.js", function() { verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals()); const done = this.async(), Jasmine = require('jasmine'), jasmineCore = require('./lib/jasmine-core.js'), jasmine = new Jasmine({jasmineCore: jasmineCore}); jasmine.loadConfigFile('./spec/support/jasmine.json'); jasmine.exitOnCompletion = false; jasmine.execute().then( result => done(result.overallStatus === 'passed'), err => { console.error(err); exit(1); } ); } ); grunt.registerTask("execSpecsInNode:performance", "Run Jasmine performance specs in Node.js", function() { require("shelljs").exec("node_modules/.bin/jasmine JASMINE_CONFIG_PATH=spec/support/jasmine-performance.json"); } ); }; function verifyNoGlobals(fn) { const initialGlobals = Object.keys(global); fn(); const extras = Object.keys(global).filter(k => !initialGlobals.includes(k)); if (extras.length !== 0) { throw new Error('Globals were unexpectedly created: ' + extras.join(', ')); } } jasmine-4.0.0/MIT.LICENSE000066400000000000000000000020451416413636100146040ustar00rootroot00000000000000Copyright (c) 2008-2019 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jasmine-4.0.0/README.md000066400000000000000000000112531416413636100144270ustar00rootroot00000000000000[](http://jasmine.github.io) [![Build Status](https://circleci.com/gh/jasmine/jasmine.svg?style=shield)](https://circleci.com/gh/jasmine/jasmine) [![Open Source Helpers](https://www.codetriage.com/jasmine/jasmine/badges/users.svg)](https://www.codetriage.com/jasmine/jasmine) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_shield) # A JavaScript Testing Framework Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run. Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/) For a quick start guide of Jasmine, see the beginning of [http://jasmine.github.io/edge/introduction.html](http://jasmine.github.io/edge/introduction.html). Upgrading from Jasmine 3.x? Check out the 4.0 release notes for a list of what's new (including breaking changes). You can also read the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0). ## Contributing Please read the [contributors' guide](https://github.com/jasmine/jasmine/blob/main/.github/CONTRIBUTING.md). ## Installation For the Jasmine NPM module:
[https://github.com/jasmine/jasmine-npm](https://github.com/jasmine/jasmine-npm). For the Jasmine browser runner:
[https://github.com/jasmine/jasmine-browser](https://github.com/jasmine/jasmine-browser). To install Jasmine standalone on your local box (where **_{#.#.#}_** below is substituted by the release number downloaded): * Download the standalone distribution for your desired release from the [releases page](https://github.com/jasmine/jasmine/releases). * Create a Jasmine directory in your project. - `mkdir my-project/jasmine` * Move the dist to your project directory. - `mv jasmine/dist/jasmine-standalone-{#.#.#}.zip my-project/jasmine` * Change directory. - `cd my-project/jasmine` * Unzip the dist. - `unzip jasmine-standalone-{#.#.#}.zip` Add the following to your HTML file: ```html ``` ## Supported environments Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and Microsoft Edge) as well as nodejs. | Environment | Supported versions | |-------------------|--------------------| | Node | 12.17+, 14, 16 | | Safari | 14-15 | | Chrome | Evergreen | | Firefox | Evergreen, 91 | | Edge | Evergreen | For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work. However, Jasmine isn't tested against them and they aren't actively supported. See the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes) for the supported environments for each Jasmine release. ## Support * Search past discussions: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js). * Send an email to the list: [jasmine-js@googlegroups.com](mailto:jasmine-js@googlegroups.com). * View the project backlog at Pivotal Tracker: [http://www.pivotaltracker.com/projects/10606](http://www.pivotaltracker.com/projects/10606). * Follow us on Twitter: [@JasmineBDD](http://twitter.com/JasmineBDD). ## Maintainers * [Gregg Van Hove](mailto:gvanhove@pivotal.io), Pivotal Labs ### Maintainers Emeritus * [Davis W. Frank](mailto:dwfrank@pivotal.io), Pivotal Labs * [Rajan Agaskar](mailto:rajan@pivotal.io), Pivotal Labs * [Greg Cobb](mailto:gcobb@pivotal.io), Pivotal Labs * [Chris Amavisca](mailto:camavisca@pivotal.io), Pivotal Labs * [Christian Williams](mailto:antixian666@gmail.com), Cloud Foundry * Sheel Choksi Copyright (c) 2008-2018 Pivotal Labs. This software is licensed under the MIT License. ## License [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_large) jasmine-4.0.0/RELEASE.md000066400000000000000000000060231416413636100145510ustar00rootroot00000000000000# How to work on a Jasmine Release ## Development ___Jasmine Core Maintainers Only___ Follow the instructions in `CONTRIBUTING.md` during development. ### Git Rules Please attempt to keep commits to `main` small, but cohesive. If a feature is contained in a bunch of small commits (e.g., it has several wip commits or small work), please squash them when pushing to `main`. ### Version We attempt to stick to [Semantic Versioning](http://semver.org/). Most of the time, development should be against a new minor version - fixing bugs and adding new features that are backwards compatible. The current version lives in the file `/package.json`. This version will be copied to `jasmine.js` when the distribution is built. When releasing a new version, update `package.json` with the new version and `npm run build` to update the gem version number. Note that Jasmine should only use the "patch" version number in the following cases: * Changes related to packaging for a specific binding library (npm or browser-runner) * Fixes for regressions. When jasmine-core revs its major or minor version, the binding libraries should also rev to that version. ## Release When ready to release - specs are all green and the stories are done: 1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly. Include a list of supported environments. 1. Update the version in `package.json` 1. Run `npm run build`. ### Commit and push core changes 1. Run the browser tests using `scripts/run-all-browsers`. 1. Commit release notes and version changes (jasmine.js, version.rb, package.json) 1. Push 1. Wait for Circle CI to go green ### Build standalone distribution 1. Build the standalone distribution with `grunt buildStandaloneDist` 1. This will generate `dist/jasmine-standalone-.zip`, which you will upload later (see "Finally" below). ### Release the core NPM module 1. Run the tests on Windows. (CI only tests on Linux.) 1. `npm adduser` to save your credentials locally 1. `npm publish .` to publish what's in `package.json` ### Release the docs Probably only need to do this when releasing a minor version, and not a patch version. 1. `rake update_edge_jasmine` 1. `npm run jsdoc` 1. `rake release[${version}]` to copy the current edge docs to the new version 1. Commit and push. ### Release the binding libraries #### NPM 1. Create release notes using Anchorman as above 1. In `package.json`, update both the package version and the jasmine-core dependency version 1. Commit and push. 1. Wait for Circle CI to go green again. 1. Run the tests on Windows locally. 1. `grunt release `. (Note: This will publish the package by running `npm publish`.) ### Finally For each of the above GitHub repos: 1. Visit the releases page and find the tag just published. 1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes. 1. If it is a pre-release, mark it as such. 1. For core, attach the standalone zipfile. jasmine-4.0.0/grunt/000077500000000000000000000000001416413636100143055ustar00rootroot00000000000000jasmine-4.0.0/grunt/config/000077500000000000000000000000001416413636100155525ustar00rootroot00000000000000jasmine-4.0.0/grunt/config/compress.js000066400000000000000000000024321416413636100177440ustar00rootroot00000000000000var standaloneLibDir = "lib/jasmine-" + jasmineVersion; function root(path) { return "./" + path; } function libJasmineCore(path) { return root("lib/jasmine-core/" + path); } function dist(path) { return root("dist/" + path); } module.exports = { standalone: { options: { archive: root("dist/jasmine-standalone-" + global.jasmineVersion + ".zip") }, files: [ { src: [ root("MIT.LICENSE") ] }, { src: [ "jasmine_favicon.png"], dest: standaloneLibDir, expand: true, cwd: root("images") }, { src: [ "jasmine.js", "jasmine-html.js", "jasmine.css" ], dest: standaloneLibDir, expand: true, cwd: libJasmineCore("") }, { src: [ "boot0.js", "boot1.js" ], dest: standaloneLibDir, expand: true, cwd: libJasmineCore("") }, { src: [ "SpecRunner.html" ], dest: root(""), expand: true, cwd: dist("tmp") }, { src: [ "*.js" ], dest: "src", expand: true, cwd: libJasmineCore("example/src/") }, { src: [ "*.js" ], dest: "spec", expand: true, cwd: libJasmineCore("example/spec/") } ] } }; jasmine-4.0.0/grunt/config/concat.js000066400000000000000000000025421416413636100173620ustar00rootroot00000000000000var grunt = require('grunt'); function license() { var currentYear = "" + new Date(Date.now()).getFullYear(); return grunt.template.process( grunt.file.read("grunt/templates/licenseBanner.js.jst"), { data: { currentYear: currentYear}}); } module.exports = { 'jasmine-html': { src: [ 'src/html/requireHtml.js', 'src/html/HtmlReporter.js', 'src/html/HtmlSpecFilter.js', 'src/html/ResultsNode.js', 'src/html/QueryString.js', 'src/html/**/*.js' ], dest: 'lib/jasmine-core/jasmine-html.js' }, jasmine: { src: [ 'src/core/requireCore.js', 'src/core/matchers/requireMatchers.js', 'src/core/base.js', 'src/core/util.js', 'src/core/Spec.js', 'src/core/Order.js', 'src/core/Env.js', 'src/core/JsApiReporter.js', 'src/core/PrettyPrinter', 'src/core/Suite', 'src/core/**/*.js', 'src/version.js' ], dest: 'lib/jasmine-core/jasmine.js' }, boot0: { src: ['src/boot/boot0.js'], dest: 'lib/jasmine-core/boot0.js' }, boot1: { src: ['src/boot/boot1.js'], dest: 'lib/jasmine-core/boot1.js' }, nodeBoot: { src: ['src/boot/node_boot.js'], dest: 'lib/jasmine-core/node_boot.js' }, options: { banner: license(), process: { data: { version: global.jasmineVersion } } } }; jasmine-4.0.0/grunt/config/cssUrlEmbed.js000066400000000000000000000002131416413636100203140ustar00rootroot00000000000000module.exports = { encodeWithBaseDir: { files: { "lib/jasmine-core/jasmine.css": ["lib/jasmine-core/jasmine.css"] } } }; jasmine-4.0.0/grunt/config/sass.js000066400000000000000000000003321416413636100170570ustar00rootroot00000000000000const sass = require('sass'); module.exports = { options: { implementation: sass, sourceComments: false }, dist: { files: { "lib/jasmine-core/jasmine.css": "src/html/jasmine.scss" } } }; jasmine-4.0.0/grunt/tasks/000077500000000000000000000000001416413636100154325ustar00rootroot00000000000000jasmine-4.0.0/grunt/tasks/build_standalone.js000066400000000000000000000015461416413636100213050ustar00rootroot00000000000000var grunt = require("grunt"); function standaloneTmpDir(path) { return "dist/tmp/" + path; } grunt.registerTask("build:compileSpecRunner", "Processes the spec runner template and writes to a tmp file", function() { var runnerHtml = grunt.template.process( grunt.file.read("grunt/templates/SpecRunner.html.jst"), { data: { jasmineVersion: global.jasmineVersion }}); grunt.file.write(standaloneTmpDir("SpecRunner.html"), runnerHtml); } ); grunt.registerTask("build:cleanSpecRunner", "Deletes the tmp spec runner file", function() { grunt.file.delete(standaloneTmpDir("")); } ); grunt.registerTask("buildStandaloneDist", "Builds a standalone distribution", [ "buildDistribution", "build:compileSpecRunner", "compress:standalone", "build:cleanSpecRunner" ] ); jasmine-4.0.0/grunt/templates/000077500000000000000000000000001416413636100163035ustar00rootroot00000000000000jasmine-4.0.0/grunt/templates/SpecRunner.html.jst000066400000000000000000000016561416413636100220640ustar00rootroot00000000000000 Jasmine Spec Runner v<%= jasmineVersion %> jasmine-4.0.0/grunt/templates/licenseBanner.js.jst000066400000000000000000000020711416413636100222100ustar00rootroot00000000000000/* Copyright (c) 2008-<%= currentYear %> Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ jasmine-4.0.0/images/000077500000000000000000000000001416413636100144135ustar00rootroot00000000000000jasmine-4.0.0/images/jasmine-horizontal.png000066400000000000000000000032621416413636100207410ustar00rootroot00000000000000PNG  IHDRZvPLTEU@3UI@9MF@;ID@DB@DB@>;A@CA@>C@>@CBA@CBA@@BA@BA@@BAA@BA@A@B@@CBA@A@@BA@A@BBA@BB@BAA@BABAA@BAA@BAABABABAA@BA@AAAAAABAAAAAABAAAAAA@BAAB@AAA@AAA@AAAAAA@AABAAABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA :DtRNS  "#$%''(*+,-.01456789:;<<>?@BCDHIJKLMNPSTUWXXYZ[^_`abcfghijklmopqrstvxyz{|}~ApIDATx^WSu`l8nU T2 -CVVQjYE(tetD@Z a{G_:ι/y}?`U'۝;oS<с8\zA ([ YmiW<+B*;Jߨk7*K&9/FS~tp >&5OILuHLX8?:ڊ0M'^2&S^b9Rβ#%W){jlaGkt_{-k?~߶!6=0<WInBV#,7|4]9Ғ6e_cR=WPMl4mհ9䗫^"EjV1wDة#R%e=HZwѯmS9z}a-`~T= meX3kkAKEÛ5J{s^eL) ]~?HЯV%pFo]ldb`T|wPځK=yNqzxto %6ޣ;M) i+҂ohH*)n>9'i.vWD٨MNptFeǾcC/iùq^W^x1Є vkcjUҊj ҌؑN/ɓ ð:̒j7=,6ɐYr%ݴš͗}[&w?{UIENDB`jasmine-4.0.0/images/jasmine-horizontal.svg000066400000000000000000000212021416413636100207460ustar00rootroot00000000000000 image/svg+xmljasmine-4.0.0/images/jasmine_favicon.png000066400000000000000000000027161416413636100202620ustar00rootroot00000000000000PNG  IHDR DOPLTEU@fUI`M]UN[UPZQUQYURURXURXUSSUSWSQUSSUSRUSRTRTRUTRUTUTSUSTSUTSUTUTSUTSUTSUSUTSUTTSUTSSTTTTUTTUTSTTSTTSTTSTSTSTTSTTSTSTTSTTSTSTTSUTTUTTUTTUTUTTUTTUTUTUTTUTTUTUUTSTTSTTSTSTTTTTTTTTTTTTTTTTTTTTTTTT0tRNS  !"%'()+,-.1345678:;=>?@ABCEFGHJLMNOPTUWXYZ[\]^_`bcdefgjklmnqstwz{|}~XFjIDATx^m[QTSFEZdD=$;B {!;DDv(% R 9\J9:s~{mS;'ZP F-+r%33U( Uu@[v)wy4jCeR Tzds? d.ɶ *% yX$ˠv(A)Sy9B A[pJ~ewe$t^H=B&rLp0H'P2X,G-# UNF'tts ,0KP"/$IrO?dIZOSe$/%4=%[JX^N4QZdb݃9{ ̓/| TѲC*ʅnRt0?XD`o,wIsܟ`Usc -YT:HHթx#)@^^ vΛΑk|IqW@}[@ g p"H lzVeeeL~ |LQ"[Ven܄q(PJoųeK# nW[NtXZ,u[{IENDB`jasmine-4.0.0/lib/000077500000000000000000000000001416413636100137145ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core.js000066400000000000000000000037411416413636100166330ustar00rootroot00000000000000/** * Note: Only available on Node. * @module jasmine-core */ const jasmineRequire = require('./jasmine-core/jasmine.js'); module.exports = jasmineRequire; /** * Boots a copy of Jasmine and returns an object as described in {@link jasmine}. * @type {function} * @return {jasmine} */ module.exports.boot = require('./jasmine-core/node_boot.js'); /** * Boots a copy of Jasmine and returns an object containing the properties * that would normally be added to the global object. If noGlobals is called * multiple times, the same object is returned every time. * * Do not call boot() if you also call noGlobals(). * * @example * const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals(); */ module.exports.noGlobals = (function() { let jasmineInterface; return function bootWithoutGlobals() { if (!jasmineInterface) { const jasmine = jasmineRequire.core(jasmineRequire); const env = jasmine.getEnv({ suppressLoadErrors: true }); jasmineInterface = jasmineRequire.interface(jasmine, env); } return jasmineInterface; }; }()); var path = require('path'), fs = require('fs'); var rootPath = path.join(__dirname, "jasmine-core"), bootFiles = ['boot0.js', 'boot1.js'], legacyBootFiles = ['boot.js'], nodeBootFiles = ['node_boot.js'], cssFiles = [], jsFiles = [], jsFilesToSkip = ['jasmine.js'].concat(bootFiles, legacyBootFiles, nodeBootFiles); fs.readdirSync(rootPath).forEach(function(file) { if(fs.statSync(path.join(rootPath, file)).isFile()) { switch(path.extname(file)) { case '.css': cssFiles.push(file); break; case '.js': if (jsFilesToSkip.indexOf(file) < 0) { jsFiles.push(file); } break; } } }); module.exports.files = { path: rootPath, bootDir: rootPath, bootFiles: bootFiles, nodeBootFiles: nodeBootFiles, cssFiles: cssFiles, jsFiles: ['jasmine.js'].concat(jsFiles), imagesDir: path.join(__dirname, '../images') }; jasmine-4.0.0/lib/jasmine-core/000077500000000000000000000000001416413636100162705ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/boot0.js000066400000000000000000000052131416413636100176520ustar00rootroot00000000000000/* Copyright (c) 2008-2022 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** This file starts the process of "booting" Jasmine. It initializes Jasmine, makes its globals available, and creates the env. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project source files or spec files are loaded. */ (function() { var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); /** * ## Require & Instantiate * * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. */ var jasmine = jasmineRequire.core(jasmineRequire), global = jasmine.getGlobal(); global.jasmine = jasmine; /** * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. */ jasmineRequire.html(jasmine); /** * Create the Jasmine environment. This is used to run all specs in a project. */ var env = jasmine.getEnv(); /** * ## The Global Interface * * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. */ var jasmineInterface = jasmineRequire.interface(jasmine, env); /** * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. */ for (var property in jasmineInterface) { global[property] = jasmineInterface[property]; } })(); jasmine-4.0.0/lib/jasmine-core/boot1.js000066400000000000000000000106401416413636100176530ustar00rootroot00000000000000/* Copyright (c) 2008-2022 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** This file finishes 'booting' Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `boot0.js` but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. If a project is using Jasmine via the standalone distribution, this file can be customized directly. If you only wish to configure the Jasmine env, you can load another file that calls `jasmine.getEnv().configure({...})` after `boot0.js` is loaded and before this file is loaded. */ (function() { var env = jasmine.getEnv(); /** * ## Runner Parameters * * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. */ var queryString = new jasmine.QueryString({ getWindowLocation: function() { return window.location; } }); var filterSpecs = !!queryString.getParam('spec'); var config = { stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'), stopSpecOnExpectationFailure: queryString.getParam( 'stopSpecOnExpectationFailure' ), hideDisabled: queryString.getParam('hideDisabled') }; var random = queryString.getParam('random'); if (random !== undefined && random !== '') { config.random = random; } var seed = queryString.getParam('seed'); if (seed) { config.seed = seed; } /** * ## Reporters * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). */ var htmlReporter = new jasmine.HtmlReporter({ env: env, navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, getContainer: function() { return document.body; }, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, timer: new jasmine.Timer(), filterSpecs: filterSpecs }); /** * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. */ env.addReporter(jsApiReporter); env.addReporter(htmlReporter); /** * Filter which specs will be run by matching the start of the full name against the `spec` query param. */ var specFilter = new jasmine.HtmlSpecFilter({ filterString: function() { return queryString.getParam('spec'); } }); config.specFilter = function(spec) { return specFilter.matches(spec.getFullName()); }; env.configure(config); /** * ## Execution * * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. */ var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } htmlReporter.initialize(); env.execute(); }; })(); jasmine-4.0.0/lib/jasmine-core/example/000077500000000000000000000000001416413636100177235ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/000077500000000000000000000000001416413636100223635ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/lib/000077500000000000000000000000001416413636100231315ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/lib/jasmine_examples/000077500000000000000000000000001416413636100264555ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js000066400000000000000000000007301416413636100302470ustar00rootroot00000000000000function Player() { } Player.prototype.play = function(song) { this.currentlyPlayingSong = song; this.isPlaying = true; }; Player.prototype.pause = function() { this.isPlaying = false; }; Player.prototype.resume = function() { if (this.isPlaying) { throw new Error("song is already playing"); } this.isPlaying = true; }; Player.prototype.makeFavorite = function() { this.currentlyPlayingSong.persistFavoriteStatus(true); }; module.exports = Player; jasmine-4.0.0/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js000066400000000000000000000002561416413636100277240ustar00rootroot00000000000000function Song() { } Song.prototype.persistFavoriteStatus = function(value) { // something complicated throw new Error("not yet implemented"); }; module.exports = Song; jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/000077500000000000000000000000001416413636100233155ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/helpers/000077500000000000000000000000001416413636100247575ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/000077500000000000000000000000001416413636100303035ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/SpecHelper.js000066400000000000000000000004771416413636100327030ustar00rootroot00000000000000beforeEach(function () { jasmine.addMatchers({ toBePlaying: function () { return { compare: function (actual, expected) { var player = actual; return { pass: player.currentlyPlayingSong === expected && player.isPlaying } } }; } }); }); jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/jasmine_examples/000077500000000000000000000000001416413636100266415ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/node_example/spec/jasmine_examples/PlayerSpec.js000066400000000000000000000031561416413636100312530ustar00rootroot00000000000000describe("Player", function() { var Player = require('../../lib/jasmine_examples/Player'); var Song = require('../../lib/jasmine_examples/Song'); var player; var song; beforeEach(function() { player = new Player(); song = new Song(); }); it("should be able to play a Song", function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); //demonstrates use of custom matcher expect(player).toBePlaying(song); }); describe("when song has been paused", function() { beforeEach(function() { player.play(song); player.pause(); }); it("should indicate that the song is currently paused", function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); it("should be possible to resume", function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); }); }); // demonstrates use of spies to intercept and test method calls it("tells the current song if the user has made it a favorite", function() { spyOn(song, 'persistFavoriteStatus'); player.play(song); player.makeFavorite(); expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true); }); //demonstrates use of expected exceptions describe("#resume", function() { it("should throw an exception if song is already playing", function() { player.play(song); expect(function() { player.resume(); }).toThrowError("song is already playing"); }); }); }); jasmine-4.0.0/lib/jasmine-core/example/spec/000077500000000000000000000000001416413636100206555ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/spec/PlayerSpec.js000066400000000000000000000027701416413636100232700ustar00rootroot00000000000000describe("Player", function() { var player; var song; beforeEach(function() { player = new Player(); song = new Song(); }); it("should be able to play a Song", function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); //demonstrates use of custom matcher expect(player).toBePlaying(song); }); describe("when song has been paused", function() { beforeEach(function() { player.play(song); player.pause(); }); it("should indicate that the song is currently paused", function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); it("should be possible to resume", function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); }); }); // demonstrates use of spies to intercept and test method calls it("tells the current song if the user has made it a favorite", function() { spyOn(song, 'persistFavoriteStatus'); player.play(song); player.makeFavorite(); expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true); }); //demonstrates use of expected exceptions describe("#resume", function() { it("should throw an exception if song is already playing", function() { player.play(song); expect(function() { player.resume(); }).toThrowError("song is already playing"); }); }); }); jasmine-4.0.0/lib/jasmine-core/example/spec/SpecHelper.js000066400000000000000000000005001416413636100232400ustar00rootroot00000000000000beforeEach(function () { jasmine.addMatchers({ toBePlaying: function () { return { compare: function (actual, expected) { var player = actual; return { pass: player.currentlyPlayingSong === expected && player.isPlaying }; } }; } }); }); jasmine-4.0.0/lib/jasmine-core/example/src/000077500000000000000000000000001416413636100205125ustar00rootroot00000000000000jasmine-4.0.0/lib/jasmine-core/example/src/Player.js000066400000000000000000000006761416413636100223150ustar00rootroot00000000000000function Player() { } Player.prototype.play = function(song) { this.currentlyPlayingSong = song; this.isPlaying = true; }; Player.prototype.pause = function() { this.isPlaying = false; }; Player.prototype.resume = function() { if (this.isPlaying) { throw new Error("song is already playing"); } this.isPlaying = true; }; Player.prototype.makeFavorite = function() { this.currentlyPlayingSong.persistFavoriteStatus(true); }; jasmine-4.0.0/lib/jasmine-core/example/src/Song.js000066400000000000000000000002261416413636100217560ustar00rootroot00000000000000function Song() { } Song.prototype.persistFavoriteStatus = function(value) { // something complicated throw new Error("not yet implemented"); }; jasmine-4.0.0/lib/jasmine-core/jasmine-html.js000066400000000000000000000662241416413636100212300ustar00rootroot00000000000000/* Copyright (c) 2008-2022 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); jasmineRequire.html = function(j$) { j$.ResultsNode = jasmineRequire.ResultsNode(); j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); j$.QueryString = jasmineRequire.QueryString(); j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); }; jasmineRequire.HtmlReporter = function(j$) { function ResultsStateBuilder() { this.topResults = new j$.ResultsNode({}, '', null); this.currentParent = this.topResults; this.specsExecuted = 0; this.failureCount = 0; this.pendingSpecCount = 0; } ResultsStateBuilder.prototype.suiteStarted = function(result) { this.currentParent.addChild(result, 'suite'); this.currentParent = this.currentParent.last(); }; ResultsStateBuilder.prototype.suiteDone = function(result) { this.currentParent.updateResult(result); if (this.currentParent !== this.topResults) { this.currentParent = this.currentParent.parent; } if (result.status === 'failed') { this.failureCount++; } }; ResultsStateBuilder.prototype.specStarted = function(result) {}; ResultsStateBuilder.prototype.specDone = function(result) { this.currentParent.addChild(result, 'spec'); if (result.status !== 'excluded') { this.specsExecuted++; } if (result.status === 'failed') { this.failureCount++; } if (result.status == 'pending') { this.pendingSpecCount++; } }; ResultsStateBuilder.prototype.jasmineDone = function(result) { if (result.failedExpectations) { this.failureCount += result.failedExpectations.length; } }; function HtmlReporter(options) { var config = function() { return (options.env && options.env.configuration()) || {}; }, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, navigateWithNewParam = options.navigateWithNewParam || function() {}, addToExistingQueryString = options.addToExistingQueryString || defaultQueryString, filterSpecs = options.filterSpecs, htmlReporterMain, symbols, deprecationWarnings = []; this.initialize = function() { clearPrior(); htmlReporterMain = createDom( 'div', { className: 'jasmine_html-reporter' }, createDom( 'div', { className: 'jasmine-banner' }, createDom('a', { className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank' }), createDom('span', { className: 'jasmine-version' }, j$.version) ), createDom('ul', { className: 'jasmine-symbol-summary' }), createDom('div', { className: 'jasmine-alert' }), createDom( 'div', { className: 'jasmine-results' }, createDom('div', { className: 'jasmine-failures' }) ) ); getContainer().appendChild(htmlReporterMain); }; var totalSpecsDefined; this.jasmineStarted = function(options) { totalSpecsDefined = options.totalSpecsDefined || 0; }; var summary = createDom('div', { className: 'jasmine-summary' }); var stateBuilder = new ResultsStateBuilder(); this.suiteStarted = function(result) { stateBuilder.suiteStarted(result); }; this.suiteDone = function(result) { stateBuilder.suiteDone(result); if (result.status === 'failed') { failures.push(failureDom(result)); } addDeprecationWarnings(result, 'suite'); }; this.specStarted = function(result) { stateBuilder.specStarted(result); }; var failures = []; this.specDone = function(result) { stateBuilder.specDone(result); if (noExpectations(result)) { var noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; if (result.status === 'failed') { console.error(noSpecMsg); } else { console.warn(noSpecMsg); } } if (!symbols) { symbols = find('.jasmine-symbol-summary'); } symbols.appendChild( createDom('li', { className: this.displaySpecInCorrectFormat(result), id: 'spec_' + result.id, title: result.fullName }) ); if (result.status === 'failed') { failures.push(failureDom(result)); } addDeprecationWarnings(result, 'spec'); }; this.displaySpecInCorrectFormat = function(result) { return noExpectations(result) && result.status === 'passed' ? 'jasmine-empty' : this.resultStatus(result.status); }; this.resultStatus = function(status) { if (status === 'excluded') { return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; } return 'jasmine-' + status; }; this.jasmineDone = function(doneResult) { stateBuilder.jasmineDone(doneResult); var banner = find('.jasmine-banner'); var alert = find('.jasmine-alert'); var order = doneResult && doneResult.order; var i; alert.appendChild( createDom( 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's' ) ); banner.appendChild(optionsMenu(config())); if (stateBuilder.specsExecuted < totalSpecsDefined) { var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 var skippedLink = (window.location.pathname || '') + addToExistingQueryString('spec', ''); alert.appendChild( createDom( 'span', { className: 'jasmine-bar jasmine-skipped' }, createDom( 'a', { href: skippedLink, title: 'Run all specs' }, skippedMessage ) ) ); } var statusBarMessage = ''; var statusBarClassName = 'jasmine-overall-result jasmine-bar '; var globalFailures = (doneResult && doneResult.failedExpectations) || []; var failed = stateBuilder.failureCount + globalFailures.length > 0; if (totalSpecsDefined > 0 || failed) { statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount); if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); } } if (doneResult.overallStatus === 'passed') { statusBarClassName += ' jasmine-passed '; } else if (doneResult.overallStatus === 'incomplete') { statusBarClassName += ' jasmine-incomplete '; statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage; } else { statusBarClassName += ' jasmine-failed '; } var seedBar; if (order && order.random) { seedBar = createDom( 'span', { className: 'jasmine-seed-bar' }, ', randomized with seed ', createDom( 'a', { title: 'randomized with seed ' + order.seed, href: seedHref(order.seed) }, order.seed ) ); } alert.appendChild( createDom( 'span', { className: statusBarClassName }, statusBarMessage, seedBar ) ); var errorBarClassName = 'jasmine-bar jasmine-errored'; var afterAllMessagePrefix = 'AfterAll '; for (i = 0; i < globalFailures.length; i++) { alert.appendChild( createDom( 'span', { className: errorBarClassName }, globalFailureMessage(globalFailures[i]) ) ); } function globalFailureMessage(failure) { if (failure.globalErrorType === 'load') { var prefix = 'Error during loading: ' + failure.message; if (failure.filename) { return ( prefix + ' in ' + failure.filename + ' line ' + failure.lineno ); } else { return prefix; } } else if (failure.globalErrorType === 'afterAll') { return afterAllMessagePrefix + failure.message; } else { return failure.message; } } addDeprecationWarnings(doneResult); for (i = 0; i < deprecationWarnings.length; i++) { var children = [], context; switch (deprecationWarnings[i].runnableType) { case 'spec': context = '(in spec: ' + deprecationWarnings[i].runnableName + ')'; break; case 'suite': context = '(in suite: ' + deprecationWarnings[i].runnableName + ')'; break; default: context = ''; } deprecationWarnings[i].message.split('\n').forEach(function(line) { children.push(line); children.push(createDom('br')); }); children[0] = 'DEPRECATION: ' + children[0]; children.push(context); if (deprecationWarnings[i].stack) { children.push(createExpander(deprecationWarnings[i].stack)); } alert.appendChild( createDom( 'span', { className: 'jasmine-bar jasmine-warning' }, children ) ); } var results = find('.jasmine-results'); results.appendChild(summary); summaryList(stateBuilder.topResults, summary); if (failures.length) { alert.appendChild( createDom( 'span', { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, createDom('span', {}, 'Spec List | '), createDom( 'a', { className: 'jasmine-failures-menu', href: '#' }, 'Failures' ) ) ); alert.appendChild( createDom( 'span', { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, createDom( 'a', { className: 'jasmine-spec-list-menu', href: '#' }, 'Spec List' ), createDom('span', {}, ' | Failures ') ) ); find('.jasmine-failures-menu').onclick = function() { setMenuModeTo('jasmine-failure-list'); return false; }; find('.jasmine-spec-list-menu').onclick = function() { setMenuModeTo('jasmine-spec-list'); return false; }; setMenuModeTo('jasmine-failure-list'); var failureNode = find('.jasmine-failures'); for (i = 0; i < failures.length; i++) { failureNode.appendChild(failures[i]); } } }; return this; function failureDom(result) { var failure = createDom( 'div', { className: 'jasmine-spec-detail jasmine-failed' }, failureDescription(result, stateBuilder.currentParent), createDom('div', { className: 'jasmine-messages' }) ); var messages = failure.childNodes[1]; for (var i = 0; i < result.failedExpectations.length; i++) { var expectation = result.failedExpectations[i]; messages.appendChild( createDom( 'div', { className: 'jasmine-result-message' }, expectation.message ) ); messages.appendChild( createDom( 'div', { className: 'jasmine-stack-trace' }, expectation.stack ) ); } if (result.failedExpectations.length === 0) { messages.appendChild( createDom( 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations' ) ); } if (result.debugLogs) { messages.appendChild(debugLogTable(result.debugLogs)); } return failure; } function debugLogTable(debugLogs) { var tbody = createDom('tbody'); debugLogs.forEach(function(entry) { tbody.appendChild( createDom( 'tr', {}, createDom('td', {}, entry.timestamp.toString()), createDom('td', {}, entry.message) ) ); }); return createDom( 'div', { className: 'jasmine-debug-log' }, createDom( 'div', { className: 'jasmine-debug-log-header' }, 'Debug logs' ), createDom( 'table', {}, createDom( 'thead', {}, createDom( 'tr', {}, createDom('th', {}, 'Time (ms)'), createDom('th', {}, 'Message') ) ), tbody ) ); } function summaryList(resultsTree, domParent) { var specListNode; for (var i = 0; i < resultsTree.children.length; i++) { var resultNode = resultsTree.children[i]; if (filterSpecs && !hasActiveSpec(resultNode)) { continue; } if (resultNode.type === 'suite') { var suiteListNode = createDom( 'ul', { className: 'jasmine-suite', id: 'suite-' + resultNode.result.id }, createDom( 'li', { className: 'jasmine-suite-detail jasmine-' + resultNode.result.status }, createDom( 'a', { href: specHref(resultNode.result) }, resultNode.result.description ) ) ); summaryList(resultNode, suiteListNode); domParent.appendChild(suiteListNode); } if (resultNode.type === 'spec') { if (domParent.getAttribute('class') !== 'jasmine-specs') { specListNode = createDom('ul', { className: 'jasmine-specs' }); domParent.appendChild(specListNode); } var specDescription = resultNode.result.description; if (noExpectations(resultNode.result)) { specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; } if ( resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '' ) { specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason; } specListNode.appendChild( createDom( 'li', { className: 'jasmine-' + resultNode.result.status, id: 'spec-' + resultNode.result.id }, createDom( 'a', { href: specHref(resultNode.result) }, specDescription ) ) ); } } } function optionsMenu(config) { var optionsMenuDom = createDom( 'div', { className: 'jasmine-run-options' }, createDom('span', { className: 'jasmine-trigger' }, 'Options'), createDom( 'div', { className: 'jasmine-payload' }, createDom( 'div', { className: 'jasmine-stop-on-failure' }, createDom('input', { className: 'jasmine-fail-fast', id: 'jasmine-fail-fast', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-fail-fast' }, 'stop execution on spec failure' ) ), createDom( 'div', { className: 'jasmine-throw-failures' }, createDom('input', { className: 'jasmine-throw', id: 'jasmine-throw-failures', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-throw-failures' }, 'stop spec on expectation failure' ) ), createDom( 'div', { className: 'jasmine-random-order' }, createDom('input', { className: 'jasmine-random', id: 'jasmine-random-order', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-random-order' }, 'run tests in random order' ) ), createDom( 'div', { className: 'jasmine-hide-disabled' }, createDom('input', { className: 'jasmine-disabled', id: 'jasmine-hide-disabled', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-hide-disabled' }, 'hide disabled tests' ) ) ) ); var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); failFastCheckbox.checked = config.stopOnSpecFailure; failFastCheckbox.onclick = function() { navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure); }; var throwCheckbox = optionsMenuDom.querySelector( '#jasmine-throw-failures' ); throwCheckbox.checked = config.stopSpecOnExpectationFailure; throwCheckbox.onclick = function() { navigateWithNewParam( 'stopSpecOnExpectationFailure', !config.stopSpecOnExpectationFailure ); }; var randomCheckbox = optionsMenuDom.querySelector( '#jasmine-random-order' ); randomCheckbox.checked = config.random; randomCheckbox.onclick = function() { navigateWithNewParam('random', !config.random); }; var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled'); hideDisabled.checked = config.hideDisabled; hideDisabled.onclick = function() { navigateWithNewParam('hideDisabled', !config.hideDisabled); }; var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), isOpen = /\bjasmine-open\b/; optionsTrigger.onclick = function() { if (isOpen.test(optionsPayload.className)) { optionsPayload.className = optionsPayload.className.replace( isOpen, '' ); } else { optionsPayload.className += ' jasmine-open'; } }; return optionsMenuDom; } function failureDescription(result, suite) { var wrapper = createDom( 'div', { className: 'jasmine-description' }, createDom( 'a', { title: result.description, href: specHref(result) }, result.description ) ); var suiteLink; while (suite && suite.parent) { wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild); suiteLink = createDom( 'a', { href: suiteHref(suite) }, suite.result.description ); wrapper.insertBefore(suiteLink, wrapper.firstChild); suite = suite.parent; } return wrapper; } function suiteHref(suite) { var els = []; while (suite && suite.parent) { els.unshift(suite.result.description); suite = suite.parent; } // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('spec', els.join(' ')) ); } function addDeprecationWarnings(result, runnableType) { if (result && result.deprecationWarnings) { for (var i = 0; i < result.deprecationWarnings.length; i++) { var warning = result.deprecationWarnings[i].message; deprecationWarnings.push({ message: warning, stack: result.deprecationWarnings[i].stack, runnableName: result.fullName, runnableType: runnableType }); } } } function createExpander(stackTrace) { var expandLink = createDom('a', { href: '#' }, 'Show stack trace'); var root = createDom( 'div', { className: 'jasmine-expander' }, expandLink, createDom( 'div', { className: 'jasmine-expander-contents jasmine-stack-trace' }, stackTrace ) ); expandLink.addEventListener('click', function(e) { e.preventDefault(); if (root.classList.contains('jasmine-expanded')) { root.classList.remove('jasmine-expanded'); expandLink.textContent = 'Show stack trace'; } else { root.classList.add('jasmine-expanded'); expandLink.textContent = 'Hide stack trace'; } }); return root; } function find(selector) { return getContainer().querySelector('.jasmine_html-reporter ' + selector); } function clearPrior() { // return the reporter var oldReporter = find(''); if (oldReporter) { getContainer().removeChild(oldReporter); } } function createDom(type, attrs, childrenArrayOrVarArgs) { var el = createElement(type), children, i; if (j$.isArray_(childrenArrayOrVarArgs)) { children = childrenArrayOrVarArgs; } else { children = []; for (i = 2; i < arguments.length; i++) { children.push(arguments[i]); } } for (i = 0; i < children.length; i++) { var child = children[i]; if (typeof child === 'string') { el.appendChild(createTextNode(child)); } else { if (child) { el.appendChild(child); } } } for (var attr in attrs) { if (attr == 'className') { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } return el; } function pluralize(singular, count) { var word = count == 1 ? singular : singular + 's'; return '' + count + ' ' + word; } function specHref(result) { // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('spec', result.fullName) ); } function seedHref(seed) { // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('seed', seed) ); } function defaultQueryString(key, value) { return '?' + key + '=' + value; } function setMenuModeTo(mode) { htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); } function noExpectations(result) { var allExpectations = result.failedExpectations.length + result.passedExpectations.length; return ( allExpectations === 0 && (result.status === 'passed' || result.status === 'failed') ); } function hasActiveSpec(resultNode) { if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') { return true; } if (resultNode.type == 'suite') { for (var i = 0, j = resultNode.children.length; i < j; i++) { if (hasActiveSpec(resultNode.children[i])) { return true; } } } } } return HtmlReporter; }; jasmineRequire.HtmlSpecFilter = function() { function HtmlSpecFilter(options) { var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); var filterPattern = new RegExp(filterString); this.matches = function(specName) { return filterPattern.test(specName); }; } return HtmlSpecFilter; }; jasmineRequire.ResultsNode = function() { function ResultsNode(result, type, parent) { this.result = result; this.type = type; this.parent = parent; this.children = []; this.addChild = function(result, type) { this.children.push(new ResultsNode(result, type, this)); }; this.last = function() { return this.children[this.children.length - 1]; }; this.updateResult = function(result) { this.result = result; }; } return ResultsNode; }; jasmineRequire.QueryString = function() { function QueryString(options) { this.navigateWithNewParam = function(key, value) { options.getWindowLocation().search = this.fullStringWithNewParam( key, value ); }; this.fullStringWithNewParam = function(key, value) { var paramMap = queryStringToParamMap(); paramMap[key] = value; return toQueryString(paramMap); }; this.getParam = function(key) { return queryStringToParamMap()[key]; }; return this; function toQueryString(paramMap) { var qStrPairs = []; for (var prop in paramMap) { qStrPairs.push( encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]) ); } return '?' + qStrPairs.join('&'); } function queryStringToParamMap() { var paramStr = options.getWindowLocation().search.substring(1), params = [], paramMap = {}; if (paramStr.length > 0) { params = paramStr.split('&'); for (var i = 0; i < params.length; i++) { var p = params[i].split('='); var value = decodeURIComponent(p[1]); if (value === 'true' || value === 'false') { value = JSON.parse(value); } paramMap[decodeURIComponent(p[0])] = value; } } return paramMap; } } return QueryString; }; jasmine-4.0.0/lib/jasmine-core/jasmine.css000066400000000000000000000532011416413636100204310ustar00rootroot00000000000000@charset "UTF-8"; body { overflow-y: scroll; } .jasmine_html-reporter { width: 100%; background-color: #eee; padding: 5px; margin: -8px; font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333; } .jasmine_html-reporter a { text-decoration: none; } .jasmine_html-reporter a:hover { text-decoration: underline; } .jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { margin: 0; line-height: 14px; } .jasmine_html-reporter .jasmine-banner, .jasmine_html-reporter .jasmine-symbol-summary, .jasmine_html-reporter .jasmine-summary, .jasmine_html-reporter .jasmine-result-message, .jasmine_html-reporter .jasmine-spec .jasmine-description, .jasmine_html-reporter .jasmine-spec-detail .jasmine-description, .jasmine_html-reporter .jasmine-alert .jasmine-bar, .jasmine_html-reporter .jasmine-stack-trace { padding-left: 9px; padding-right: 9px; } .jasmine_html-reporter .jasmine-banner { position: relative; } .jasmine_html-reporter .jasmine-banner .jasmine-title { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==") no-repeat; background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=") no-repeat, none; -moz-background-size: 100%; -o-background-size: 100%; -webkit-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; } .jasmine_html-reporter .jasmine-banner .jasmine-version { margin-left: 14px; position: relative; top: 6px; } .jasmine_html-reporter #jasmine_content { position: fixed; right: 100%; } .jasmine_html-reporter .jasmine-version { color: #aaa; } .jasmine_html-reporter .jasmine-banner { margin-top: 14px; } .jasmine_html-reporter .jasmine-duration { color: #fff; float: right; line-height: 28px; padding-right: 9px; } .jasmine_html-reporter .jasmine-symbol-summary { overflow: hidden; margin: 14px 0; } .jasmine_html-reporter .jasmine-symbol-summary li { display: inline-block; height: 10px; width: 14px; font-size: 16px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed { font-size: 14px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed:before { color: #007069; content: "•"; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed { line-height: 9px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { color: #ca3a11; content: "×"; font-weight: bold; margin-left: -1px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded { font-size: 14px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before { color: #bababa; content: "•"; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded-no-display { font-size: 14px; display: none; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { line-height: 17px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { color: #ba9d37; content: "*"; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { font-size: 14px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty:before { color: #ba9d37; content: "•"; } .jasmine_html-reporter .jasmine-run-options { float: right; margin-right: 5px; border: 1px solid #8a4182; color: #8a4182; position: relative; line-height: 20px; } .jasmine_html-reporter .jasmine-run-options .jasmine-trigger { cursor: pointer; padding: 8px 16px; } .jasmine_html-reporter .jasmine-run-options .jasmine-payload { position: absolute; display: none; right: -1px; border: 1px solid #8a4182; background-color: #eee; white-space: nowrap; padding: 4px 8px; } .jasmine_html-reporter .jasmine-run-options .jasmine-payload.jasmine-open { display: block; } .jasmine_html-reporter .jasmine-bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } .jasmine_html-reporter .jasmine-bar.jasmine-failed, .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; border-bottom: 1px solid #eee; } .jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; } .jasmine_html-reporter .jasmine-bar.jasmine-incomplete { background-color: #bababa; } .jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; } .jasmine_html-reporter .jasmine-bar.jasmine-warning { margin-top: 14px; margin-bottom: 14px; background-color: #ba9d37; color: #333; } .jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; } .jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; } .jasmine_html-reporter .jasmine-bar a { color: white; } .jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list, .jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures { display: none; } .jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list, .jasmine_html-reporter.jasmine-failure-list .jasmine-summary { display: none; } .jasmine_html-reporter .jasmine-results { margin-top: 14px; } .jasmine_html-reporter .jasmine-summary { margin-top: 14px; } .jasmine_html-reporter .jasmine-summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } .jasmine_html-reporter .jasmine-summary ul.jasmine-suite { margin-top: 7px; margin-bottom: 7px; } .jasmine_html-reporter .jasmine-summary li.jasmine-passed a { color: #007069; } .jasmine_html-reporter .jasmine-summary li.jasmine-failed a { color: #ca3a11; } .jasmine_html-reporter .jasmine-summary li.jasmine-empty a { color: #ba9d37; } .jasmine_html-reporter .jasmine-summary li.jasmine-pending a { color: #ba9d37; } .jasmine_html-reporter .jasmine-summary li.jasmine-excluded a { color: #bababa; } .jasmine_html-reporter .jasmine-specs li.jasmine-passed a:before { content: "• "; } .jasmine_html-reporter .jasmine-specs li.jasmine-failed a:before { content: "× "; } .jasmine_html-reporter .jasmine-specs li.jasmine-empty a:before { content: "* "; } .jasmine_html-reporter .jasmine-specs li.jasmine-pending a:before { content: "• "; } .jasmine_html-reporter .jasmine-specs li.jasmine-excluded a:before { content: "• "; } .jasmine_html-reporter .jasmine-description + .jasmine-suite { margin-top: 0; } .jasmine_html-reporter .jasmine-suite { margin-top: 14px; } .jasmine_html-reporter .jasmine-suite a { color: #333; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { margin-bottom: 28px; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; color: white; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { color: white; } .jasmine_html-reporter .jasmine-result-message { padding-top: 14px; color: #333; white-space: pre-wrap; } .jasmine_html-reporter .jasmine-result-message span.jasmine-result { display: block; } .jasmine_html-reporter .jasmine-stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666; border: 1px solid #ddd; background: white; white-space: pre; } .jasmine_html-reporter .jasmine-expander a { display: block; margin-left: 14px; color: blue; text-decoration: underline; } .jasmine_html-reporter .jasmine-expander-contents { display: none; } .jasmine_html-reporter .jasmine-expanded { padding-bottom: 10px; } .jasmine_html-reporter .jasmine-expanded .jasmine-expander-contents { display: block; margin-left: 14px; padding: 5px; } .jasmine_html-reporter .jasmine-debug-log { margin: 5px 0 0 0; padding: 5px; color: #666; border: 1px solid #ddd; background: white; } .jasmine_html-reporter .jasmine-debug-log table { border-spacing: 0; } .jasmine_html-reporter .jasmine-debug-log table, .jasmine_html-reporter .jasmine-debug-log th, .jasmine_html-reporter .jasmine-debug-log td { border: 1px solid #ddd; }jasmine-4.0.0/lib/jasmine-core/jasmine.js000066400000000000000000010601371416413636100202640ustar00rootroot00000000000000/* Copyright (c) 2008-2022 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // eslint-disable-next-line no-unused-vars var getJasmineRequireObj = (function(jasmineGlobal) { var jasmineRequire; if ( typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined' ) { if (typeof global !== 'undefined') { jasmineGlobal = global; } else { jasmineGlobal = {}; } jasmineRequire = exports; } else { if ( typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]' ) { jasmineGlobal = window; } jasmineRequire = jasmineGlobal.jasmineRequire = {}; } function getJasmineRequire() { return jasmineRequire; } getJasmineRequire().core = function(jRequire) { var j$ = {}; jRequire.base(j$, jasmineGlobal); j$.util = jRequire.util(j$); j$.errors = jRequire.errors(); j$.formatErrorMsg = jRequire.formatErrorMsg(); j$.Any = jRequire.Any(j$); j$.Anything = jRequire.Anything(j$); j$.CallTracker = jRequire.CallTracker(j$); j$.MockDate = jRequire.MockDate(j$); j$.getClearStack = jRequire.clearStack(j$); j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Deprecator = jRequire.Deprecator(j$); j$.Env = jRequire.Env(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); j$.Expector = jRequire.Expector(j$); j$.Expectation = jRequire.Expectation(j$); j$.buildExpectationResult = jRequire.buildExpectationResult(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$); j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$); j$.basicPrettyPrinter_ = j$.makePrettyPrinter(); j$.MatchersUtil = jRequire.MatchersUtil(j$); j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); j$.MapContaining = jRequire.MapContaining(j$); j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( j$ ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ ); j$.ReportDispatcher = jRequire.ReportDispatcher(j$); j$.Spec = jRequire.Spec(j$); j$.Spy = jRequire.Spy(j$); j$.SpyFactory = jRequire.SpyFactory(j$); j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); j$.StringContaining = jRequire.StringContaining(j$); j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); j$.TreeProcessor = jRequire.TreeProcessor(); j$.version = jRequire.version(); j$.Order = jRequire.Order(); j$.DiffBuilder = jRequire.DiffBuilder(j$); j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$); j$.ObjectPath = jRequire.ObjectPath(j$); j$.MismatchTree = jRequire.MismatchTree(j$); j$.GlobalErrors = jRequire.GlobalErrors(j$); j$.Truthy = jRequire.Truthy(j$); j$.Falsy = jRequire.Falsy(j$); j$.Empty = jRequire.Empty(j$); j$.NotEmpty = jRequire.NotEmpty(j$); j$.matchers = jRequire.requireMatchers(jRequire, j$); j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$); return j$; }; return getJasmineRequire; })(this); getJasmineRequireObj().requireMatchers = function(jRequire, j$) { var availableMatchers = [ 'nothing', 'toBe', 'toBeCloseTo', 'toBeDefined', 'toBeInstanceOf', 'toBeFalse', 'toBeFalsy', 'toBeGreaterThan', 'toBeGreaterThanOrEqual', 'toBeLessThan', 'toBeLessThanOrEqual', 'toBeNaN', 'toBeNegativeInfinity', 'toBeNull', 'toBePositiveInfinity', 'toBeTrue', 'toBeTruthy', 'toBeUndefined', 'toContain', 'toEqual', 'toHaveSize', 'toHaveBeenCalled', 'toHaveBeenCalledBefore', 'toHaveBeenCalledOnceWith', 'toHaveBeenCalledTimes', 'toHaveBeenCalledWith', 'toHaveClass', 'toMatch', 'toThrow', 'toThrowError', 'toThrowMatching' ], matchers = {}; for (var i = 0; i < availableMatchers.length; i++) { var name = availableMatchers[i]; matchers[name] = jRequire[name](j$); } return matchers; }; getJasmineRequireObj().base = function(j$, jasmineGlobal) { j$.unimplementedMethod_ = function() { throw new Error('unimplemented method'); }; /** * Maximum object depth the pretty printer will print to. * Set this to a lower value to speed up pretty printing if you have large objects. * @name jasmine.MAX_PRETTY_PRINT_DEPTH * @default 8 * @since 1.3.0 */ j$.MAX_PRETTY_PRINT_DEPTH = 8; /** * Maximum number of array elements to display when pretty printing objects. * This will also limit the number of keys and values displayed for an object. * Elements past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH * @default 50 * @since 2.7.0 */ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50; /** * Maximum number of characters to display when pretty printing objects. * Characters past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_CHARS * @default 100 * @since 2.9.0 */ j$.MAX_PRETTY_PRINT_CHARS = 1000; /** * Default number of milliseconds Jasmine will wait for an asynchronous spec, * before, or after function to complete. This can be overridden on a case by * case basis by passing a time limit as the third argument to {@link it}, * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or * {@link afterAll}. The value must be no greater than the largest number of * milliseconds supported by setTimeout, which is usually 2147483647. * * While debugging tests, you may want to set this to a large number (or pass * a large number to one of the functions mentioned above) so that Jasmine * does not move on to after functions or the next spec while you're debugging. * @name jasmine.DEFAULT_TIMEOUT_INTERVAL * @default 5000 * @since 1.3.0 */ var DEFAULT_TIMEOUT_INTERVAL = 5000; Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', { get: function() { return DEFAULT_TIMEOUT_INTERVAL; }, set: function(newValue) { j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL'); DEFAULT_TIMEOUT_INTERVAL = newValue; } }); j$.getGlobal = function() { return jasmineGlobal; }; /** * Get the currently booted Jasmine Environment. * * @name jasmine.getEnv * @since 1.3.0 * @function * @return {Env} */ j$.getEnv = function(options) { var env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options)); //jasmine. singletons in here (setTimeout blah blah). return env; }; j$.isArray_ = function(value) { return j$.isA_('Array', value); }; j$.isObject_ = function(value) { return ( !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value) ); }; j$.isString_ = function(value) { return j$.isA_('String', value); }; j$.isNumber_ = function(value) { return j$.isA_('Number', value); }; j$.isFunction_ = function(value) { return j$.isA_('Function', value); }; j$.isAsyncFunction_ = function(value) { return j$.isA_('AsyncFunction', value); }; j$.isGeneratorFunction_ = function(value) { return j$.isA_('GeneratorFunction', value); }; j$.isTypedArray_ = function(value) { return ( j$.isA_('Float32Array', value) || j$.isA_('Float64Array', value) || j$.isA_('Int16Array', value) || j$.isA_('Int32Array', value) || j$.isA_('Int8Array', value) || j$.isA_('Uint16Array', value) || j$.isA_('Uint32Array', value) || j$.isA_('Uint8Array', value) || j$.isA_('Uint8ClampedArray', value) ); }; j$.isA_ = function(typeName, value) { return j$.getType_(value) === '[object ' + typeName + ']'; }; j$.isError_ = function(value) { if (!value) { return false; } if (value instanceof Error) { return true; } return typeof value.stack === 'string' && typeof value.message === 'string'; }; j$.isAsymmetricEqualityTester_ = function(obj) { return obj ? j$.isA_('Function', obj.asymmetricMatch) : false; }; j$.getType_ = function(value) { return Object.prototype.toString.apply(value); }; j$.isDomNode = function(obj) { // Node is a function, because constructors return typeof jasmineGlobal.Node !== 'undefined' ? obj instanceof jasmineGlobal.Node : obj !== null && typeof obj === 'object' && typeof obj.nodeType === 'number' && typeof obj.nodeName === 'string'; // return obj.nodeType > 0; }; j$.isMap = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.Map ); }; j$.isSet = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.Set ); }; j$.isWeakMap = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.WeakMap ); }; j$.isURL = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.URL ); }; j$.isIterable_ = function(value) { return value && !!value[Symbol.iterator]; }; j$.isDataView = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.DataView ); }; j$.isPromise = function(obj) { return !!obj && obj.constructor === jasmineGlobal.Promise; }; j$.isPromiseLike = function(obj) { return !!obj && j$.isFunction_(obj.then); }; j$.fnNameFor = function(func) { if (func.name) { return func.name; } var matches = func.toString().match(/^\s*function\s*(\w+)\s*\(/) || func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/); return matches ? matches[1] : ''; }; j$.isPending_ = function(promise) { var sentinel = {}; return Promise.race([promise, Promise.resolve(sentinel)]).then( function(result) { return result === sentinel; }, function() { return false; } ); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is an instance of the specified class/constructor. * @name jasmine.any * @since 1.3.0 * @function * @param {Constructor} clazz - The constructor to check against. */ j$.any = function(clazz) { return new j$.Any(clazz); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is not `null` and not `undefined`. * @name jasmine.anything * @since 2.2.0 * @function */ j$.anything = function() { return new j$.Anything(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is `true` or anything truthy. * @name jasmine.truthy * @since 3.1.0 * @function */ j$.truthy = function() { return new j$.Truthy(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey. * @name jasmine.falsy * @since 3.1.0 * @function */ j$.falsy = function() { return new j$.Falsy(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is empty. * @name jasmine.empty * @since 3.1.0 * @function */ j$.empty = function() { return new j$.Empty(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is not empty. * @name jasmine.notEmpty * @since 3.1.0 * @function */ j$.notEmpty = function() { return new j$.NotEmpty(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared contains at least the keys and values. * @name jasmine.objectContaining * @since 1.3.0 * @function * @param {Object} sample - The subset of properties that _must_ be in the actual. */ j$.objectContaining = function(sample) { return new j$.ObjectContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`. * @name jasmine.stringMatching * @since 2.2.0 * @function * @param {RegExp|String} expected */ j$.stringMatching = function(expected) { return new j$.StringMatching(expected); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is a `String` that contains the specified `String`. * @name jasmine.stringContaining * @since 3.10.0 * @function * @param {String} expected */ j$.stringContaining = function(expected) { return new j$.StringContaining(expected); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains at least the elements in the sample. * @name jasmine.arrayContaining * @since 2.2.0 * @function * @param {Array} sample */ j$.arrayContaining = function(sample) { return new j$.ArrayContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order. * @name jasmine.arrayWithExactContents * @since 2.8.0 * @function * @param {Array} sample */ j$.arrayWithExactContents = function(sample) { return new j$.ArrayWithExactContents(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if every key/value pair in the sample passes the deep equality comparison * with at least one key/value pair in the actual value being compared * @name jasmine.mapContaining * @since 3.5.0 * @function * @param {Map} sample - The subset of items that _must_ be in the actual. */ j$.mapContaining = function(sample) { return new j$.MapContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if every item in the sample passes the deep equality comparison * with at least one item in the actual value being compared * @name jasmine.setContaining * @since 3.5.0 * @function * @param {Set} sample - The subset of items that _must_ be in the actual. */ j$.setContaining = function(sample) { return new j$.SetContaining(sample); }; /** * Determines whether the provided function is a Jasmine spy. * @name jasmine.isSpy * @since 2.0.0 * @function * @param {Function} putativeSpy - The function to check. * @return {Boolean} */ j$.isSpy = function(putativeSpy) { if (!putativeSpy) { return false; } return ( putativeSpy.and instanceof j$.SpyStrategy && putativeSpy.calls instanceof j$.CallTracker ); }; /** * Logs a message for use in debugging. If the spec fails, trace messages * will be included in the {@link SpecResult|result} passed to the * reporter's specDone method. * * This method should be called only when a spec (including any associated * beforeEach or afterEach functions) is running. * @function * @name jasmine.debugLog * @since 4.0.0 * @param {String} msg - The message to log */ j$.debugLog = function(msg) { j$.getEnv().debugLog(msg); }; }; getJasmineRequireObj().util = function(j$) { var util = {}; util.inherit = function(childClass, parentClass) { var Subclass = function() {}; Subclass.prototype = parentClass.prototype; childClass.prototype = new Subclass(); }; util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) { arrayOfArgs.push(args[i]); } return arrayOfArgs; }; util.isUndefined = function(obj) { return obj === void 0; }; util.arrayContains = function(array, search) { var i = array.length; while (i--) { if (array[i] === search) { return true; } } return false; }; util.clone = function(obj) { if (Object.prototype.toString.apply(obj) === '[object Array]') { return obj.slice(); } var cloned = {}; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { cloned[prop] = obj[prop]; } } return cloned; }; util.cloneArgs = function(args) { var clonedArgs = []; var argsAsArray = j$.util.argsToArray(args); for (var i = 0; i < argsAsArray.length; i++) { var str = Object.prototype.toString.apply(argsAsArray[i]), primitives = /^\[object (Boolean|String|RegExp|Number)/; // All falsey values are either primitives, `null`, or `undefined. if (!argsAsArray[i] || str.match(primitives)) { clonedArgs.push(argsAsArray[i]); } else { clonedArgs.push(j$.util.clone(argsAsArray[i])); } } return clonedArgs; }; util.getPropertyDescriptor = function(obj, methodName) { var descriptor, proto = obj; do { descriptor = Object.getOwnPropertyDescriptor(proto, methodName); proto = Object.getPrototypeOf(proto); } while (!descriptor && proto); return descriptor; }; util.objectDifference = function(obj, toRemove) { var diff = {}; for (var key in obj) { if (util.has(obj, key) && !util.has(toRemove, key)) { diff[key] = obj[key]; } } return diff; }; util.has = function(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); }; util.errorWithStack = function errorWithStack() { // Don't throw and catch. That makes it harder for users to debug their // code with exception breakpoints, and it's unnecessary since all // supported environments populate new Error().stack return new Error(); }; function callerFile() { var trace = new j$.StackTrace(util.errorWithStack()); return trace.frames[2].file; } util.jasmineFile = (function() { var result; return function() { if (!result) { result = callerFile(); } return result; }; })(); function StopIteration() {} StopIteration.prototype = Object.create(Error.prototype); StopIteration.prototype.constructor = StopIteration; util.validateTimeout = function(timeout, msgPrefix) { // Timeouts are implemented with setTimeout, which only supports a limited // range of values. The limit is unspecified, as is the behavior when it's // exceeded. But on all currently supported JS runtimes, setTimeout calls // the callback immediately when the timeout is greater than 2147483647 // (the maximum value of a signed 32 bit integer). var max = 2147483647; if (timeout > max) { throw new Error( (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max ); } }; return util; }; getJasmineRequireObj().Spec = function(j$) { /** * @interface Spec * @see Configuration#specFilter * @since 2.0.0 */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; /** * The unique ID of this spec. * @name Spec#id * @readonly * @type {string} * @since 2.0.0 */ this.id = attrs.id; /** * The description passed to the {@link it} that created this spec. * @name Spec#description * @readonly * @type {string} * @since 2.0.0 */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return { befores: [], afters: [] }; }; this.userContext = attrs.userContext || function() { return {}; }; this.onStart = attrs.onStart || function() {}; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; this.getSpecName = attrs.getSpecName || function() { return ''; }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; this.onLateError = attrs.onLateError || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.timer = attrs.timer || new j$.Timer(); if (!this.queueableFn.fn) { this.exclude(); } /** * @typedef SpecResult * @property {Int} id - The unique id of this spec. * @property {String} description - The description passed to the {@link it} that created this spec. * @property {String} fullName - The full description including all ancestors of this spec. * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. * @since 2.0.0 */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], deprecationWarnings: [], pendingReason: '', duration: null, properties: null, debugLogs: null }; } Spec.prototype.addExpectationResult = function(passed, data, isError) { var expectationResult = this.expectationResultFactory(data); if (passed) { this.result.passedExpectations.push(expectationResult); } else { this.result.failedExpectations.push(expectationResult); if (this.throwOnExpectationFailure && !isError) { throw new j$.errors.ExpectationFailed(); } } }; Spec.prototype.setSpecProperty = function(key, value) { this.result.properties = this.result.properties || {}; this.result.properties[key] = value; }; Spec.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; Spec.prototype.expectAsync = function(actual) { return this.asyncExpectationFactory(actual, this); }; Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) { var self = this; var onStart = { fn: function(done) { self.timer.start(); self.onStart(self, done); } }; var complete = { fn: function(done) { if (self.autoCleanClosures) { self.queueableFn.fn = null; } self.result.status = self.status(excluded, failSpecWithNoExp); self.result.duration = self.timer.elapsed(); if (self.result.status !== 'failed') { self.result.debugLogs = null; } self.resultCallback(self.result, done); }, type: 'specCleanup' }; var fns = this.beforeAndAfterFns(); var runnerConfig = { isLeaf: true, queueableFns: [...fns.befores, this.queueableFn, ...fns.afters], onException: function() { self.onException.apply(self, arguments); }, onMultipleDone: function() { // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. self.onLateError( new Error( 'An asynchronous spec, beforeEach, or afterEach function called its ' + "'done' callback more than once.\n(in spec: " + self.getFullName() + ')' ) ); }, onComplete: function() { if (self.result.status === 'failed') { onComplete(new j$.StopExecutionError('spec failed')); } else { onComplete(); } }, userContext: this.userContext(), runnableName: this.getFullName.bind(this) }; if (this.markedPending || excluded === true) { runnerConfig.queueableFns = []; } runnerConfig.queueableFns.unshift(onStart); runnerConfig.queueableFns.push(complete); this.queueRunnerFactory(runnerConfig); }; Spec.prototype.reset = function() { this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], deprecationWarnings: [], pendingReason: this.excludeMessage, duration: null, properties: null, debugLogs: null }; this.markedPending = this.markedExcluding; }; Spec.prototype.onException = function onException(e) { if (Spec.isPendingSpecException(e)) { this.pend(extractCustomPendingMessage(e)); return; } if (e instanceof j$.errors.ExpectationFailed) { return; } this.addExpectationResult( false, { matcherName: '', passed: false, expected: '', actual: '', error: e }, true ); }; /* * Marks state as pending * @param {string} [message] An optional reason message */ Spec.prototype.pend = function(message) { this.markedPending = true; if (message) { this.result.pendingReason = message; } }; /* * Like {@link Spec#pend}, but pending state will survive {@link Spec#reset} * Useful for fit, xit, where pending state remains. * @param {string} [message] An optional reason message */ Spec.prototype.exclude = function(message) { this.markedExcluding = true; if (this.message) { this.excludeMessage = message; } this.pend(message); }; Spec.prototype.getResult = function() { this.result.status = this.status(); return this.result; }; Spec.prototype.status = function(excluded, failSpecWithNoExpectations) { if (excluded === true) { return 'excluded'; } if (this.markedPending) { return 'pending'; } if ( this.result.failedExpectations.length > 0 || (failSpecWithNoExpectations && this.result.failedExpectations.length + this.result.passedExpectations.length === 0) ) { return 'failed'; } return 'passed'; }; /** * The full description including all ancestors of this spec. * @name Spec#getFullName * @function * @returns {string} * @since 2.0.0 */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; Spec.prototype.addDeprecationWarning = function(deprecation) { if (typeof deprecation === 'string') { deprecation = { message: deprecation }; } this.result.deprecationWarnings.push( this.expectationResultFactory(deprecation) ); }; Spec.prototype.debugLog = function(msg) { if (!this.result.debugLogs) { this.result.debugLogs = []; } /** * @typedef DebugLogEntry * @property {String} message - The message that was passed to {@link jasmine.debugLog}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ this.result.debugLogs.push({ message: msg, timestamp: this.timer.elapsed() }); }; var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length; return fullMessage.substr(boilerplateEnd); }; Spec.pendingSpecExceptionMessage = '=> marked Pending'; Spec.isPendingSpecException = function(e) { return !!( e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1 ); }; /** * @interface Spec * @see Configuration#specFilter */ Object.defineProperty(Spec.prototype, 'metadata', { get: function() { if (!this.metadata_) { this.metadata_ = { /** * The unique ID of this spec. * @name Spec#id * @readonly * @type {string} */ id: this.id, /** * The description passed to the {@link it} that created this spec. * @name Spec#description * @readonly * @type {string} */ description: this.description, /** * The full description including all ancestors of this spec. * @name Spec#getFullName * @function * @returns {string} */ getFullName: this.getFullName.bind(this) }; } return this.metadata_; } }); return Spec; }; /*jshint bitwise: false*/ getJasmineRequireObj().Order = function() { function Order(options) { this.random = 'random' in options ? options.random : true; var seed = (this.seed = options.seed || generateSeed()); this.sort = this.random ? randomOrder : naturalOrder; function naturalOrder(items) { return items; } function randomOrder(items) { var copy = items.slice(); copy.sort(function(a, b) { return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id); }); return copy; } function generateSeed() { return String(Math.random()).slice(-5); } // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function // used to get a different output when the key changes slightly. // We use your return to sort the children randomly in a consistent way when // used in conjunction with a seed function jenkinsHash(key) { var hash, i; for (hash = i = 0; i < key.length; ++i) { hash += key.charCodeAt(i); hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash; } } return Order; }; getJasmineRequireObj().Env = function(j$) { /** * @class Env * @since 2.0.0 * @classdesc The Jasmine environment.
* _Note:_ Do not construct this directly. You can obtain the Env instance by * calling {@link jasmine.getEnv}. * @hideconstructor */ function Env(options) { options = options || {}; var self = this; var global = options.global || j$.getGlobal(); var totalSpecsDefined = 0; var realSetTimeout = global.setTimeout; var realClearTimeout = global.clearTimeout; var clearStack = j$.getClearStack(global); this.clock = new j$.Clock( global, function() { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global) ); var runnableResources = {}; var currentSpec = null; var currentlyExecutingSuites = []; var currentDeclarationSuite = null; var hasFailures = false; /** * This represents the available options to configure Jasmine. * Options that are not provided will use their default values. * @see Env#configure * @interface Configuration * @since 3.3.0 */ var config = { /** * Whether to randomize spec execution order * @name Configuration#random * @since 3.3.0 * @type Boolean * @default true */ random: true, /** * Seed to use as the basis of randomization. * Null causes the seed to be determined randomly at the start of execution. * @name Configuration#seed * @since 3.3.0 * @type (number|string) * @default null */ seed: null, /** * Whether to stop execution of the suite after the first spec failure * @name Configuration#stopOnSpecFailure * @since 3.9.0 * @type Boolean * @default false */ stopOnSpecFailure: false, /** * Whether to fail the spec if it ran no expectations. By default * a spec that ran no expectations is reported as passed. Setting this * to true will report such spec as a failure. * @name Configuration#failSpecWithNoExpectations * @since 3.5.0 * @type Boolean * @default false */ failSpecWithNoExpectations: false, /** * Whether to cause specs to only have one expectation failure. * @name Configuration#stopSpecOnExpectationFailure * @since 3.3.0 * @type Boolean * @default false */ stopSpecOnExpectationFailure: false, /** * A function that takes a spec and returns true if it should be executed * or false if it should be skipped. * @callback SpecFilter * @param {Spec} spec - The spec that the filter is being applied to. * @return boolean */ /** * Function to use to filter specs * @name Configuration#specFilter * @since 3.3.0 * @type SpecFilter * @default A function that always returns true. */ specFilter: function() { return true; }, /** * Whether or not reporters should hide disabled specs from their output. * Currently only supported by Jasmine's HTMLReporter * @name Configuration#hideDisabled * @since 3.3.0 * @type Boolean * @default false */ hideDisabled: false, /** * Clean closures when a suite is done running (done by clearing the stored function reference). * This prevents memory leaks, but you won't be able to run jasmine multiple times. * @name Configuration#autoCleanClosures * @since 3.10.0 * @type boolean * @default true */ autoCleanClosures: true, /** * Whether or not to issue warnings for certain deprecated functionality * every time it's used. If not set or set to false, deprecation warnings * for methods that tend to be called frequently will be issued only once * or otherwise throttled to to prevent the suite output from being flooded * with warnings. * @name Configuration#verboseDeprecations * @since 3.6.0 * @type Boolean * @default false */ verboseDeprecations: false }; var currentSuite = function() { return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; }; var currentRunnable = function() { return currentSpec || currentSuite(); }; var globalErrors = null; var installGlobalErrors = function() { if (globalErrors) { return; } globalErrors = new j$.GlobalErrors(); globalErrors.install(); }; if (!options.suppressLoadErrors) { installGlobalErrors(); globalErrors.pushListener(function( message, filename, lineno, colNo, err ) { topSuite.result.failedExpectations.push({ passed: false, globalErrorType: 'load', message: message, stack: err && err.stack, filename: filename, lineno: lineno }); }); } /** * Configure your jasmine environment * @name Env#configure * @since 3.3.0 * @argument {Configuration} configuration * @function */ this.configure = function(configuration) { var booleanProps = [ 'random', 'failSpecWithNoExpectations', 'hideDisabled', 'stopOnSpecFailure', 'stopSpecOnExpectationFailure', 'autoCleanClosures' ]; booleanProps.forEach(function(prop) { if (typeof configuration[prop] !== 'undefined') { config[prop] = !!configuration[prop]; } }); if (configuration.specFilter) { config.specFilter = configuration.specFilter; } if (typeof configuration.seed !== 'undefined') { config.seed = configuration.seed; } if (configuration.hasOwnProperty('verboseDeprecations')) { config.verboseDeprecations = configuration.verboseDeprecations; deprecator.verboseDeprecations(config.verboseDeprecations); } }; /** * Get the current configuration for your jasmine environment * @name Env#configuration * @since 3.3.0 * @function * @returns {Configuration} */ this.configuration = function() { var result = {}; for (var property in config) { result[property] = config[property]; } return result; }; this.setDefaultSpyStrategy = function(defaultStrategyFn) { if (!currentRunnable()) { throw new Error( 'Default spy strategy must be set in a before function or a spec' ); } runnableResources[ currentRunnable().id ].defaultStrategyFn = defaultStrategyFn; }; this.addSpyStrategy = function(name, fn) { if (!currentRunnable()) { throw new Error( 'Custom spy strategies must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customSpyStrategies[name] = fn; }; this.addCustomEqualityTester = function(tester) { if (!currentRunnable()) { throw new Error( 'Custom Equalities must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customEqualityTesters.push( tester ); }; this.addMatchers = function(matchersToAdd) { if (!currentRunnable()) { throw new Error( 'Matchers must be added in a before function or a spec' ); } var customMatchers = runnableResources[currentRunnable().id].customMatchers; for (var matcherName in matchersToAdd) { customMatchers[matcherName] = matchersToAdd[matcherName]; } }; this.addAsyncMatchers = function(matchersToAdd) { if (!currentRunnable()) { throw new Error( 'Async Matchers must be added in a before function or a spec' ); } var customAsyncMatchers = runnableResources[currentRunnable().id].customAsyncMatchers; for (var matcherName in matchersToAdd) { customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; } }; this.addCustomObjectFormatter = function(formatter) { if (!currentRunnable()) { throw new Error( 'Custom object formatters must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customObjectFormatters.push( formatter ); }; j$.Expectation.addCoreMatchers(j$.matchers); j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers); var nextSpecId = 0; var getNextSpecId = function() { return 'spec' + nextSpecId++; }; var nextSuiteId = 0; var getNextSuiteId = function() { return 'suite' + nextSuiteId++; }; var makePrettyPrinter = function() { var customObjectFormatters = runnableResources[currentRunnable().id].customObjectFormatters; return j$.makePrettyPrinter(customObjectFormatters); }; var makeMatchersUtil = function() { const cr = currentRunnable(); if (cr) { const customEqualityTesters = runnableResources[cr.id].customEqualityTesters; return new j$.MatchersUtil({ customTesters: customEqualityTesters, pp: makePrettyPrinter() }); } else { return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ }); } }; var expectationFactory = function(actual, spec) { return j$.Expectation.factory({ matchersUtil: makeMatchersUtil(), customMatchers: runnableResources[spec.id].customMatchers, actual: actual, addExpectationResult: addExpectationResult }); function addExpectationResult(passed, result) { return spec.addExpectationResult(passed, result); } }; function recordLateError(error) { const result = expectationResultFactory({ error, passed: false, matcherName: '', expected: '', actual: '' }); result.globalErrorType = 'lateError'; topSuite.result.failedExpectations.push(result); } function recordLateExpectation(runable, runableType, result) { var delayedExpectationResult = {}; Object.keys(result).forEach(function(k) { delayedExpectationResult[k] = result[k]; }); delayedExpectationResult.passed = false; delayedExpectationResult.globalErrorType = 'lateExpectation'; delayedExpectationResult.message = runableType + ' "' + runable.getFullName() + '" ran a "' + result.matcherName + '" expectation after it finished.\n'; if (result.message) { delayedExpectationResult.message += 'Message: "' + result.message + '"\n'; } delayedExpectationResult.message += '1. Did you forget to return or await the result of expectAsync?\n' + '2. Was done() invoked before an async operation completed?\n' + '3. Did an expectation follow a call to done()?'; topSuite.result.failedExpectations.push(delayedExpectationResult); } var asyncExpectationFactory = function(actual, spec, runableType) { return j$.Expectation.asyncFactory({ matchersUtil: makeMatchersUtil(), customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, actual: actual, addExpectationResult: addExpectationResult }); function addExpectationResult(passed, result) { if (currentRunnable() !== spec) { recordLateExpectation(spec, runableType, result); } return spec.addExpectationResult(passed, result); } }; var suiteAsyncExpectationFactory = function(actual, suite) { return asyncExpectationFactory(actual, suite, 'Suite'); }; var specAsyncExpectationFactory = function(actual, suite) { return asyncExpectationFactory(actual, suite, 'Spec'); }; var defaultResourcesForRunnable = function(id, parentRunnableId) { var resources = { spies: [], customEqualityTesters: [], customMatchers: {}, customAsyncMatchers: {}, customSpyStrategies: {}, defaultStrategyFn: undefined, customObjectFormatters: [] }; if (runnableResources[parentRunnableId]) { resources.customEqualityTesters = j$.util.clone( runnableResources[parentRunnableId].customEqualityTesters ); resources.customMatchers = j$.util.clone( runnableResources[parentRunnableId].customMatchers ); resources.customAsyncMatchers = j$.util.clone( runnableResources[parentRunnableId].customAsyncMatchers ); resources.customObjectFormatters = j$.util.clone( runnableResources[parentRunnableId].customObjectFormatters ); resources.customSpyStrategies = j$.util.clone( runnableResources[parentRunnableId].customSpyStrategies ); resources.defaultStrategyFn = runnableResources[parentRunnableId].defaultStrategyFn; } runnableResources[id] = resources; }; var clearResourcesForRunnable = function(id) { spyRegistry.clearSpies(); delete runnableResources[id]; }; var beforeAndAfterFns = function(targetSuite) { return function() { var befores = [], afters = [], suite = targetSuite; while (suite) { befores = befores.concat(suite.beforeFns); afters = afters.concat(suite.afterFns); suite = suite.parentSuite; } return { befores: befores.reverse(), afters: afters }; }; }; var getSpecName = function(spec, suite) { var fullName = [spec.description], suiteFullName = suite.getFullName(); if (suiteFullName !== '') { fullName.unshift(suiteFullName); } return fullName.join(' '); }; // TODO: we may just be able to pass in the fn instead of wrapping here var buildExpectationResult = j$.buildExpectationResult, exceptionFormatter = new j$.ExceptionFormatter(), expectationResultFactory = function(attrs) { attrs.messageFormatter = exceptionFormatter.message; attrs.stackFormatter = exceptionFormatter.stack; return buildExpectationResult(attrs); }; /** * Causes a deprecation warning to be logged to the console and reported to * reporters. * * The optional second parameter is an object that can have either of the * following properties: * * omitStackTrace: Whether to omit the stack trace. Optional. Defaults to * false. This option is ignored if the deprecation is an Error. Set this * when the stack trace will not contain anything that helps the user find * the source of the deprecation. * * ignoreRunnable: Whether to log the deprecation on the root suite, ignoring * the spec or suite that's running when it happens. Optional. Defaults to * false. * * @name Env#deprecated * @since 2.99 * @function * @param {String|Error} deprecation The deprecation message * @param {Object} [options] Optional extra options, as described above */ this.deprecated = function(deprecation, options) { var runnable = currentRunnable() || topSuite; deprecator.addDeprecationWarning(runnable, deprecation, options); }; var queueRunnerFactory = function(options, args) { if (options.isLeaf) { // A spec options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; } else if (options.isReporter) { // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; } else { // A suite if (config.stopOnSpecFailure) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; } else { options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; } } options.clearStack = options.clearStack || clearStack; options.timeout = { setTimeout: realSetTimeout, clearTimeout: realClearTimeout }; options.fail = self.fail; options.globalErrors = globalErrors; options.onException = options.onException || function(e) { (currentRunnable() || topSuite).onException(e); }; options.deprecated = self.deprecated; new j$.QueueRunner(options).execute(args); }; var topSuite = new j$.Suite({ id: getNextSuiteId(), description: 'Jasmine__TopLevel__Suite', expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, autoCleanClosures: config.autoCleanClosures, onLateError: recordLateError }); var deprecator = new j$.Deprecator(topSuite); currentDeclarationSuite = topSuite; /** * Provides the root suite, through which all suites and specs can be * accessed. * @function * @name Env#topSuite * @return {Suite} the root suite * @since 2.0.0 */ this.topSuite = function() { return topSuite.metadata; }; /** * This represents the available reporter callback for an object passed to {@link Env#addReporter}. * @interface Reporter * @see custom_reporter */ var reporter = new j$.ReportDispatcher( [ /** * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts. * @function * @name Reporter#jasmineStarted * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'jasmineStarted', /** * When the entire suite has finished execution `jasmineDone` is called * @function * @name Reporter#jasmineDone * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'jasmineDone', /** * `suiteStarted` is invoked when a `describe` starts to run * @function * @name Reporter#suiteStarted * @param {SuiteResult} result Information about the individual {@link describe} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'suiteStarted', /** * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run * * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`. * @function * @name Reporter#suiteDone * @param {SuiteResult} result * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'suiteDone', /** * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions) * @function * @name Reporter#specStarted * @param {SpecResult} result Information about the individual {@link it} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'specStarted', /** * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run. * * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed. * @function * @name Reporter#specDone * @param {SpecResult} result * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'specDone' ], queueRunnerFactory, recordLateError ); /** * Executes the specs. * * If called with no parameters or with a falsy value as the first parameter, * all specs will be executed except those that are excluded by a * [spec filter]{@link Configuration#specFilter} or other mechanism. If the * first parameter is a list of spec/suite IDs, only those specs/suites will * be run. * * Both parameters are optional, but a completion callback is only valid as * the second parameter. To specify a completion callback but not a list of * specs/suites to run, pass null or undefined as the first parameter. The * completion callback is supported for backward compatibility. In most * cases it will be more convenient to use the returned promise instead. * * execute should not be called more than once unless the env has been * configured with `{autoCleanClosures: false}`. * * execute returns a promise. The promise will be resolved to the same * {@link JasmineDoneInfo|overall result} that's passed to a reporter's * `jasmineDone` method, even if the suite did not pass. To determine * whether the suite passed, check the value that the promise resolves to * or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { topSuite.reset(); } this._executedBefore = true; defaultResourcesForRunnable(topSuite.id); installGlobalErrors(); if (!runnablesToRun) { if (focusedRunnables.length) { runnablesToRun = focusedRunnables; } else { runnablesToRun = [topSuite.id]; } } var order = new j$.Order({ random: config.random, seed: config.seed }); var processor = new j$.TreeProcessor({ tree: topSuite, runnableIds: runnablesToRun, queueRunnerFactory: queueRunnerFactory, failSpecWithNoExpectations: config.failSpecWithNoExpectations, nodeStart: function(suite, next) { currentlyExecutingSuites.push(suite); defaultResourcesForRunnable(suite.id, suite.parentSuite.id); reporter.suiteStarted(suite.result, next); suite.startTimer(); }, nodeComplete: function(suite, result, next) { if (suite !== currentSuite()) { throw new Error('Tried to complete the wrong suite'); } clearResourcesForRunnable(suite.id); currentlyExecutingSuites.pop(); if (result.status === 'failed') { hasFailures = true; } suite.endTimer(); if (suite.hadBeforeAllFailure) { reportChildrenOfBeforeAllFailure(suite).then(function() { reporter.suiteDone(result, next); }); } else { reporter.suiteDone(result, next); } }, orderChildren: function(node) { return order.sort(node.children); }, excludeNode: function(spec) { return !config.specFilter(spec); } }); if (!processor.processTree().valid) { throw new Error( 'Invalid order: would cause a beforeAll or afterAll to be run multiple times' ); } var jasmineTimer = new j$.Timer(); jasmineTimer.start(); return new Promise(function(resolve) { runAll(function(jasmineDoneInfo) { if (onComplete) { onComplete(); } resolve(jasmineDoneInfo); }); }); function runAll(done) { /** * Information passed to the {@link Reporter#jasmineStarted} event. * @typedef JasmineStartedInfo * @property {Int} totalSpecsDefined - The total number of specs defined in this suite. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @since 2.0.0 */ reporter.jasmineStarted( { totalSpecsDefined: totalSpecsDefined, order: order }, function() { currentlyExecutingSuites.push(topSuite); processor.execute(function() { (async function() { if (topSuite.hadBeforeAllFailure) { await reportChildrenOfBeforeAllFailure(topSuite); } clearResourcesForRunnable(topSuite.id); currentlyExecutingSuites.pop(); var overallStatus, incompleteReason; if ( hasFailures || topSuite.result.failedExpectations.length > 0 ) { overallStatus = 'failed'; } else if (focusedRunnables.length > 0) { overallStatus = 'incomplete'; incompleteReason = 'fit() or fdescribe() was found'; } else if (totalSpecsDefined === 0) { overallStatus = 'incomplete'; incompleteReason = 'No specs found'; } else { overallStatus = 'passed'; } /** * Information passed to the {@link Reporter#jasmineDone} event. * @typedef JasmineDoneInfo * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. * @property {Int} totalTime - The total time (in ms) that it took to execute the suite * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. * @since 2.4.0 */ const jasmineDoneInfo = { overallStatus: overallStatus, totalTime: jasmineTimer.elapsed(), incompleteReason: incompleteReason, order: order, failedExpectations: topSuite.result.failedExpectations, deprecationWarnings: topSuite.result.deprecationWarnings }; reporter.jasmineDone(jasmineDoneInfo, function() { done(jasmineDoneInfo); }); })(); }); } ); } async function reportChildrenOfBeforeAllFailure(suite) { for (const child of suite.children) { if (child instanceof j$.Suite) { await new Promise(function(resolve) { reporter.suiteStarted(child.result, resolve); }); await reportChildrenOfBeforeAllFailure(child); // Marking the suite passed is consistent with how suites that // contain failed specs but no suite-level failures are reported. child.result.status = 'passed'; await new Promise(function(resolve) { reporter.suiteDone(child.result, resolve); }); } else { /* a spec */ await new Promise(function(resolve) { reporter.specStarted(child.result, resolve); }); child.addExpectationResult( false, { passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }, true ); child.result.status = 'failed'; await new Promise(function(resolve) { reporter.specDone(child.result, resolve); }); } } } }; /** * Add a custom reporter to the Jasmine environment. * @name Env#addReporter * @since 2.0.0 * @function * @param {Reporter} reporterToAdd The reporter to be added. * @see custom_reporter */ this.addReporter = function(reporterToAdd) { reporter.addReporter(reporterToAdd); }; /** * Provide a fallback reporter if no other reporters have been specified. * @name Env#provideFallbackReporter * @since 2.5.0 * @function * @param {Reporter} reporterToAdd The reporter * @see custom_reporter */ this.provideFallbackReporter = function(reporterToAdd) { reporter.provideFallbackReporter(reporterToAdd); }; /** * Clear all registered reporters * @name Env#clearReporters * @since 2.5.2 * @function */ this.clearReporters = function() { reporter.clearReporters(); }; var spyFactory = new j$.SpyFactory( function getCustomStrategies() { var runnable = currentRunnable(); if (runnable) { return runnableResources[runnable.id].customSpyStrategies; } return {}; }, function getDefaultStrategyFn() { var runnable = currentRunnable(); if (runnable) { return runnableResources[runnable.id].defaultStrategyFn; } return undefined; }, makeMatchersUtil ); var spyRegistry = new j$.SpyRegistry({ currentSpies: function() { if (!currentRunnable()) { throw new Error( 'Spies must be created in a before function or a spec' ); } return runnableResources[currentRunnable().id].spies; }, createSpy: function(name, originalFn) { return self.createSpy(name, originalFn); } }); /** * Configures whether Jasmine should allow the same function to be spied on * more than once during the execution of a spec. By default, spying on * a function that is already a spy will cause an error. * @name Env#allowRespy * @function * @since 2.5.0 * @param {boolean} allow Whether to allow respying */ this.allowRespy = function(allow) { spyRegistry.allowRespy(allow); }; this.spyOn = function() { return spyRegistry.spyOn.apply(spyRegistry, arguments); }; this.spyOnProperty = function() { return spyRegistry.spyOnProperty.apply(spyRegistry, arguments); }; this.spyOnAllFunctions = function() { return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments); }; this.createSpy = function(name, originalFn) { if (arguments.length === 1 && j$.isFunction_(name)) { originalFn = name; name = originalFn.name; } return spyFactory.createSpy(name, originalFn); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { return spyFactory.createSpyObj(baseName, methodNames, propertyNames); }; var ensureIsFunction = function(fn, caller) { if (!j$.isFunction_(fn)) { throw new Error( caller + ' expects a function argument; received ' + j$.getType_(fn) ); } }; var ensureIsFunctionOrAsync = function(fn, caller) { if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) { throw new Error( caller + ' expects a function argument; received ' + j$.getType_(fn) ); } }; function ensureIsNotNested(method) { var runnable = currentRunnable(); if (runnable !== null && runnable !== undefined) { throw new Error( "'" + method + "' should only be used in 'describe' function" ); } } var suiteFactory = function(description) { var suite = new j$.Suite({ id: getNextSuiteId(), description: description, parentSuite: currentDeclarationSuite, timer: new j$.Timer(), expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, throwOnExpectationFailure: config.stopSpecOnExpectationFailure, autoCleanClosures: config.autoCleanClosures, onLateError: recordLateError }); return suite; }; this.describe = function(description, specDefinitions) { ensureIsNotNested('describe'); ensureIsFunction(specDefinitions, 'describe'); var suite = suiteFactory(description); if (specDefinitions.length > 0) { throw new Error('describe does not expect any arguments'); } if (currentDeclarationSuite.markedExcluding) { suite.exclude(); } addSpecsToSuite(suite, specDefinitions); if (suite.parentSuite && !suite.children.length) { throw new Error('describe with no children (describe() or it())'); } return suite.metadata; }; this.xdescribe = function(description, specDefinitions) { ensureIsNotNested('xdescribe'); ensureIsFunction(specDefinitions, 'xdescribe'); var suite = suiteFactory(description); suite.exclude(); addSpecsToSuite(suite, specDefinitions); return suite.metadata; }; var focusedRunnables = []; this.fdescribe = function(description, specDefinitions) { ensureIsNotNested('fdescribe'); ensureIsFunction(specDefinitions, 'fdescribe'); var suite = suiteFactory(description); suite.isFocused = true; focusedRunnables.push(suite.id); unfocusAncestor(); addSpecsToSuite(suite, specDefinitions); return suite.metadata; }; function addSpecsToSuite(suite, specDefinitions) { var parentSuite = currentDeclarationSuite; parentSuite.addChild(suite); currentDeclarationSuite = suite; var declarationError = null; try { specDefinitions(); } catch (e) { declarationError = e; } if (declarationError) { suite.onException(declarationError); } currentDeclarationSuite = parentSuite; } function findFocusedAncestor(suite) { while (suite) { if (suite.isFocused) { return suite.id; } suite = suite.parentSuite; } return null; } function unfocusAncestor() { var focusedAncestor = findFocusedAncestor(currentDeclarationSuite); if (focusedAncestor) { for (var i = 0; i < focusedRunnables.length; i++) { if (focusedRunnables[i] === focusedAncestor) { focusedRunnables.splice(i, 1); break; } } } } var specFactory = function(description, fn, suite, timeout) { totalSpecsDefined++; var spec = new j$.Spec({ id: getNextSpecId(), beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: expectationFactory, asyncExpectationFactory: specAsyncExpectationFactory, onLateError: recordLateError, resultCallback: specResultCallback, getSpecName: function(spec) { return getSpecName(spec, suite); }, onStart: specStarted, description: description, expectationResultFactory: expectationResultFactory, queueRunnerFactory: queueRunnerFactory, userContext: function() { return suite.clonedSharedUserContext(); }, queueableFn: { fn: fn, timeout: timeout || 0 }, throwOnExpectationFailure: config.stopSpecOnExpectationFailure, autoCleanClosures: config.autoCleanClosures, timer: new j$.Timer() }); return spec; function specResultCallback(result, next) { clearResourcesForRunnable(spec.id); currentSpec = null; if (result.status === 'failed') { hasFailures = true; } reporter.specDone(result, next); } function specStarted(spec, next) { currentSpec = spec; defaultResourcesForRunnable(spec.id, suite.id); reporter.specStarted(spec.result, next); } }; this.it_ = function(description, fn, timeout) { ensureIsNotNested('it'); // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'it'); } if (timeout) { j$.util.validateTimeout(timeout); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); if (currentDeclarationSuite.markedExcluding) { spec.exclude(); } currentDeclarationSuite.addChild(spec); return spec; }; this.it = function(description, fn, timeout) { const spec = this.it_(description, fn, timeout); return spec.metadata; }; this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } var spec = this.it_.apply(this, arguments); spec.exclude('Temporarily disabled with xit'); return spec.metadata; }; this.fit = function(description, fn, timeout) { ensureIsNotNested('fit'); ensureIsFunctionOrAsync(fn, 'fit'); if (timeout) { j$.util.validateTimeout(timeout); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); unfocusAncestor(); return spec.metadata; }; /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} * @name Env#setSpecProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ this.setSpecProperty = function(key, value) { if (!currentRunnable() || currentRunnable() == currentSuite()) { throw new Error( "'setSpecProperty' was used when there was no current spec" ); } currentRunnable().setSpecProperty(key, value); }; /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} * @name Env#setSuiteProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ this.setSuiteProperty = function(key, value) { if (!currentSuite()) { throw new Error( "'setSuiteProperty' was used when there was no current suite" ); } currentSuite().setSuiteProperty(key, value); }; this.debugLog = function(msg) { var maybeSpec = currentRunnable(); if (!maybeSpec || !maybeSpec.debugLog) { throw new Error("'debugLog' was called when there was no current spec"); } maybeSpec.debugLog(msg); }; this.expect = function(actual) { if (!currentRunnable()) { throw new Error( "'expect' was used when there was no current spec, this could be because an asynchronous test timed out" ); } return currentRunnable().expect(actual); }; this.expectAsync = function(actual) { if (!currentRunnable()) { throw new Error( "'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out" ); } return currentRunnable().expectAsync(actual); }; this.beforeEach = function(beforeEachFunction, timeout) { ensureIsNotNested('beforeEach'); ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, timeout: timeout || 0 }); }; this.beforeAll = function(beforeAllFunction, timeout) { ensureIsNotNested('beforeAll'); ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, timeout: timeout || 0 }); }; this.afterEach = function(afterEachFunction, timeout) { ensureIsNotNested('afterEach'); ensureIsFunctionOrAsync(afterEachFunction, 'afterEach'); if (timeout) { j$.util.validateTimeout(timeout); } afterEachFunction.isCleanup = true; currentDeclarationSuite.afterEach({ fn: afterEachFunction, timeout: timeout || 0 }); }; this.afterAll = function(afterAllFunction, timeout) { ensureIsNotNested('afterAll'); ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.afterAll({ fn: afterAllFunction, timeout: timeout || 0 }); }; this.pending = function(message) { var fullMessage = j$.Spec.pendingSpecExceptionMessage; if (message) { fullMessage += message; } throw fullMessage; }; this.fail = function(error) { if (!currentRunnable()) { throw new Error( "'fail' was used when there was no current spec, this could be because an asynchronous test timed out" ); } var message = 'Failed'; if (error) { message += ': '; if (error.message) { message += error.message; } else if (j$.isString_(error)) { message += error; } else { // pretty print all kind of objects. This includes arrays. message += makePrettyPrinter()(error); } } currentRunnable().addExpectationResult(false, { matcherName: '', passed: false, expected: '', actual: '', message: message, error: error && error.message ? error : null }); if (config.stopSpecOnExpectationFailure) { throw new Error(message); } }; this.cleanup_ = function() { if (globalErrors) { globalErrors.uninstall(); } }; } return Env; }; getJasmineRequireObj().JsApiReporter = function(j$) { /** * @name jsApiReporter * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object. * @class * @hideconstructor */ function JsApiReporter(options) { var timer = options.timer || new j$.Timer(), status = 'loaded'; this.started = false; this.finished = false; this.runDetails = {}; this.jasmineStarted = function() { this.started = true; status = 'started'; timer.start(); }; var executionTime; this.jasmineDone = function(runDetails) { this.finished = true; this.runDetails = runDetails; executionTime = timer.elapsed(); status = 'done'; }; /** * Get the current status for the Jasmine environment. * @name jsApiReporter#status * @since 2.0.0 * @function * @return {String} - One of `loaded`, `started`, or `done` */ this.status = function() { return status; }; var suites = [], suites_hash = {}; this.suiteStarted = function(result) { suites_hash[result.id] = result; }; this.suiteDone = function(result) { storeSuite(result); }; /** * Get the results for a set of suites. * * Retrievable in slices for easier serialization. * @name jsApiReporter#suiteResults * @since 2.1.0 * @function * @param {Number} index - The position in the suites list to start from. * @param {Number} length - Maximum number of suite results to return. * @return {SuiteResult[]} */ this.suiteResults = function(index, length) { return suites.slice(index, index + length); }; function storeSuite(result) { suites.push(result); suites_hash[result.id] = result; } /** * Get all of the suites in a single object, with their `id` as the key. * @name jsApiReporter#suites * @since 2.0.0 * @function * @return {Object} - Map of suite id to {@link SuiteResult} */ this.suites = function() { return suites_hash; }; var specs = []; this.specDone = function(result) { specs.push(result); }; /** * Get the results for a set of specs. * * Retrievable in slices for easier serialization. * @name jsApiReporter#specResults * @since 2.0.0 * @function * @param {Number} index - The position in the specs list to start from. * @param {Number} length - Maximum number of specs results to return. * @return {SpecResult[]} */ this.specResults = function(index, length) { return specs.slice(index, index + length); }; /** * Get all spec results. * @name jsApiReporter#specs * @since 2.0.0 * @function * @return {SpecResult[]} */ this.specs = function() { return specs; }; /** * Get the number of milliseconds it took for the full Jasmine suite to run. * @name jsApiReporter#executionTime * @since 2.0.0 * @function * @return {Number} */ this.executionTime = function() { return executionTime; }; } return JsApiReporter; }; getJasmineRequireObj().Any = function(j$) { function Any(expectedObject) { if (typeof expectedObject === 'undefined') { throw new TypeError( 'jasmine.any() expects to be passed a constructor function. ' + 'Please pass one or use jasmine.anything() to match any object.' ); } this.expectedObject = expectedObject; } Any.prototype.asymmetricMatch = function(other) { if (this.expectedObject == String) { return typeof other == 'string' || other instanceof String; } if (this.expectedObject == Number) { return typeof other == 'number' || other instanceof Number; } if (this.expectedObject == Function) { return typeof other == 'function' || other instanceof Function; } if (this.expectedObject == Object) { return other !== null && typeof other == 'object'; } if (this.expectedObject == Boolean) { return typeof other == 'boolean'; } /* jshint -W122 */ /* global Symbol */ if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) { return typeof other == 'symbol'; } /* jshint +W122 */ return other instanceof this.expectedObject; }; Any.prototype.jasmineToString = function() { return ''; }; return Any; }; getJasmineRequireObj().Anything = function(j$) { function Anything() {} Anything.prototype.asymmetricMatch = function(other) { return !j$.util.isUndefined(other) && other !== null; }; Anything.prototype.jasmineToString = function() { return ''; }; return Anything; }; getJasmineRequireObj().ArrayContaining = function(j$) { function ArrayContaining(sample) { this.sample = sample; } ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isArray_(this.sample)) { throw new Error( 'You must provide an array to arrayContaining, not ' + j$.basicPrettyPrinter_(this.sample) + '.' ); } // If the actual parameter is not an array, we can fail immediately, since it couldn't // possibly be an "array containing" anything. However, we also want an empty sample // array to match anything, so we need to double-check we aren't in that case if (!j$.isArray_(other) && this.sample.length > 0) { return false; } for (var i = 0; i < this.sample.length; i++) { var item = this.sample[i]; if (!matchersUtil.contains(other, item)) { return false; } } return true; }; ArrayContaining.prototype.jasmineToString = function(pp) { return ''; }; return ArrayContaining; }; getJasmineRequireObj().ArrayWithExactContents = function(j$) { function ArrayWithExactContents(sample) { this.sample = sample; } ArrayWithExactContents.prototype.asymmetricMatch = function( other, matchersUtil ) { if (!j$.isArray_(this.sample)) { throw new Error( 'You must provide an array to arrayWithExactContents, not ' + j$.basicPrettyPrinter_(this.sample) + '.' ); } if (this.sample.length !== other.length) { return false; } for (var i = 0; i < this.sample.length; i++) { var item = this.sample[i]; if (!matchersUtil.contains(other, item)) { return false; } } return true; }; ArrayWithExactContents.prototype.jasmineToString = function(pp) { return ''; }; return ArrayWithExactContents; }; getJasmineRequireObj().Empty = function(j$) { function Empty() {} Empty.prototype.asymmetricMatch = function(other) { if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) { return other.length === 0; } if (j$.isMap(other) || j$.isSet(other)) { return other.size === 0; } if (j$.isObject_(other)) { return Object.keys(other).length === 0; } return false; }; Empty.prototype.jasmineToString = function() { return ''; }; return Empty; }; getJasmineRequireObj().Falsy = function(j$) { function Falsy() {} Falsy.prototype.asymmetricMatch = function(other) { return !other; }; Falsy.prototype.jasmineToString = function() { return ''; }; return Falsy; }; getJasmineRequireObj().MapContaining = function(j$) { function MapContaining(sample) { if (!j$.isMap(sample)) { throw new Error( 'You must provide a map to `mapContaining`, not ' + j$.basicPrettyPrinter_(sample) ); } this.sample = sample; } MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isMap(other)) return false; for (const [key, value] of this.sample) { // for each key/value pair in `sample` // there should be at least one pair in `other` whose key and value both match var hasMatch = false; for (const [oKey, oValue] of other) { if ( matchersUtil.equals(oKey, key) && matchersUtil.equals(oValue, value) ) { hasMatch = true; break; } } if (!hasMatch) { return false; } } return true; }; MapContaining.prototype.jasmineToString = function(pp) { return ''; }; return MapContaining; }; getJasmineRequireObj().NotEmpty = function(j$) { function NotEmpty() {} NotEmpty.prototype.asymmetricMatch = function(other) { if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) { return other.length !== 0; } if (j$.isMap(other) || j$.isSet(other)) { return other.size !== 0; } if (j$.isObject_(other)) { return Object.keys(other).length !== 0; } return false; }; NotEmpty.prototype.jasmineToString = function() { return ''; }; return NotEmpty; }; getJasmineRequireObj().ObjectContaining = function(j$) { function ObjectContaining(sample) { this.sample = sample; } function hasProperty(obj, property) { if (!obj || typeof obj !== 'object') { return false; } if (Object.prototype.hasOwnProperty.call(obj, property)) { return true; } return hasProperty(Object.getPrototypeOf(obj), property); } ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (typeof this.sample !== 'object') { throw new Error( "You must provide an object to objectContaining, not '" + this.sample + "'." ); } if (typeof other !== 'object') { return false; } for (var property in this.sample) { if ( !hasProperty(other, property) || !matchersUtil.equals(this.sample[property], other[property]) ) { return false; } } return true; }; ObjectContaining.prototype.valuesForDiff_ = function(other, pp) { if (!j$.isObject_(other)) { return { self: this.jasmineToString(pp), other: other }; } var filteredOther = {}; Object.keys(this.sample).forEach(function(k) { // eq short-circuits comparison of objects that have different key sets, // so include all keys even if undefined. filteredOther[k] = other[k]; }); return { self: this.sample, other: filteredOther }; }; ObjectContaining.prototype.jasmineToString = function(pp) { return ''; }; return ObjectContaining; }; getJasmineRequireObj().SetContaining = function(j$) { function SetContaining(sample) { if (!j$.isSet(sample)) { throw new Error( 'You must provide a set to `setContaining`, not ' + j$.basicPrettyPrinter_(sample) ); } this.sample = sample; } SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isSet(other)) return false; for (const item of this.sample) { // for each item in `sample` there should be at least one matching item in `other` // (not using `matchersUtil.contains` because it compares set members by reference, // not by deep value equality) var hasMatch = false; for (const oItem of other) { if (matchersUtil.equals(oItem, item)) { hasMatch = true; break; } } if (!hasMatch) { return false; } } return true; }; SetContaining.prototype.jasmineToString = function(pp) { return ''; }; return SetContaining; }; getJasmineRequireObj().StringContaining = function(j$) { function StringContaining(expected) { if (!j$.isString_(expected)) { throw new Error('Expected is not a String'); } this.expected = expected; } StringContaining.prototype.asymmetricMatch = function(other) { if (!j$.isString_(other)) { // Arrays, etc. don't match no matter what their indexOf returns. return false; } return other.indexOf(this.expected) !== -1; }; StringContaining.prototype.jasmineToString = function() { return ''; }; return StringContaining; }; getJasmineRequireObj().StringMatching = function(j$) { function StringMatching(expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { throw new Error('Expected is not a String or a RegExp'); } this.regexp = new RegExp(expected); } StringMatching.prototype.asymmetricMatch = function(other) { return this.regexp.test(other); }; StringMatching.prototype.jasmineToString = function() { return ''; }; return StringMatching; }; getJasmineRequireObj().Truthy = function(j$) { function Truthy() {} Truthy.prototype.asymmetricMatch = function(other) { return !!other; }; Truthy.prototype.jasmineToString = function() { return ''; }; return Truthy; }; getJasmineRequireObj().CallTracker = function(j$) { /** * @namespace Spy#calls * @since 2.0.0 */ function CallTracker() { var calls = []; var opts = {}; this.track = function(context) { if (opts.cloneArgs) { context.args = j$.util.cloneArgs(context.args); } calls.push(context); }; /** * Check whether this spy has been invoked. * @name Spy#calls#any * @since 2.0.0 * @function * @return {Boolean} */ this.any = function() { return !!calls.length; }; /** * Get the number of invocations of this spy. * @name Spy#calls#count * @since 2.0.0 * @function * @return {Integer} */ this.count = function() { return calls.length; }; /** * Get the arguments that were passed to a specific invocation of this spy. * @name Spy#calls#argsFor * @since 2.0.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Array} */ this.argsFor = function(index) { var call = calls[index]; return call ? call.args : []; }; /** * Get the "this" object that was passed to a specific invocation of this spy. * @name Spy#calls#thisFor * @since 3.8.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Object?} */ this.thisFor = function(index) { var call = calls[index]; return call ? call.object : undefined; }; /** * Get the raw calls array for this spy. * @name Spy#calls#all * @since 2.0.0 * @function * @return {Spy.callData[]} */ this.all = function() { return calls; }; /** * Get all of the arguments for each invocation of this spy in the order they were received. * @name Spy#calls#allArgs * @since 2.0.0 * @function * @return {Array} */ this.allArgs = function() { var callArgs = []; for (var i = 0; i < calls.length; i++) { callArgs.push(calls[i].args); } return callArgs; }; /** * Get the first invocation of this spy. * @name Spy#calls#first * @since 2.0.0 * @function * @return {ObjecSpy.callData} */ this.first = function() { return calls[0]; }; /** * Get the most recent invocation of this spy. * @name Spy#calls#mostRecent * @since 2.0.0 * @function * @return {ObjecSpy.callData} */ this.mostRecent = function() { return calls[calls.length - 1]; }; /** * Reset this spy as if it has never been called. * @name Spy#calls#reset * @since 2.0.0 * @function */ this.reset = function() { calls = []; }; /** * Set this spy to do a shallow clone of arguments passed to each invocation. * @name Spy#calls#saveArgumentsByValue * @since 2.5.0 * @function */ this.saveArgumentsByValue = function() { opts.cloneArgs = true; }; } return CallTracker; }; getJasmineRequireObj().clearStack = function(j$) { var maxInlineCallCount = 10; function messageChannelImpl(global, setTimeout) { var channel = new global.MessageChannel(), head = {}, tail = head; var taskRunning = false; channel.port1.onmessage = function() { head = head.next; var task = head.task; delete head.task; if (taskRunning) { global.setTimeout(task, 0); } else { try { taskRunning = true; task(); } finally { taskRunning = false; } } }; var currentCallCount = 0; return function clearStack(fn) { currentCallCount++; if (currentCallCount < maxInlineCallCount) { tail = tail.next = { task: fn }; channel.port2.postMessage(0); } else { currentCallCount = 0; setTimeout(fn); } }; } function getClearStack(global) { var currentCallCount = 0; var realSetTimeout = global.setTimeout; var setTimeoutImpl = function clearStack(fn) { Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]); }; if (j$.isFunction_(global.setImmediate)) { var realSetImmediate = global.setImmediate; return function(fn) { currentCallCount++; if (currentCallCount < maxInlineCallCount) { realSetImmediate(fn); } else { currentCallCount = 0; setTimeoutImpl(fn); } }; } else if (!j$.util.isUndefined(global.MessageChannel)) { return messageChannelImpl(global, setTimeoutImpl); } else { return setTimeoutImpl; } } return getClearStack; }; getJasmineRequireObj().Clock = function() { /* global process */ var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string'; /** * @class Clock * @since 1.3.0 * @classdesc Jasmine's mock clock is used when testing time dependent code.
* _Note:_ Do not construct this directly. You can get the current clock with * {@link jasmine.clock}. * @hideconstructor */ function Clock(global, delayedFunctionSchedulerFactory, mockDate) { var self = this, realTimingFunctions = { setTimeout: global.setTimeout, clearTimeout: global.clearTimeout, setInterval: global.setInterval, clearInterval: global.clearInterval }, fakeTimingFunctions = { setTimeout: setTimeout, clearTimeout: clearTimeout, setInterval: setInterval, clearInterval: clearInterval }, installed = false, delayedFunctionScheduler, timer; self.FakeTimeout = FakeTimeout; /** * Install the mock clock over the built-in methods. * @name Clock#install * @since 2.0.0 * @function * @return {Clock} */ self.install = function() { if (!originalTimingFunctionsIntact()) { throw new Error( 'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?' ); } replace(global, fakeTimingFunctions); timer = fakeTimingFunctions; delayedFunctionScheduler = delayedFunctionSchedulerFactory(); installed = true; return self; }; /** * Uninstall the mock clock, returning the built-in methods to their places. * @name Clock#uninstall * @since 2.0.0 * @function */ self.uninstall = function() { delayedFunctionScheduler = null; mockDate.uninstall(); replace(global, realTimingFunctions); timer = realTimingFunctions; installed = false; }; /** * Execute a function with a mocked Clock * * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes. * @name Clock#withMock * @since 2.3.0 * @function * @param {Function} closure The function to be called. */ self.withMock = function(closure) { this.install(); try { closure(); } finally { this.uninstall(); } }; /** * Instruct the installed Clock to also mock the date returned by `new Date()` * @name Clock#mockDate * @since 2.1.0 * @function * @param {Date} [initialDate=now] The `Date` to provide. */ self.mockDate = function(initialDate) { mockDate.install(initialDate); }; self.setTimeout = function(fn, delay, params) { return Function.prototype.apply.apply(timer.setTimeout, [ global, arguments ]); }; self.setInterval = function(fn, delay, params) { return Function.prototype.apply.apply(timer.setInterval, [ global, arguments ]); }; self.clearTimeout = function(id) { return Function.prototype.call.apply(timer.clearTimeout, [global, id]); }; self.clearInterval = function(id) { return Function.prototype.call.apply(timer.clearInterval, [global, id]); }; /** * Tick the Clock forward, running any enqueued timeouts along the way * @name Clock#tick * @since 1.3.0 * @function * @param {int} millis The number of milliseconds to tick. */ self.tick = function(millis) { if (installed) { delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); }); } else { throw new Error( 'Mock clock is not installed, use jasmine.clock().install()' ); } }; return self; function originalTimingFunctionsIntact() { return ( global.setTimeout === realTimingFunctions.setTimeout && global.clearTimeout === realTimingFunctions.clearTimeout && global.setInterval === realTimingFunctions.setInterval && global.clearInterval === realTimingFunctions.clearInterval ); } function replace(dest, source) { for (var prop in source) { dest[prop] = source[prop]; } } function setTimeout(fn, delay) { if (!NODE_JS) { return delayedFunctionScheduler.scheduleFunction( fn, delay, argSlice(arguments, 2) ); } var timeout = new FakeTimeout(); delayedFunctionScheduler.scheduleFunction( fn, delay, argSlice(arguments, 2), false, timeout ); return timeout; } function clearTimeout(id) { return delayedFunctionScheduler.removeFunctionWithId(id); } function setInterval(fn, interval) { if (!NODE_JS) { return delayedFunctionScheduler.scheduleFunction( fn, interval, argSlice(arguments, 2), true ); } var timeout = new FakeTimeout(); delayedFunctionScheduler.scheduleFunction( fn, interval, argSlice(arguments, 2), true, timeout ); return timeout; } function clearInterval(id) { return delayedFunctionScheduler.removeFunctionWithId(id); } function argSlice(argsObj, n) { return Array.prototype.slice.call(argsObj, n); } } /** * Mocks Node.js Timeout class */ function FakeTimeout() {} FakeTimeout.prototype.ref = function() { return this; }; FakeTimeout.prototype.unref = function() { return this; }; return Clock; }; getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.erroredFnIx_ = null; } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { let i; for ( i = lastRanFnIx + 1; i < this.queueableFns_.length && this.shouldSkip_(i); i++ ) {} return i; }; CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { this.erroredFnIx_ = fnIx; }; CompleteOnFirstErrorSkipPolicy.prototype.shouldSkip_ = function(fnIx) { if (this.erroredFnIx_ === null) { return false; } const fn = this.queueableFns_[fnIx]; const candidateSuite = fn.suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; const wasCleanupFn = fn.type === 'afterEach' || fn.type === 'afterAll' || fn.type === 'specCleanup'; return ( !wasCleanupFn || (candidateSuite && isDescendent(candidateSuite, errorSuite)) ); }; function isDescendent(candidate, ancestor) { if (!candidate.parentSuite) { return false; } else if (candidate.parentSuite === ancestor) { return true; } else { return isDescendent(candidate.parentSuite, ancestor); } } return CompleteOnFirstErrorSkipPolicy; }; getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function DelayedFunctionScheduler() { var self = this; var scheduledLookup = []; var scheduledFunctions = {}; var currentTime = 0; var delayedFnCount = 0; var deletedKeys = []; self.tick = function(millis, tickDate) { millis = millis || 0; var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); }; self.scheduleFunction = function( funcToCall, millis, params, recurring, timeoutKey, runAtMillis ) { var f; if (typeof funcToCall === 'string') { /* jshint evil: true */ f = function() { return eval(funcToCall); }; /* jshint evil: false */ } else { f = funcToCall; } millis = millis || 0; timeoutKey = timeoutKey || ++delayedFnCount; runAtMillis = runAtMillis || currentTime + millis; var funcToSchedule = { runAtMillis: runAtMillis, funcToCall: f, recurring: recurring, params: params, timeoutKey: timeoutKey, millis: millis }; if (runAtMillis in scheduledFunctions) { scheduledFunctions[runAtMillis].push(funcToSchedule); } else { scheduledFunctions[runAtMillis] = [funcToSchedule]; scheduledLookup.push(runAtMillis); scheduledLookup.sort(function(a, b) { return a - b; }); } return timeoutKey; }; self.removeFunctionWithId = function(timeoutKey) { deletedKeys.push(timeoutKey); for (var runAtMillis in scheduledFunctions) { var funcs = scheduledFunctions[runAtMillis]; var i = indexOfFirstToPass(funcs, function(func) { return func.timeoutKey === timeoutKey; }); if (i > -1) { if (funcs.length === 1) { delete scheduledFunctions[runAtMillis]; deleteFromLookup(runAtMillis); } else { funcs.splice(i, 1); } // intervals get rescheduled when executed, so there's never more // than a single scheduled function with a given timeoutKey break; } } }; return self; function indexOfFirstToPass(array, testFn) { var index = -1; for (var i = 0; i < array.length; ++i) { if (testFn(array[i])) { index = i; break; } } return index; } function deleteFromLookup(key) { var value = Number(key); var i = indexOfFirstToPass(scheduledLookup, function(millis) { return millis === value; }); if (i > -1) { scheduledLookup.splice(i, 1); } } function reschedule(scheduledFn) { self.scheduleFunction( scheduledFn.funcToCall, scheduledFn.millis, scheduledFn.params, true, scheduledFn.timeoutKey, scheduledFn.runAtMillis + scheduledFn.millis ); } function forEachFunction(funcsToRun, callback) { for (var i = 0; i < funcsToRun.length; ++i) { callback(funcsToRun[i]); } } function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { if (endTime >= currentTime) { tickDate(endTime - currentTime); currentTime = endTime; } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); if (newCurrentTime >= currentTime) { tickDate(newCurrentTime - currentTime); currentTime = newCurrentTime; } var funcsToRun = scheduledFunctions[currentTime]; delete scheduledFunctions[currentTime]; forEachFunction(funcsToRun, function(funcToRun) { if (funcToRun.recurring) { reschedule(funcToRun); } }); forEachFunction(funcsToRun, function(funcToRun) { if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) { // skip a timeoutKey deleted whilst we were running return; } funcToRun.funcToCall.apply(null, funcToRun.params || []); }); deletedKeys = []; } while ( scheduledLookup.length > 0 && // checking first if we're out of time prevents setTimeout(0) // scheduled in a funcToRun from forcing an extra iteration currentTime !== endTime && scheduledLookup[0] <= endTime ); // ran out of functions to call, but still time left on the clock if (endTime >= currentTime) { tickDate(endTime - currentTime); currentTime = endTime; } } } return DelayedFunctionScheduler; }; getJasmineRequireObj().Deprecator = function(j$) { function Deprecator(topSuite) { this.topSuite_ = topSuite; this.verbose_ = false; this.toSuppress_ = []; } var verboseNote = 'Note: This message will be shown only once. Set the verboseDeprecations ' + 'config property to true to see every occurrence.'; Deprecator.prototype.verboseDeprecations = function(enabled) { this.verbose_ = enabled; }; // runnable is a spec or a suite. // deprecation is a string or an Error. // See Env#deprecated for a description of the options argument. Deprecator.prototype.addDeprecationWarning = function( runnable, deprecation, options ) { options = options || {}; if (!this.verbose_ && !j$.isError_(deprecation)) { if (this.toSuppress_.indexOf(deprecation) !== -1) { return; } this.toSuppress_.push(deprecation); } this.log_(runnable, deprecation, options); this.report_(runnable, deprecation, options); }; Deprecator.prototype.log_ = function(runnable, deprecation, options) { var context; if (j$.isError_(deprecation)) { console.error(deprecation); return; } if (runnable === this.topSuite_ || options.ignoreRunnable) { context = ''; } else if (runnable.children) { context = ' (in suite: ' + runnable.getFullName() + ')'; } else { context = ' (in spec: ' + runnable.getFullName() + ')'; } if (!options.omitStackTrace) { context += '\n' + this.stackTrace_(); } if (!this.verbose_) { context += '\n' + verboseNote; } console.error('DEPRECATION: ' + deprecation + context); }; Deprecator.prototype.stackTrace_ = function() { var formatter = new j$.ExceptionFormatter(); return formatter.stack(j$.util.errorWithStack()).replace(/^Error\n/m, ''); }; Deprecator.prototype.report_ = function(runnable, deprecation, options) { if (options.ignoreRunnable) { runnable = this.topSuite_; } if (j$.isError_(deprecation)) { runnable.addDeprecationWarning(deprecation); return; } if (!this.verbose_) { deprecation += '\n' + verboseNote; } runnable.addDeprecationWarning({ message: deprecation, omitStackTrace: options.omitStackTrace || false }); }; return Deprecator; }; getJasmineRequireObj().errors = function() { function ExpectationFailed() {} ExpectationFailed.prototype = new Error(); ExpectationFailed.prototype.constructor = ExpectationFailed; return { ExpectationFailed: ExpectationFailed }; }; getJasmineRequireObj().ExceptionFormatter = function(j$) { var ignoredProperties = [ 'name', 'message', 'stack', 'fileName', 'sourceURL', 'line', 'lineNumber', 'column', 'description', 'jasmineMessage' ]; function ExceptionFormatter(options) { var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile(); this.message = function(error) { var message = ''; if (error.jasmineMessage) { message += error.jasmineMessage; } else if (error.name && error.message) { message += error.name + ': ' + error.message; } else if (error.message) { message += error.message; } else { message += error.toString() + ' thrown'; } if (error.fileName || error.sourceURL) { message += ' in ' + (error.fileName || error.sourceURL); } if (error.line || error.lineNumber) { message += ' (line ' + (error.line || error.lineNumber) + ')'; } return message; }; this.stack = function(error, { omitMessage } = {}) { if (!error || !error.stack) { return null; } var stackTrace = new j$.StackTrace(error); var lines = filterJasmine(stackTrace); var result = ''; if (stackTrace.message && !omitMessage) { lines.unshift(stackTrace.message); } result += formatProperties(error); result += lines.join('\n'); return result; }; function filterJasmine(stackTrace) { var result = [], jasmineMarker = stackTrace.style === 'webkit' ? '' : ' at '; stackTrace.frames.forEach(function(frame) { if (frame.file !== jasmineFile) { result.push(frame.raw); } else if (result[result.length - 1] !== jasmineMarker) { result.push(jasmineMarker); } }); return result; } function formatProperties(error) { if (!(error instanceof Object)) { return; } var result = {}; var empty = true; for (var prop in error) { if (j$.util.arrayContains(ignoredProperties, prop)) { continue; } result[prop] = error[prop]; empty = false; } if (!empty) { return 'error properties: ' + j$.basicPrettyPrinter_(result) + '\n'; } return ''; } } return ExceptionFormatter; }; getJasmineRequireObj().Expectation = function(j$) { /** * Matchers that come with Jasmine out of the box. * @namespace matchers */ function Expectation(options) { this.expector = new j$.Expector(options); var customMatchers = options.customMatchers || {}; for (var matcherName in customMatchers) { this[matcherName] = wrapSyncCompare( matcherName, customMatchers[matcherName] ); } } /** * Add some context for an {@link expect} * @function * @name matchers#withContext * @since 3.3.0 * @param {String} message - Additional context to show when the matcher fails * @return {matchers} */ Expectation.prototype.withContext = function withContext(message) { return addFilter(this, new ContextAddingFilter(message)); }; /** * Invert the matcher following this {@link expect} * @member * @name matchers#not * @since 1.3.0 * @type {matchers} * @example * expect(something).not.toBe(true); */ Object.defineProperty(Expectation.prototype, 'not', { get: function() { return addFilter(this, syncNegatingFilter); } }); /** * Asynchronous matchers that operate on an actual value which is a promise, * and return a promise. * * Most async matchers will wait indefinitely for the promise to be resolved * or rejected, resulting in a spec timeout if that never happens. If you * expect that the promise will already be resolved or rejected at the time * the matcher is called, you can use the {@link async-matchers#already} * modifier to get a faster failure with a more helpful message. * * Note: Specs must await the result of each async matcher, return the * promise returned by the matcher, or return a promise that's derived from * the one returned by the matcher. Otherwise the matcher will not be * evaluated before the spec completes. * * @example * // Good * await expectAsync(aPromise).toBeResolved(); * @example * // Good * return expectAsync(aPromise).toBeResolved(); * @example * // Good * return expectAsync(aPromise).toBeResolved() * .then(function() { * // more spec code * }); * @example * // Bad * expectAsync(aPromise).toBeResolved(); * @namespace async-matchers */ function AsyncExpectation(options) { this.expector = new j$.Expector(options); var customAsyncMatchers = options.customAsyncMatchers || {}; for (var matcherName in customAsyncMatchers) { this[matcherName] = wrapAsyncCompare( matcherName, customAsyncMatchers[matcherName] ); } } /** * Add some context for an {@link expectAsync} * @function * @name async-matchers#withContext * @since 3.3.0 * @param {String} message - Additional context to show when the async matcher fails * @return {async-matchers} */ AsyncExpectation.prototype.withContext = function withContext(message) { return addFilter(this, new ContextAddingFilter(message)); }; /** * Invert the matcher following this {@link expectAsync} * @member * @name async-matchers#not * @type {async-matchers} * @example * await expectAsync(myPromise).not.toBeResolved(); * @example * return expectAsync(myPromise).not.toBeResolved(); */ Object.defineProperty(AsyncExpectation.prototype, 'not', { get: function() { return addFilter(this, asyncNegatingFilter); } }); /** * Fail as soon as possible if the actual is pending. * Otherwise evaluate the matcher. * @member * @name async-matchers#already * @since 3.8.0 * @type {async-matchers} * @example * await expectAsync(myPromise).already.toBeResolved(); * @example * return expectAsync(myPromise).already.toBeResolved(); */ Object.defineProperty(AsyncExpectation.prototype, 'already', { get: function() { return addFilter(this, expectSettledPromiseFilter); } }); function wrapSyncCompare(name, matcherFactory) { return function() { var result = this.expector.compare(name, matcherFactory, arguments); this.expector.processResult(result); }; } function wrapAsyncCompare(name, matcherFactory) { return function() { var self = this; // Capture the call stack here, before we go async, so that it will contain // frames that are relevant to the user instead of just parts of Jasmine. var errorForStack = j$.util.errorWithStack(); return this.expector .compare(name, matcherFactory, arguments) .then(function(result) { self.expector.processResult(result, errorForStack); }); }; } function addCoreMatchers(prototype, matchers, wrapper) { for (var matcherName in matchers) { var matcher = matchers[matcherName]; prototype[matcherName] = wrapper(matcherName, matcher); } } function addFilter(source, filter) { var result = Object.create(source); result.expector = source.expector.addFilter(filter); return result; } function negatedFailureMessage(result, matcherName, args, matchersUtil) { if (result.message) { if (j$.isFunction_(result.message)) { return result.message(); } else { return result.message; } } args = args.slice(); args.unshift(true); args.unshift(matcherName); return matchersUtil.buildFailureMessage.apply(matchersUtil, args); } function negate(result) { result.pass = !result.pass; return result; } var syncNegatingFilter = { selectComparisonFunc: function(matcher) { function defaultNegativeCompare() { return negate(matcher.compare.apply(null, arguments)); } return matcher.negativeCompare || defaultNegativeCompare; }, buildFailureMessage: negatedFailureMessage }; var asyncNegatingFilter = { selectComparisonFunc: function(matcher) { function defaultNegativeCompare() { return matcher.compare.apply(this, arguments).then(negate); } return matcher.negativeCompare || defaultNegativeCompare; }, buildFailureMessage: negatedFailureMessage }; var expectSettledPromiseFilter = { selectComparisonFunc: function(matcher) { return function(actual) { var matcherArgs = arguments; return j$.isPending_(actual).then(function(isPending) { if (isPending) { return { pass: false, message: 'Expected a promise to be settled (via ' + 'expectAsync(...).already) but it was pending.' }; } else { return matcher.compare.apply(null, matcherArgs); } }); }; } }; function ContextAddingFilter(message) { this.message = message; } ContextAddingFilter.prototype.modifyFailureMessage = function(msg) { var nl = msg.indexOf('\n'); if (nl === -1) { return this.message + ': ' + msg; } else { return this.message + ':\n' + indent(msg); } }; function indent(s) { return s.replace(/^/gm, ' '); } return { factory: function(options) { return new Expectation(options || {}); }, addCoreMatchers: function(matchers) { addCoreMatchers(Expectation.prototype, matchers, wrapSyncCompare); }, asyncFactory: function(options) { return new AsyncExpectation(options || {}); }, addAsyncCoreMatchers: function(matchers) { addCoreMatchers(AsyncExpectation.prototype, matchers, wrapAsyncCompare); } }; }; getJasmineRequireObj().ExpectationFilterChain = function() { function ExpectationFilterChain(maybeFilter, prev) { this.filter_ = maybeFilter; this.prev_ = prev; } ExpectationFilterChain.prototype.addFilter = function(filter) { return new ExpectationFilterChain(filter, this); }; ExpectationFilterChain.prototype.selectComparisonFunc = function(matcher) { return this.callFirst_('selectComparisonFunc', arguments).result; }; ExpectationFilterChain.prototype.buildFailureMessage = function( result, matcherName, args, matchersUtil ) { return this.callFirst_('buildFailureMessage', arguments).result; }; ExpectationFilterChain.prototype.modifyFailureMessage = function(msg) { var result = this.callFirst_('modifyFailureMessage', arguments).result; return result || msg; }; ExpectationFilterChain.prototype.callFirst_ = function(fname, args) { var prevResult; if (this.prev_) { prevResult = this.prev_.callFirst_(fname, args); if (prevResult.found) { return prevResult; } } if (this.filter_ && this.filter_[fname]) { return { found: true, result: this.filter_[fname].apply(this.filter_, args) }; } return { found: false }; }; return ExpectationFilterChain; }; //TODO: expectation result may make more sense as a presentation of an expectation. getJasmineRequireObj().buildExpectationResult = function(j$) { function buildExpectationResult(options) { var messageFormatter = options.messageFormatter || function() {}, stackFormatter = options.stackFormatter || function() {}; /** * @typedef Expectation * @property {String} matcherName - The name of the matcher that was executed for this expectation. * @property {String} message - The failure message for the expectation. * @property {String} stack - The stack trace for the failure if available. * @property {Boolean} passed - Whether the expectation passed or failed. * @property {Object} expected - If the expectation failed, what was the expected value. * @property {Object} actual - If the expectation failed, what actual value was produced. * @property {String|undefined} globalErrorType - The type of an error that * is reported on the top suite. Valid values are undefined, "afterAll", * "load", "lateExpectation", and "lateError". */ var result = { matcherName: options.matcherName, message: message(), stack: options.omitStackTrace ? '' : stack(), passed: options.passed }; if (!result.passed) { result.expected = options.expected; result.actual = options.actual; if (options.error && !j$.isString_(options.error)) { if ('code' in options.error) { result.code = options.error.code; } if ( options.error.code === 'ERR_ASSERTION' && options.expected === '' && options.actual === '' ) { result.expected = options.error.expected; result.actual = options.error.actual; result.matcherName = 'assert ' + options.error.operator; } } } return result; function message() { if (options.passed) { return 'Passed.'; } else if (options.message) { return options.message; } else if (options.error) { return messageFormatter(options.error); } return ''; } function stack() { if (options.passed) { return ''; } var error = options.error; if (!error) { if (options.errorForStack) { error = options.errorForStack; } else if (options.stack) { error = options; } else { try { throw new Error(message()); } catch (e) { error = e; } } } // Omit the message from the stack trace because it will be // included elsewhere. return stackFormatter(error, { omitMessage: true }); } } return buildExpectationResult; }; getJasmineRequireObj().Expector = function(j$) { function Expector(options) { this.matchersUtil = options.matchersUtil || { buildFailureMessage: function() {} }; this.actual = options.actual; this.addExpectationResult = options.addExpectationResult || function() {}; this.filters = new j$.ExpectationFilterChain(); } Expector.prototype.instantiateMatcher = function( matcherName, matcherFactory, args ) { this.matcherName = matcherName; this.args = Array.prototype.slice.call(args, 0); this.expected = this.args.slice(0); this.args.unshift(this.actual); var matcher = matcherFactory(this.matchersUtil); var comparisonFunc = this.filters.selectComparisonFunc(matcher); return comparisonFunc || matcher.compare; }; Expector.prototype.buildMessage = function(result) { var self = this; if (result.pass) { return ''; } var msg = this.filters.buildFailureMessage( result, this.matcherName, this.args, this.matchersUtil, defaultMessage ); return this.filters.modifyFailureMessage(msg || defaultMessage()); function defaultMessage() { if (!result.message) { var args = self.args.slice(); args.unshift(false); args.unshift(self.matcherName); return self.matchersUtil.buildFailureMessage.apply( self.matchersUtil, args ); } else if (j$.isFunction_(result.message)) { return result.message(); } else { return result.message; } } }; Expector.prototype.compare = function(matcherName, matcherFactory, args) { var matcherCompare = this.instantiateMatcher( matcherName, matcherFactory, args ); return matcherCompare.apply(null, this.args); }; Expector.prototype.addFilter = function(filter) { var result = Object.create(this); result.filters = this.filters.addFilter(filter); return result; }; Expector.prototype.processResult = function(result, errorForStack) { var message = this.buildMessage(result); if (this.expected.length === 1) { this.expected = this.expected[0]; } this.addExpectationResult(result.pass, { matcherName: this.matcherName, passed: result.pass, message: message, error: errorForStack ? undefined : result.error, errorForStack: errorForStack || undefined, actual: this.actual, expected: this.expected // TODO: this may need to be arrayified/sliced }); }; return Expector; }; getJasmineRequireObj().formatErrorMsg = function() { function generateErrorMsg(domain, usage) { var usageDefinition = usage ? '\nUsage: ' + usage : ''; return function errorMsg(msg) { return domain + ' : ' + msg + usageDefinition; }; } return generateErrorMsg; }; getJasmineRequireObj().GlobalErrors = function(j$) { function GlobalErrors(global) { var handlers = []; global = global || j$.getGlobal(); var onerror = function onerror() { var handler = handlers[handlers.length - 1]; if (handler) { handler.apply(null, Array.prototype.slice.call(arguments, 0)); } else { throw arguments[0]; } }; this.originalHandlers = {}; this.jasmineHandlers = {}; this.installOne_ = function installOne_(errorType, jasmineMessage) { function taggedOnError(error) { var substituteMsg; if (j$.isError_(error)) { error.jasmineMessage = jasmineMessage + ': ' + error; } else { if (error) { substituteMsg = jasmineMessage + ': ' + error; } else { substituteMsg = jasmineMessage + ' with no error or message'; } if (errorType === 'unhandledRejection') { substituteMsg += '\n' + '(Tip: to get a useful stack trace, use ' + 'Promise.reject(new Error(...)) instead of Promise.reject(' + (error ? '...' : '') + ').)'; } error = new Error(substituteMsg); } var handler = handlers[handlers.length - 1]; if (handler) { handler(error); } else { throw error; } } this.originalHandlers[errorType] = global.process.listeners(errorType); this.jasmineHandlers[errorType] = taggedOnError; global.process.removeAllListeners(errorType); global.process.on(errorType, taggedOnError); this.uninstall = function uninstall() { var errorTypes = Object.keys(this.originalHandlers); for (var iType = 0; iType < errorTypes.length; iType++) { var errorType = errorTypes[iType]; global.process.removeListener( errorType, this.jasmineHandlers[errorType] ); for (var i = 0; i < this.originalHandlers[errorType].length; i++) { global.process.on(errorType, this.originalHandlers[errorType][i]); } delete this.originalHandlers[errorType]; delete this.jasmineHandlers[errorType]; } }; }; this.install = function install() { if ( global.process && global.process.listeners && j$.isFunction_(global.process.on) ) { this.installOne_('uncaughtException', 'Uncaught exception'); this.installOne_('unhandledRejection', 'Unhandled promise rejection'); } else { var originalHandler = global.onerror; global.onerror = onerror; var browserRejectionHandler = function browserRejectionHandler(event) { if (j$.isError_(event.reason)) { event.reason.jasmineMessage = 'Unhandled promise rejection: ' + event.reason; global.onerror(event.reason); } else { global.onerror('Unhandled promise rejection: ' + event.reason); } }; if (global.addEventListener) { global.addEventListener( 'unhandledrejection', browserRejectionHandler ); } this.uninstall = function uninstall() { global.onerror = originalHandler; if (global.removeEventListener) { global.removeEventListener( 'unhandledrejection', browserRejectionHandler ); } }; } }; this.pushListener = function pushListener(listener) { handlers.push(listener); }; this.popListener = function popListener(listener) { if (!listener) { throw new Error('popListener expects a listener'); } handlers.pop(); }; } return GlobalErrors; }; getJasmineRequireObj().toBePending = function(j$) { /** * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected. * @function * @async * @name async-matchers#toBePending * @since 3.6 * @example * await expectAsync(aPromise).toBePending(); */ return function toBePending() { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBePending to be called on a promise.'); } var want = {}; return Promise.race([actual, Promise.resolve(want)]).then( function(got) { return { pass: want === got }; }, function() { return { pass: false }; } ); } }; }; }; getJasmineRequireObj().toBeRejected = function(j$) { /** * Expect a promise to be rejected. * @function * @async * @name async-matchers#toBeRejected * @since 3.1.0 * @example * await expectAsync(aPromise).toBeRejected(); * @example * return expectAsync(aPromise).toBeRejected(); */ return function toBeRejected() { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBeRejected to be called on a promise.'); } return actual.then( function() { return { pass: false }; }, function() { return { pass: true }; } ); } }; }; }; getJasmineRequireObj().toBeRejectedWith = function(j$) { /** * Expect a promise to be rejected with a value equal to the expected, using deep equality comparison. * @function * @async * @name async-matchers#toBeRejectedWith * @since 3.3.0 * @param {Object} expected - Value that the promise is expected to be rejected with * @example * await expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); * @example * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); */ return function toBeRejectedWith(matchersUtil) { return { compare: function(actualPromise, expectedValue) { if (!j$.isPromiseLike(actualPromise)) { throw new Error( 'Expected toBeRejectedWith to be called on a promise.' ); } function prefix(passed) { return ( 'Expected a promise ' + (passed ? 'not ' : '') + 'to be rejected with ' + matchersUtil.pp(expectedValue) ); } return actualPromise.then( function() { return { pass: false, message: prefix(false) + ' but it was resolved.' }; }, function(actualValue) { if (matchersUtil.equals(actualValue, expectedValue)) { return { pass: true, message: prefix(true) + '.' }; } else { return { pass: false, message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' }; } } ); } }; }; }; getJasmineRequireObj().toBeRejectedWithError = function(j$) { /** * Expect a promise to be rejected with a value matched to the expected * @function * @async * @name async-matchers#toBeRejectedWithError * @since 3.5.0 * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` * @example * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message'); * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/); * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError); * await expectAsync(aPromise).toBeRejectedWithError('Error message'); * return expectAsync(aPromise).toBeRejectedWithError(/Error message/); */ return function toBeRejectedWithError(matchersUtil) { return { compare: function(actualPromise, arg1, arg2) { if (!j$.isPromiseLike(actualPromise)) { throw new Error( 'Expected toBeRejectedWithError to be called on a promise.' ); } var expected = getExpectedFromArgs(arg1, arg2, matchersUtil); return actualPromise.then( function() { return { pass: false, message: 'Expected a promise to be rejected but it was resolved.' }; }, function(actualValue) { return matchError(actualValue, expected, matchersUtil); } ); } }; }; function matchError(actual, expected, matchersUtil) { if (!j$.isError_(actual)) { return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); } if (!(actual instanceof expected.error)) { return fail( expected, 'rejected with type ' + j$.fnNameFor(actual.constructor) ); } var actualMessage = actual.message; if ( actualMessage === expected.message || typeof expected.message === 'undefined' ) { return pass(expected); } if ( expected.message instanceof RegExp && expected.message.test(actualMessage) ) { return pass(expected); } return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); } function pass(expected) { return { pass: true, message: 'Expected a promise not to be rejected with ' + expected.printValue + ', but it was.' }; } function fail(expected, message) { return { pass: false, message: 'Expected a promise to be rejected with ' + expected.printValue + ' but it was ' + message + '.' }; } function getExpectedFromArgs(arg1, arg2, matchersUtil) { var error, message; if (isErrorConstructor(arg1)) { error = arg1; message = arg2; } else { error = Error; message = arg1; } return { error: error, message: message, printValue: j$.fnNameFor(error) + (typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message)) }; } function isErrorConstructor(value) { return ( typeof value === 'function' && (value === Error || j$.isError_(value.prototype)) ); } }; getJasmineRequireObj().toBeResolved = function(j$) { /** * Expect a promise to be resolved. * @function * @async * @name async-matchers#toBeResolved * @since 3.1.0 * @example * await expectAsync(aPromise).toBeResolved(); * @example * return expectAsync(aPromise).toBeResolved(); */ return function toBeResolved(matchersUtil) { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBeResolved to be called on a promise.'); } return actual.then( function() { return { pass: true }; }, function(e) { return { pass: false, message: 'Expected a promise to be resolved but it was ' + 'rejected with ' + matchersUtil.pp(e) + '.' }; } ); } }; }; }; getJasmineRequireObj().toBeResolvedTo = function(j$) { /** * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison. * @function * @async * @name async-matchers#toBeResolvedTo * @since 3.1.0 * @param {Object} expected - Value that the promise is expected to resolve to * @example * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); * @example * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); */ return function toBeResolvedTo(matchersUtil) { return { compare: function(actualPromise, expectedValue) { if (!j$.isPromiseLike(actualPromise)) { throw new Error('Expected toBeResolvedTo to be called on a promise.'); } function prefix(passed) { return ( 'Expected a promise ' + (passed ? 'not ' : '') + 'to be resolved to ' + matchersUtil.pp(expectedValue) ); } return actualPromise.then( function(actualValue) { if (matchersUtil.equals(actualValue, expectedValue)) { return { pass: true, message: prefix(true) + '.' }; } else { return { pass: false, message: prefix(false) + ' but it was resolved to ' + matchersUtil.pp(actualValue) + '.' }; } }, function(e) { return { pass: false, message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(e) + '.' }; } ); } }; }; }; getJasmineRequireObj().DiffBuilder = function(j$) { return function DiffBuilder(config) { var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(), mismatches = new j$.MismatchTree(), path = new j$.ObjectPath(), actualRoot = undefined, expectedRoot = undefined; return { setRoots: function(actual, expected) { actualRoot = actual; expectedRoot = expected; }, recordMismatch: function(formatter) { mismatches.add(path, formatter); }, getMessage: function() { var messages = []; mismatches.traverse(function(path, isLeaf, formatter) { var actualCustom, expectedCustom, useCustom, derefResult = dereferencePath( path, actualRoot, expectedRoot, prettyPrinter ), actual = derefResult.actual, expected = derefResult.expected; if (formatter) { messages.push(formatter(actual, expected, path, prettyPrinter)); return true; } actualCustom = prettyPrinter.customFormat_(actual); expectedCustom = prettyPrinter.customFormat_(expected); useCustom = !( j$.util.isUndefined(actualCustom) && j$.util.isUndefined(expectedCustom) ); if (useCustom) { messages.push( wrapPrettyPrinted(actualCustom, expectedCustom, path) ); return false; // don't recurse further } if (isLeaf) { messages.push( defaultFormatter(actual, expected, path, prettyPrinter) ); } return true; }); return messages.join('\n'); }, withPath: function(pathComponent, block) { var oldPath = path; path = path.add(pathComponent); block(); path = oldPath; } }; function defaultFormatter(actual, expected, path, prettyPrinter) { return wrapPrettyPrinted( prettyPrinter(actual), prettyPrinter(expected), path ); } function wrapPrettyPrinted(actual, expected, path) { return ( 'Expected ' + path + (path.depth() ? ' = ' : '') + actual + ' to equal ' + expected + '.' ); } }; function dereferencePath(objectPath, actual, expected, pp) { function handleAsymmetricExpected() { if ( j$.isAsymmetricEqualityTester_(expected) && j$.isFunction_(expected.valuesForDiff_) ) { var asymmetricResult = expected.valuesForDiff_(actual, pp); expected = asymmetricResult.self; actual = asymmetricResult.other; } } var i; handleAsymmetricExpected(); for (i = 0; i < objectPath.components.length; i++) { actual = actual[objectPath.components[i]]; expected = expected[objectPath.components[i]]; handleAsymmetricExpected(); } return { actual: actual, expected: expected }; } }; getJasmineRequireObj().MatchersUtil = function(j$) { /** * @class MatchersUtil * @classdesc Utilities for use in implementing matchers.
* _Note:_ Do not construct this directly. Jasmine will construct one and * pass it to matchers and asymmetric equality testers. * @hideconstructor */ function MatchersUtil(options) { options = options || {}; this.customTesters_ = options.customTesters || []; /** * Formats a value for use in matcher failure messages and similar contexts, * taking into account the current set of custom value formatters. * @function * @name MatchersUtil#pp * @since 3.6.0 * @param {*} value The value to pretty-print * @return {string} The pretty-printed value */ this.pp = options.pp || function() {}; } /** * Determines whether `haystack` contains `needle`, using the same comparison * logic as {@link MatchersUtil#equals}. * @function * @name MatchersUtil#contains * @since 2.0.0 * @param {*} haystack The collection to search * @param {*} needle The value to search for * @returns {boolean} True if `needle` was found in `haystack` */ MatchersUtil.prototype.contains = function(haystack, needle) { if (!haystack) { return false; } if (j$.isSet(haystack)) { // Try .has() first. It should be faster in cases where // needle === something in haystack. Fall back to .equals() comparison // if that fails. if (haystack.has(needle)) { return true; } } if (j$.isIterable_(haystack) && !j$.isString_(haystack)) { // Arrays, Sets, etc. for (const candidate of haystack) { if (this.equals(candidate, needle)) { return true; } } return false; } if (haystack.indexOf) { // Mainly strings return haystack.indexOf(needle) >= 0; } if (j$.isNumber_(haystack.length)) { // Objects that are shaped like arrays but aren't iterable for (var i = 0; i < haystack.length; i++) { if (this.equals(haystack[i], needle)) { return true; } } } return false; }; MatchersUtil.prototype.buildFailureMessage = function() { var self = this; var args = Array.prototype.slice.call(arguments, 0), matcherName = args[0], isNot = args[1], actual = args[2], expected = args.slice(3), englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); var message = 'Expected ' + self.pp(actual) + (isNot ? ' not ' : ' ') + englishyPredicate; if (expected.length > 0) { for (var i = 0; i < expected.length; i++) { if (i > 0) { message += ','; } message += ' ' + self.pp(expected[i]); } } return message + '.'; }; MatchersUtil.prototype.asymmetricDiff_ = function( a, b, aStack, bStack, diffBuilder ) { if (j$.isFunction_(b.valuesForDiff_)) { var values = b.valuesForDiff_(a, this.pp); this.eq_(values.other, values.self, aStack, bStack, diffBuilder); } else { diffBuilder.recordMismatch(); } }; MatchersUtil.prototype.asymmetricMatch_ = function( a, b, aStack, bStack, diffBuilder ) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), asymmetricB = j$.isAsymmetricEqualityTester_(b), result; if (asymmetricA === asymmetricB) { return undefined; } if (asymmetricA) { result = a.asymmetricMatch(b, this); if (!result) { diffBuilder.recordMismatch(); } return result; } if (asymmetricB) { result = b.asymmetricMatch(a, this); if (!result) { this.asymmetricDiff_(a, b, aStack, bStack, diffBuilder); } return result; } }; /** * Determines whether two values are deeply equal to each other. * @function * @name MatchersUtil#equals * @since 2.0.0 * @param {*} a The first value to compare * @param {*} b The second value to compare * @returns {boolean} True if the values are equal */ MatchersUtil.prototype.equals = function(a, b, diffBuilder) { diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder.setRoots(a, b); return this.eq_(a, b, [], [], diffBuilder); }; // Equality function lovingly adapted from isEqual in // [Underscore](http://underscorejs.org) MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, diffBuilder) { var result = true, self = this, i; var asymmetricResult = this.asymmetricMatch_( a, b, aStack, bStack, diffBuilder ); if (!j$.util.isUndefined(asymmetricResult)) { return asymmetricResult; } for (i = 0; i < this.customTesters_.length; i++) { var customTesterResult = this.customTesters_[i](a, b); if (!j$.util.isUndefined(customTesterResult)) { if (!customTesterResult) { diffBuilder.recordMismatch(); } return customTesterResult; } } if (a instanceof Error && b instanceof Error) { result = a.message == b.message; if (!result) { diffBuilder.recordMismatch(); } return result; } // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) { result = a !== 0 || 1 / a == 1 / b; if (!result) { diffBuilder.recordMismatch(); } return result; } // A strict comparison is necessary because `null == undefined`. if (a === null || b === null) { result = a === b; if (!result) { diffBuilder.recordMismatch(); } return result; } var className = Object.prototype.toString.call(a); if (className != Object.prototype.toString.call(b)) { diffBuilder.recordMismatch(); return false; } switch (className) { // Strings, numbers, dates, and booleans are compared by value. case '[object String]': // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. result = a == String(b); if (!result) { diffBuilder.recordMismatch(); } return result; case '[object Number]': // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for // other numeric values. result = a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b; if (!result) { diffBuilder.recordMismatch(); } return result; case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. result = +a == +b; if (!result) { diffBuilder.recordMismatch(); } return result; case '[object ArrayBuffer]': // If we have an instance of ArrayBuffer the Uint8Array ctor // will be defined as well return self.eq_( new Uint8Array(a), new Uint8Array(b), aStack, bStack, diffBuilder ); // RegExps are compared by their source patterns and flags. case '[object RegExp]': return ( a.source == b.source && a.global == b.global && a.multiline == b.multiline && a.ignoreCase == b.ignoreCase ); } if (typeof a != 'object' || typeof b != 'object') { diffBuilder.recordMismatch(); return false; } var aIsDomNode = j$.isDomNode(a); var bIsDomNode = j$.isDomNode(b); if (aIsDomNode && bIsDomNode) { // At first try to use DOM3 method isEqualNode result = a.isEqualNode(b); if (!result) { diffBuilder.recordMismatch(); } return result; } if (aIsDomNode || bIsDomNode) { diffBuilder.recordMismatch(); return false; } var aIsPromise = j$.isPromise(a); var bIsPromise = j$.isPromise(b); if (aIsPromise && bIsPromise) { return a === b; } // Assume equality for cyclic structures. The algorithm for detecting cyclic // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. var length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of // unique nested structures. if (aStack[length] == a) { return bStack[length] == b; } } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); var size = 0; // Recursively compare objects and arrays. // Compare array lengths to determine if a deep comparison is necessary. if (className == '[object Array]') { var aLength = a.length; var bLength = b.length; diffBuilder.withPath('length', function() { if (aLength !== bLength) { diffBuilder.recordMismatch(); result = false; } }); for (i = 0; i < aLength || i < bLength; i++) { diffBuilder.withPath(i, function() { if (i >= bLength) { diffBuilder.recordMismatch( actualArrayIsLongerFormatter.bind(null, self.pp) ); result = false; } else { result = self.eq_( i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, diffBuilder ) && result; } }); } if (!result) { return false; } } else if (j$.isMap(a) && j$.isMap(b)) { if (a.size != b.size) { diffBuilder.recordMismatch(); return false; } var keysA = []; var keysB = []; a.forEach(function(valueA, keyA) { keysA.push(keyA); }); b.forEach(function(valueB, keyB) { keysB.push(keyB); }); // For both sets of keys, check they map to equal values in both maps. // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys. var mapKeys = [keysA, keysB]; var cmpKeys = [keysB, keysA]; var mapIter, mapKey, mapValueA, mapValueB; var cmpIter, cmpKey; for (i = 0; result && i < mapKeys.length; i++) { mapIter = mapKeys[i]; cmpIter = cmpKeys[i]; for (var j = 0; result && j < mapIter.length; j++) { mapKey = mapIter[j]; cmpKey = cmpIter[j]; mapValueA = a.get(mapKey); // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches, // otherwise explicitly look up the mapKey in the other Map since we want keys with unique // obj identity (that are otherwise equal) to not match. if ( j$.isAsymmetricEqualityTester_(mapKey) || (j$.isAsymmetricEqualityTester_(cmpKey) && this.eq_(mapKey, cmpKey, aStack, bStack, j$.NullDiffBuilder())) ) { mapValueB = b.get(cmpKey); } else { mapValueB = b.get(mapKey); } result = this.eq_( mapValueA, mapValueB, aStack, bStack, j$.NullDiffBuilder() ); } } if (!result) { diffBuilder.recordMismatch(); return false; } } else if (j$.isSet(a) && j$.isSet(b)) { if (a.size != b.size) { diffBuilder.recordMismatch(); return false; } var valuesA = []; a.forEach(function(valueA) { valuesA.push(valueA); }); var valuesB = []; b.forEach(function(valueB) { valuesB.push(valueB); }); // For both sets, check they are all contained in the other set var setPairs = [[valuesA, valuesB], [valuesB, valuesA]]; var stackPairs = [[aStack, bStack], [bStack, aStack]]; var baseValues, baseValue, baseStack; var otherValues, otherValue, otherStack; var found; var prevStackSize; for (i = 0; result && i < setPairs.length; i++) { baseValues = setPairs[i][0]; otherValues = setPairs[i][1]; baseStack = stackPairs[i][0]; otherStack = stackPairs[i][1]; // For each value in the base set... for (var k = 0; result && k < baseValues.length; k++) { baseValue = baseValues[k]; found = false; // ... test that it is present in the other set for (var l = 0; !found && l < otherValues.length; l++) { otherValue = otherValues[l]; prevStackSize = baseStack.length; // compare by value equality found = this.eq_( baseValue, otherValue, baseStack, otherStack, j$.NullDiffBuilder() ); if (!found && prevStackSize !== baseStack.length) { baseStack.splice(prevStackSize); otherStack.splice(prevStackSize); } } result = result && found; } } if (!result) { diffBuilder.recordMismatch(); return false; } } else if (j$.isURL(a) && j$.isURL(b)) { // URLs have no enumrable properties, so the default object comparison // would consider any two URLs to be equal. return a.toString() === b.toString(); } else { // Objects with different constructors are not equivalent, but `Object`s // or `Array`s from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if ( aCtor !== bCtor && isFunction(aCtor) && isFunction(bCtor) && a instanceof aCtor && b instanceof bCtor && !(aCtor instanceof aCtor && bCtor instanceof bCtor) ) { diffBuilder.recordMismatch( constructorsAreDifferentFormatter.bind(null, this.pp) ); return false; } } // Deep compare objects. var aKeys = keys(a, className == '[object Array]'), key; size = aKeys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. if (keys(b, className == '[object Array]').length !== size) { diffBuilder.recordMismatch( objectKeysAreDifferentFormatter.bind(null, this.pp) ); return false; } for (i = 0; i < size; i++) { key = aKeys[i]; // Deep compare each member if (!j$.util.has(b, key)) { diffBuilder.recordMismatch( objectKeysAreDifferentFormatter.bind(null, this.pp) ); result = false; continue; } diffBuilder.withPath(key, function() { if (!self.eq_(a[key], b[key], aStack, bStack, diffBuilder)) { result = false; } }); } if (!result) { return false; } // Remove the first object from the stack of traversed objects. aStack.pop(); bStack.pop(); return result; }; function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { if (j$.util.has(o, key)) { keys.push(key); } } return keys; })(obj); if (!isArray) { return allKeys; } if (allKeys.length === 0) { return allKeys; } var extraKeys = []; for (var i = 0; i < allKeys.length; i++) { if (!/^[0-9]+$/.test(allKeys[i])) { extraKeys.push(allKeys[i]); } } return extraKeys; } function isFunction(obj) { return typeof obj === 'function'; } function objectKeysAreDifferentFormatter(pp, actual, expected, path) { var missingProperties = j$.util.objectDifference(expected, actual), extraProperties = j$.util.objectDifference(actual, expected), missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), messages = []; if (!path.depth()) { path = 'object'; } if (missingPropertiesMessage.length) { messages.push( 'Expected ' + path + ' to have properties' + missingPropertiesMessage ); } if (extraPropertiesMessage.length) { messages.push( 'Expected ' + path + ' not to have properties' + extraPropertiesMessage ); } return messages.join('\n'); } function constructorsAreDifferentFormatter(pp, actual, expected, path) { if (!path.depth()) { path = 'object'; } return ( 'Expected ' + path + ' to be a kind of ' + j$.fnNameFor(expected.constructor) + ', but was ' + pp(actual) + '.' ); } function actualArrayIsLongerFormatter(pp, actual, expected, path) { return ( 'Unexpected ' + path + (path.depth() ? ' = ' : '') + pp(actual) + ' in array.' ); } function formatKeyValuePairs(pp, obj) { var formatted = ''; for (var key in obj) { formatted += '\n ' + key + ': ' + pp(obj[key]); } return formatted; } return MatchersUtil; }; /** * @interface AsymmetricEqualityTester * @classdesc An asymmetric equality tester is an object that can match multiple * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine * includes a number of built-in asymmetric equality testers, such as * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are * also supported. * * Asymmetric equality testers work with any matcher, including user-defined * custom matchers, that uses {@link MatchersUtil#equals} or * {@link MatchersUtil#contains}. * * @example * function numberDivisibleBy(divisor) { * return { * asymmetricMatch: function(n) { * return typeof n === 'number' && n % divisor === 0; * }, * jasmineToString: function() { * return ``; * } * }; * } * * var actual = { * n: 2, * otherFields: "don't care" * }; * * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)})); * @see custom_asymmetric_equality_testers * @since 2.0.0 */ /** * Determines whether a value matches this tester * @function * @name AsymmetricEqualityTester#asymmetricMatch * @param value {any} The value to test * @param matchersUtil {MatchersUtil} utilities for testing equality, etc * @return {Boolean} */ /** * Returns a string representation of this tester to use in matcher failure messages * @function * @name AsymmetricEqualityTester#jasmineToString * @param pp {function} Function that takes a value and returns a pretty-printed representation * @return {String} */ getJasmineRequireObj().MismatchTree = function(j$) { /* To be able to apply custom object formatters at all possible levels of an object graph, DiffBuilder needs to be able to know not just where the mismatch occurred but also all ancestors of the mismatched value in both the expected and actual object graphs. MismatchTree maintains that context and provides it via the traverse method. */ function MismatchTree(path) { this.path = path || new j$.ObjectPath([]); this.formatter = undefined; this.children = []; this.isMismatch = false; } MismatchTree.prototype.add = function(path, formatter) { var key, child; if (path.depth() === 0) { this.formatter = formatter; this.isMismatch = true; } else { key = path.components[0]; path = path.shift(); child = this.child(key); if (!child) { child = new MismatchTree(this.path.add(key)); this.children.push(child); } child.add(path, formatter); } }; MismatchTree.prototype.traverse = function(visit) { var i, hasChildren = this.children.length > 0; if (this.isMismatch || hasChildren) { if (visit(this.path, !hasChildren, this.formatter)) { for (i = 0; i < this.children.length; i++) { this.children[i].traverse(visit); } } } }; MismatchTree.prototype.child = function(key) { var i, pathEls; for (i = 0; i < this.children.length; i++) { pathEls = this.children[i].path.components; if (pathEls[pathEls.length - 1] === key) { return this.children[i]; } } }; return MismatchTree; }; getJasmineRequireObj().nothing = function() { /** * {@link expect} nothing explicitly. * @function * @name matchers#nothing * @since 2.8.0 * @example * expect().nothing(); */ function nothing() { return { compare: function() { return { pass: true }; } }; } return nothing; }; getJasmineRequireObj().NullDiffBuilder = function(j$) { return function() { return { withPath: function(_, block) { block(); }, setRoots: function() {}, recordMismatch: function() {} }; }; }; getJasmineRequireObj().ObjectPath = function(j$) { function ObjectPath(components) { this.components = components || []; } ObjectPath.prototype.toString = function() { if (this.components.length) { return '$' + map(this.components, formatPropertyAccess).join(''); } else { return ''; } }; ObjectPath.prototype.add = function(component) { return new ObjectPath(this.components.concat([component])); }; ObjectPath.prototype.shift = function() { return new ObjectPath(this.components.slice(1)); }; ObjectPath.prototype.depth = function() { return this.components.length; }; function formatPropertyAccess(prop) { if (typeof prop === 'number') { return '[' + prop + ']'; } if (isValidIdentifier(prop)) { return '.' + prop; } return "['" + prop + "']"; } function map(array, fn) { var results = []; for (var i = 0; i < array.length; i++) { results.push(fn(array[i])); } return results; } function isValidIdentifier(string) { return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string); } return ObjectPath; }; getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) { var availableMatchers = [ 'toBePending', 'toBeResolved', 'toBeRejected', 'toBeResolvedTo', 'toBeRejectedWith', 'toBeRejectedWithError' ], matchers = {}; for (var i = 0; i < availableMatchers.length; i++) { var name = availableMatchers[i]; matchers[name] = jRequire[name](j$); } return matchers; }; getJasmineRequireObj().toBe = function(j$) { /** * {@link expect} the actual value to be `===` to the expected value. * @function * @name matchers#toBe * @since 1.3.0 * @param {Object} expected - The expected value to compare against. * @example * expect(thing).toBe(realThing); */ function toBe(matchersUtil) { var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().'; return { compare: function(actual, expected) { var result = { pass: actual === expected }; if (typeof expected === 'object') { result.message = matchersUtil.buildFailureMessage( 'toBe', result.pass, actual, expected ) + tip; } return result; } }; } return toBe; }; getJasmineRequireObj().toBeCloseTo = function() { /** * {@link expect} the actual value to be within a specified precision of the expected value. * @function * @name matchers#toBeCloseTo * @since 1.3.0 * @param {Object} expected - The expected value to compare against. * @param {Number} [precision=2] - The number of decimal points to check. * @example * expect(number).toBeCloseTo(42.2, 3); */ function toBeCloseTo() { return { compare: function(actual, expected, precision) { if (precision !== 0) { precision = precision || 2; } if (expected === null || actual === null) { throw new Error( 'Cannot use toBeCloseTo with null. Arguments evaluated to: ' + 'expect(' + actual + ').toBeCloseTo(' + expected + ').' ); } var pow = Math.pow(10, precision + 1); var delta = Math.abs(expected - actual); var maxDelta = Math.pow(10, -precision) / 2; return { pass: Math.round(delta * pow) <= maxDelta * pow }; } }; } return toBeCloseTo; }; getJasmineRequireObj().toBeDefined = function() { /** * {@link expect} the actual value to be defined. (Not `undefined`) * @function * @name matchers#toBeDefined * @since 1.3.0 * @example * expect(result).toBeDefined(); */ function toBeDefined() { return { compare: function(actual) { return { pass: void 0 !== actual }; } }; } return toBeDefined; }; getJasmineRequireObj().toBeFalse = function() { /** * {@link expect} the actual value to be `false`. * @function * @name matchers#toBeFalse * @since 3.5.0 * @example * expect(result).toBeFalse(); */ function toBeFalse() { return { compare: function(actual) { return { pass: actual === false }; } }; } return toBeFalse; }; getJasmineRequireObj().toBeFalsy = function() { /** * {@link expect} the actual value to be falsy * @function * @name matchers#toBeFalsy * @since 2.0.0 * @example * expect(result).toBeFalsy(); */ function toBeFalsy() { return { compare: function(actual) { return { pass: !actual }; } }; } return toBeFalsy; }; getJasmineRequireObj().toBeGreaterThan = function() { /** * {@link expect} the actual value to be greater than the expected value. * @function * @name matchers#toBeGreaterThan * @since 2.0.0 * @param {Number} expected - The value to compare against. * @example * expect(result).toBeGreaterThan(3); */ function toBeGreaterThan() { return { compare: function(actual, expected) { return { pass: actual > expected }; } }; } return toBeGreaterThan; }; getJasmineRequireObj().toBeGreaterThanOrEqual = function() { /** * {@link expect} the actual value to be greater than or equal to the expected value. * @function * @name matchers#toBeGreaterThanOrEqual * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeGreaterThanOrEqual(25); */ function toBeGreaterThanOrEqual() { return { compare: function(actual, expected) { return { pass: actual >= expected }; } }; } return toBeGreaterThanOrEqual; }; getJasmineRequireObj().toBeInstanceOf = function(j$) { var usageError = j$.formatErrorMsg( '', 'expect(value).toBeInstanceOf()' ); /** * {@link expect} the actual to be an instance of the expected class * @function * @name matchers#toBeInstanceOf * @since 3.5.0 * @param {Object} expected - The class or constructor function to check for * @example * expect('foo').toBeInstanceOf(String); * expect(3).toBeInstanceOf(Number); * expect(new Error()).toBeInstanceOf(Error); */ function toBeInstanceOf(matchersUtil) { return { compare: function(actual, expected) { var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : matchersUtil.pp(actual), expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), expectedMatcher, pass; try { expectedMatcher = new j$.Any(expected); pass = expectedMatcher.asymmetricMatch(actual); } catch (error) { throw new Error( usageError('Expected value is not a constructor function') ); } if (pass) { return { pass: true, message: 'Expected instance of ' + actualType + ' not to be an instance of ' + expectedType }; } else { return { pass: false, message: 'Expected instance of ' + actualType + ' to be an instance of ' + expectedType }; } } }; } return toBeInstanceOf; }; getJasmineRequireObj().toBeLessThan = function() { /** * {@link expect} the actual value to be less than the expected value. * @function * @name matchers#toBeLessThan * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeLessThan(0); */ function toBeLessThan() { return { compare: function(actual, expected) { return { pass: actual < expected }; } }; } return toBeLessThan; }; getJasmineRequireObj().toBeLessThanOrEqual = function() { /** * {@link expect} the actual value to be less than or equal to the expected value. * @function * @name matchers#toBeLessThanOrEqual * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeLessThanOrEqual(123); */ function toBeLessThanOrEqual() { return { compare: function(actual, expected) { return { pass: actual <= expected }; } }; } return toBeLessThanOrEqual; }; getJasmineRequireObj().toBeNaN = function(j$) { /** * {@link expect} the actual value to be `NaN` (Not a Number). * @function * @name matchers#toBeNaN * @since 1.3.0 * @example * expect(thing).toBeNaN(); */ function toBeNaN(matchersUtil) { return { compare: function(actual) { var result = { pass: actual !== actual }; if (result.pass) { result.message = 'Expected actual not to be NaN.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.'; }; } return result; } }; } return toBeNaN; }; getJasmineRequireObj().toBeNegativeInfinity = function(j$) { /** * {@link expect} the actual value to be `-Infinity` (-infinity). * @function * @name matchers#toBeNegativeInfinity * @since 2.6.0 * @example * expect(thing).toBeNegativeInfinity(); */ function toBeNegativeInfinity(matchersUtil) { return { compare: function(actual) { var result = { pass: actual === Number.NEGATIVE_INFINITY }; if (result.pass) { result.message = 'Expected actual not to be -Infinity.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.'; }; } return result; } }; } return toBeNegativeInfinity; }; getJasmineRequireObj().toBeNull = function() { /** * {@link expect} the actual value to be `null`. * @function * @name matchers#toBeNull * @since 1.3.0 * @example * expect(result).toBeNull(); */ function toBeNull() { return { compare: function(actual) { return { pass: actual === null }; } }; } return toBeNull; }; getJasmineRequireObj().toBePositiveInfinity = function(j$) { /** * {@link expect} the actual value to be `Infinity` (infinity). * @function * @name matchers#toBePositiveInfinity * @since 2.6.0 * @example * expect(thing).toBePositiveInfinity(); */ function toBePositiveInfinity(matchersUtil) { return { compare: function(actual) { var result = { pass: actual === Number.POSITIVE_INFINITY }; if (result.pass) { result.message = 'Expected actual not to be Infinity.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.'; }; } return result; } }; } return toBePositiveInfinity; }; getJasmineRequireObj().toBeTrue = function() { /** * {@link expect} the actual value to be `true`. * @function * @name matchers#toBeTrue * @since 3.5.0 * @example * expect(result).toBeTrue(); */ function toBeTrue() { return { compare: function(actual) { return { pass: actual === true }; } }; } return toBeTrue; }; getJasmineRequireObj().toBeTruthy = function() { /** * {@link expect} the actual value to be truthy. * @function * @name matchers#toBeTruthy * @since 2.0.0 * @example * expect(thing).toBeTruthy(); */ function toBeTruthy() { return { compare: function(actual) { return { pass: !!actual }; } }; } return toBeTruthy; }; getJasmineRequireObj().toBeUndefined = function() { /** * {@link expect} the actual value to be `undefined`. * @function * @name matchers#toBeUndefined * @since 1.3.0 * @example * expect(result).toBeUndefined(): */ function toBeUndefined() { return { compare: function(actual) { return { pass: void 0 === actual }; } }; } return toBeUndefined; }; getJasmineRequireObj().toContain = function() { /** * {@link expect} the actual value to contain a specific value. * @function * @name matchers#toContain * @since 2.0.0 * @param {Object} expected - The value to look for. * @example * expect(array).toContain(anElement); * expect(string).toContain(substring); */ function toContain(matchersUtil) { return { compare: function(actual, expected) { return { pass: matchersUtil.contains(actual, expected) }; } }; } return toContain; }; getJasmineRequireObj().toEqual = function(j$) { /** * {@link expect} the actual value to be equal to the expected, using deep equality comparison. * @function * @name matchers#toEqual * @since 1.3.0 * @param {Object} expected - Expected value * @example * expect(bigObject).toEqual({"foo": ['bar', 'baz']}); */ function toEqual(matchersUtil) { return { compare: function(actual, expected) { var result = { pass: false }, diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp }); result.pass = matchersUtil.equals(actual, expected, diffBuilder); // TODO: only set error message if test fails result.message = diffBuilder.getMessage(); return result; } }; } return toEqual; }; getJasmineRequireObj().toHaveBeenCalled = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalled()' ); /** * {@link expect} the actual (a {@link Spy}) to have been called. * @function * @name matchers#toHaveBeenCalled * @since 1.3.0 * @example * expect(mySpy).toHaveBeenCalled(); * expect(mySpy).not.toHaveBeenCalled(); */ function toHaveBeenCalled(matchersUtil) { return { compare: function(actual) { var result = {}; if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } if (arguments.length > 1) { throw new Error( getErrorMsg('Does not take arguments, use toHaveBeenCalledWith') ); } result.pass = actual.calls.any(); result.message = result.pass ? 'Expected spy ' + actual.and.identity + ' not to have been called.' : 'Expected spy ' + actual.and.identity + ' to have been called.'; return result; } }; } return toHaveBeenCalled; }; getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledBefore()' ); /** * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}. * @function * @name matchers#toHaveBeenCalledBefore * @since 2.6.0 * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}. * @example * expect(mySpy).toHaveBeenCalledBefore(otherSpy); */ function toHaveBeenCalledBefore(matchersUtil) { return { compare: function(firstSpy, latterSpy) { if (!j$.isSpy(firstSpy)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.' ) ); } if (!j$.isSpy(latterSpy)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.' ) ); } var result = { pass: false }; if (!firstSpy.calls.count()) { result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.'; return result; } if (!latterSpy.calls.count()) { result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.'; return result; } var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder; var first2ndSpyCall = latterSpy.calls.first().invocationOrder; result.pass = latest1stSpyCall < first2ndSpyCall; if (result.pass) { result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was'; } else { var first1stSpyCall = firstSpy.calls.first().invocationOrder; var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder; if (first1stSpyCall < first2ndSpyCall) { result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)'; } else if (latest2ndSpyCall > latest1stSpyCall) { result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)'; } else { result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity; } } return result; } }; } return toHaveBeenCalledBefore; }; getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledOnceWith(...arguments)' ); /** * {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments. * @function * @name matchers#toHaveBeenCalledOnceWith * @since 3.6.0 * @param {...Object} - The arguments to look for * @example * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2); */ function toHaveBeenCalledOnceWith(util) { return { compare: function() { var args = Array.prototype.slice.call(arguments, 0), actual = args[0], expectedArgs = args.slice(1); if (!j$.isSpy(actual)) { throw new Error( getErrorMsg('Expected a spy, but got ' + util.pp(actual) + '.') ); } var prettyPrintedCalls = actual.calls .allArgs() .map(function(argsForCall) { return ' ' + util.pp(argsForCall); }); if ( actual.calls.count() === 1 && util.contains(actual.calls.allArgs(), expectedArgs) ) { return { pass: true, message: 'Expected spy ' + actual.and.identity + ' to have been called 0 times, multiple times, or once, but with arguments different from:\n' + ' ' + util.pp(expectedArgs) + '\n' + 'But the actual call was:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' }; } function getDiffs() { return actual.calls.allArgs().map(function(argsForCall, callIx) { var diffBuilder = new j$.DiffBuilder(); util.equals(argsForCall, expectedArgs, diffBuilder); return diffBuilder.getMessage(); }); } function butString() { switch (actual.calls.count()) { case 0: return 'But it was never called.\n\n'; case 1: return ( 'But the actual call was:\n' + prettyPrintedCalls.join(',\n') + '.\n' + getDiffs().join('\n') + '\n\n' ); default: return ( 'But the actual calls were:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' ); } } return { pass: false, message: 'Expected spy ' + actual.and.identity + ' to have been called only once, and with given args:\n' + ' ' + util.pp(expectedArgs) + '\n' + butString() }; } }; } return toHaveBeenCalledOnceWith; }; getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledTimes()' ); /** * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times. * @function * @name matchers#toHaveBeenCalledTimes * @since 2.4.0 * @param {Number} expected - The number of invocations to look for. * @example * expect(mySpy).toHaveBeenCalledTimes(3); */ function toHaveBeenCalledTimes(matchersUtil) { return { compare: function(actual, expected) { if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } var args = Array.prototype.slice.call(arguments, 0), result = { pass: false }; if (!j$.isNumber_(expected)) { throw new Error( getErrorMsg( 'The expected times failed is a required argument and must be a number.' ) ); } actual = args[0]; var calls = actual.calls.count(); var timesMessage = expected === 1 ? 'once' : expected + ' times'; result.pass = calls === expected; result.message = result.pass ? 'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' : 'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.'; return result; } }; } return toHaveBeenCalledTimes; }; getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledWith(...arguments)' ); /** * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once. * @function * @name matchers#toHaveBeenCalledWith * @since 1.3.0 * @param {...Object} - The arguments to look for * @example * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2); */ function toHaveBeenCalledWith(matchersUtil) { return { compare: function() { var args = Array.prototype.slice.call(arguments, 0), actual = args[0], expectedArgs = args.slice(1), result = { pass: false }; if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } if (!actual.calls.any()) { result.message = function() { return ( 'Expected spy ' + actual.and.identity + ' to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\nbut it was never called.' ); }; return result; } if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) { result.pass = true; result.message = function() { return ( 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\nbut it was.' ); }; } else { result.message = function() { var prettyPrintedCalls = actual.calls .allArgs() .map(function(argsForCall) { return ' ' + matchersUtil.pp(argsForCall); }); var diffs = actual.calls .allArgs() .map(function(argsForCall, callIx) { var diffBuilder = new j$.DiffBuilder(); matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); return ( 'Call ' + callIx + ':\n' + diffBuilder.getMessage().replace(/^/gm, ' ') ); }); return ( 'Expected spy ' + actual.and.identity + ' to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\n' + '' + 'but actual calls were:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' + diffs.join('\n') ); }; } return result; } }; } return toHaveBeenCalledWith; }; getJasmineRequireObj().toHaveClass = function(j$) { /** * {@link expect} the actual value to be a DOM element that has the expected class * @function * @name matchers#toHaveClass * @since 3.0.0 * @param {Object} expected - The class name to test for * @example * var el = document.createElement('div'); * el.className = 'foo bar baz'; * expect(el).toHaveClass('bar'); */ function toHaveClass(matchersUtil) { return { compare: function(actual, expected) { if (!isElement(actual)) { throw new Error(matchersUtil.pp(actual) + ' is not a DOM element'); } return { pass: actual.classList.contains(expected) }; } }; } function isElement(maybeEl) { return ( maybeEl && maybeEl.classList && j$.isFunction_(maybeEl.classList.contains) ); } return toHaveClass; }; getJasmineRequireObj().toHaveSize = function(j$) { /** * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size. * @function * @name matchers#toHaveSize * @since 3.6.0 * @param {Object} expected - Expected size * @example * array = [1,2]; * expect(array).toHaveSize(2); */ function toHaveSize() { return { compare: function(actual, expected) { var result = { pass: false }; if ( j$.isA_('WeakSet', actual) || j$.isWeakMap(actual) || j$.isDataView(actual) ) { throw new Error('Cannot get size of ' + actual + '.'); } if (j$.isSet(actual) || j$.isMap(actual)) { result.pass = actual.size === expected; } else if (isLength(actual.length)) { result.pass = actual.length === expected; } else { result.pass = Object.keys(actual).length === expected; } return result; } }; } var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; function isLength(value) { return ( typeof value == 'number' && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER ); } return toHaveSize; }; getJasmineRequireObj().toMatch = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toMatch( || )' ); /** * {@link expect} the actual value to match a regular expression * @function * @name matchers#toMatch * @since 1.3.0 * @param {RegExp|String} expected - Value to look for in the string. * @example * expect("my string").toMatch(/string$/); * expect("other string").toMatch("her"); */ function toMatch() { return { compare: function(actual, expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { throw new Error(getErrorMsg('Expected is not a String or a RegExp')); } var regexp = new RegExp(expected); return { pass: regexp.test(actual) }; } }; } return toMatch; }; getJasmineRequireObj().toThrow = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect(function() {}).toThrow()' ); /** * {@link expect} a function to `throw` something. * @function * @name matchers#toThrow * @since 2.0.0 * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked. * @example * expect(function() { return 'things'; }).toThrow('foo'); * expect(function() { return 'stuff'; }).toThrow(); */ function toThrow(matchersUtil) { return { compare: function(actual, expected) { var result = { pass: false }, threw = false, thrown; if (typeof actual != 'function') { throw new Error(getErrorMsg('Actual is not a Function')); } try { actual(); } catch (e) { threw = true; thrown = e; } if (!threw) { result.message = 'Expected function to throw an exception.'; return result; } if (arguments.length == 1) { result.pass = true; result.message = function() { return ( 'Expected function not to throw, but it threw ' + matchersUtil.pp(thrown) + '.' ); }; return result; } if (matchersUtil.equals(thrown, expected)) { result.pass = true; result.message = function() { return ( 'Expected function not to throw ' + matchersUtil.pp(expected) + '.' ); }; } else { result.message = function() { return ( 'Expected function to throw ' + matchersUtil.pp(expected) + ', but it threw ' + matchersUtil.pp(thrown) + '.' ); }; } return result; } }; } return toThrow; }; getJasmineRequireObj().toThrowError = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect(function() {}).toThrowError(, )' ); /** * {@link expect} a function to `throw` an `Error`. * @function * @name matchers#toThrowError * @since 2.0.0 * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` * @example * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message'); * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/); * expect(function() { return 'stuff'; }).toThrowError(MyCustomError); * expect(function() { return 'other'; }).toThrowError(/foo/); * expect(function() { return 'other'; }).toThrowError(); */ function toThrowError(matchersUtil) { return { compare: function(actual) { var errorMatcher = getMatcher.apply(null, arguments), thrown; if (typeof actual != 'function') { throw new Error(getErrorMsg('Actual is not a Function')); } try { actual(); return fail('Expected function to throw an Error.'); } catch (e) { thrown = e; } if (!j$.isError_(thrown)) { return fail(function() { return ( 'Expected function to throw an Error, but it threw ' + matchersUtil.pp(thrown) + '.' ); }); } return errorMatcher.match(thrown); } }; function getMatcher() { var expected, errorType; if (arguments[2]) { errorType = arguments[1]; expected = arguments[2]; if (!isAnErrorType(errorType)) { throw new Error(getErrorMsg('Expected error type is not an Error.')); } return exactMatcher(expected, errorType); } else if (arguments[1]) { expected = arguments[1]; if (isAnErrorType(arguments[1])) { return exactMatcher(null, arguments[1]); } else { return exactMatcher(arguments[1], null); } } else { return anyMatcher(); } } function anyMatcher() { return { match: function(error) { return pass( 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.' ); } }; } function exactMatcher(expected, errorType) { if (expected && !isStringOrRegExp(expected)) { if (errorType) { throw new Error( getErrorMsg('Expected error message is not a string or RegExp.') ); } else { throw new Error( getErrorMsg('Expected is not an Error, string, or RegExp.') ); } } function messageMatch(message) { if (typeof expected == 'string') { return expected == message; } else { return expected.test(message); } } var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception'; function thrownDescription(thrown) { var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception', thrownMessage = ''; if (expected) { thrownMessage = ' with message ' + matchersUtil.pp(thrown.message); } return thrownName + thrownMessage; } function messageDescription() { if (expected === null) { return ''; } else if (expected instanceof RegExp) { return ' with a message matching ' + matchersUtil.pp(expected); } else { return ' with message ' + matchersUtil.pp(expected); } } function matches(error) { return ( (errorType === null || error instanceof errorType) && (expected === null || messageMatch(error.message)) ); } return { match: function(thrown) { if (matches(thrown)) { return pass(function() { return ( 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.' ); }); } else { return fail(function() { return ( 'Expected function to throw ' + errorTypeDescription + messageDescription() + ', but it threw ' + thrownDescription(thrown) + '.' ); }); } } }; } function isStringOrRegExp(potential) { return potential instanceof RegExp || typeof potential == 'string'; } function isAnErrorType(type) { if (typeof type !== 'function') { return false; } var Surrogate = function() {}; Surrogate.prototype = type.prototype; return j$.isError_(new Surrogate()); } } function pass(message) { return { pass: true, message: message }; } function fail(message) { return { pass: false, message: message }; } return toThrowError; }; getJasmineRequireObj().toThrowMatching = function(j$) { var usageError = j$.formatErrorMsg( '', 'expect(function() {}).toThrowMatching()' ); /** * {@link expect} a function to `throw` something matching a predicate. * @function * @name matchers#toThrowMatching * @since 3.0.0 * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches. * @example * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; }); */ function toThrowMatching(matchersUtil) { return { compare: function(actual, predicate) { var thrown; if (typeof actual !== 'function') { throw new Error(usageError('Actual is not a Function')); } if (typeof predicate !== 'function') { throw new Error(usageError('Predicate is not a Function')); } try { actual(); return fail('Expected function to throw an exception.'); } catch (e) { thrown = e; } if (predicate(thrown)) { return pass( 'Expected function not to throw an exception matching a predicate.' ); } else { return fail(function() { return ( 'Expected function to throw an exception matching a predicate, ' + 'but it threw ' + thrownDescription(thrown) + '.' ); }); } } }; function thrownDescription(thrown) { if (thrown && thrown.constructor) { return ( j$.fnNameFor(thrown.constructor) + ' with message ' + matchersUtil.pp(thrown.message) ); } else { return matchersUtil.pp(thrown); } } } function pass(message) { return { pass: true, message: message }; } function fail(message) { return { pass: false, message: message }; } return toThrowMatching; }; getJasmineRequireObj().MockDate = function(j$) { function MockDate(global) { var self = this; var currentTime = 0; if (!global || !global.Date) { self.install = function() {}; self.tick = function() {}; self.uninstall = function() {}; return self; } var GlobalDate = global.Date; self.install = function(mockDate) { if (mockDate instanceof GlobalDate) { currentTime = mockDate.getTime(); } else { if (!j$.util.isUndefined(mockDate)) { throw new Error( 'The argument to jasmine.clock().mockDate(), if specified, ' + 'should be a Date instance.' ); } currentTime = new GlobalDate().getTime(); } global.Date = FakeDate; }; self.tick = function(millis) { millis = millis || 0; currentTime = currentTime + millis; }; self.uninstall = function() { currentTime = 0; global.Date = GlobalDate; }; createDateProperties(); return self; function FakeDate() { switch (arguments.length) { case 0: return new GlobalDate(currentTime); case 1: return new GlobalDate(arguments[0]); case 2: return new GlobalDate(arguments[0], arguments[1]); case 3: return new GlobalDate(arguments[0], arguments[1], arguments[2]); case 4: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3] ); case 5: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4] ); case 6: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5] ); default: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6] ); } } function createDateProperties() { FakeDate.prototype = GlobalDate.prototype; FakeDate.now = function() { return currentTime; }; FakeDate.toSource = GlobalDate.toSource; FakeDate.toString = GlobalDate.toString; FakeDate.parse = GlobalDate.parse; FakeDate.UTC = GlobalDate.UTC; } } return MockDate; }; getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns) {} NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; return NeverSkipPolicy; }; getJasmineRequireObj().makePrettyPrinter = function(j$) { function SinglePrettyPrintRun(customObjectFormatters, pp) { this.customObjectFormatters_ = customObjectFormatters; this.ppNestLevel_ = 0; this.seen = []; this.length = 0; this.stringParts = []; this.pp_ = pp; } function hasCustomToString(value) { // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g. // iframe, web worker) try { return ( j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && value.toString() !== Object.prototype.toString.call(value) ); } catch (e) { // The custom toString() threw. return true; } } SinglePrettyPrintRun.prototype.format = function(value) { this.ppNestLevel_++; try { var customFormatResult = this.applyCustomFormatters_(value); if (customFormatResult) { this.emitScalar(customFormatResult); } else if (j$.util.isUndefined(value)) { this.emitScalar('undefined'); } else if (value === null) { this.emitScalar('null'); } else if (value === 0 && 1 / value === -Infinity) { this.emitScalar('-0'); } else if (value === j$.getGlobal()) { this.emitScalar(''); } else if (value.jasmineToString) { this.emitScalar(value.jasmineToString(this.pp_)); } else if (typeof value === 'string') { this.emitString(value); } else if (j$.isSpy(value)) { this.emitScalar('spy on ' + value.and.identity); } else if (j$.isSpy(value.toString)) { this.emitScalar('spy on ' + value.toString.and.identity); } else if (value instanceof RegExp) { this.emitScalar(value.toString()); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (j$.isDomNode(value)) { if (value.tagName) { this.emitDomElement(value); } else { this.emitScalar('HTMLNode'); } } else if (value instanceof Date) { this.emitScalar('Date(' + value + ')'); } else if (j$.isSet(value)) { this.emitSet(value); } else if (j$.isMap(value)) { this.emitMap(value); } else if (j$.isTypedArray_(value)) { this.emitTypedArray(value); } else if ( value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value) ) { try { this.emitScalar(value.toString()); } catch (e) { this.emitScalar('has-invalid-toString-method'); } } else if (j$.util.arrayContains(this.seen, value)) { this.emitScalar( '' ); } else if (j$.isArray_(value) || j$.isA_('Object', value)) { this.seen.push(value); if (j$.isArray_(value)) { this.emitArray(value); } else { this.emitObject(value); } this.seen.pop(); } else { this.emitScalar(value.toString()); } } catch (e) { if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) { throw e; } } finally { this.ppNestLevel_--; } }; SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) { return customFormat(value, this.customObjectFormatters_); }; SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) { var objKeys = keys(obj, j$.isArray_(obj)); var isGetter = function isGetter(prop) {}; if (obj.__lookupGetter__) { isGetter = function isGetter(prop) { var getter = obj.__lookupGetter__(prop); return !j$.util.isUndefined(getter) && getter !== null; }; } var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); for (var i = 0; i < length; i++) { var property = objKeys[i]; fn(property, isGetter(property)); } return objKeys.length > length; }; SinglePrettyPrintRun.prototype.emitScalar = function(value) { this.append(value); }; SinglePrettyPrintRun.prototype.emitString = function(value) { this.append("'" + value + "'"); }; SinglePrettyPrintRun.prototype.emitArray = function(array) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Array'); return; } var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); this.append('[ '); for (var i = 0; i < length; i++) { if (i > 0) { this.append(', '); } this.format(array[i]); } if (array.length > length) { this.append(', ...'); } var self = this; var first = array.length === 0; var truncated = this.iterateObject(array, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.formatProperty(array, property, isGetter); }); if (truncated) { this.append(', ...'); } this.append(' ]'); }; SinglePrettyPrintRun.prototype.emitSet = function(set) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Set'); return; } this.append('Set( '); var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); var i = 0; set.forEach(function(value, key) { if (i >= size) { return; } if (i > 0) { this.append(', '); } this.format(value); i++; }, this); if (set.size > size) { this.append(', ...'); } this.append(' )'); }; SinglePrettyPrintRun.prototype.emitMap = function(map) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Map'); return; } this.append('Map( '); var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); var i = 0; map.forEach(function(value, key) { if (i >= size) { return; } if (i > 0) { this.append(', '); } this.format([key, value]); i++; }, this); if (map.size > size) { this.append(', ...'); } this.append(' )'); }; SinglePrettyPrintRun.prototype.emitObject = function(obj) { var ctor = obj.constructor, constructorName; constructorName = typeof ctor === 'function' && obj instanceof ctor ? j$.fnNameFor(obj.constructor) : 'null'; this.append(constructorName); if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { return; } var self = this; this.append('({ '); var first = true; var truncated = this.iterateObject(obj, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.formatProperty(obj, property, isGetter); }); if (truncated) { this.append(', ...'); } this.append(' })'); }; SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) { var constructorName = j$.fnNameFor(arr.constructor), limitedArray = Array.prototype.slice.call( arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH ), itemsString = Array.prototype.join.call(limitedArray, ', '); if (limitedArray.length !== arr.length) { itemsString += ', ...'; } this.append(constructorName + ' [ ' + itemsString + ' ]'); }; SinglePrettyPrintRun.prototype.emitDomElement = function(el) { var tagName = el.tagName.toLowerCase(), attrs = el.attributes, i, len = attrs.length, out = '<' + tagName, attr; for (i = 0; i < len; i++) { attr = attrs[i]; out += ' ' + attr.name; if (attr.value !== '') { out += '="' + attr.value + '"'; } } out += '>'; if (el.childElementCount !== 0 || el.textContent !== '') { out += '...'; } this.append(out); }; SinglePrettyPrintRun.prototype.formatProperty = function( obj, property, isGetter ) { this.append(property); this.append(': '); if (isGetter) { this.append(''); } else { this.format(obj[property]); } }; SinglePrettyPrintRun.prototype.append = function(value) { // This check protects us from the rare case where an object has overriden // `toString()` with an invalid implementation (returning a non-string). if (typeof value !== 'string') { value = Object.prototype.toString.call(value); } var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length); this.length += result.value.length; this.stringParts.push(result.value); if (result.truncated) { throw new MaxCharsReachedError(); } }; function truncate(s, maxlen) { if (s.length <= maxlen) { return { value: s, truncated: false }; } s = s.substring(0, maxlen - 4) + ' ...'; return { value: s, truncated: true }; } function MaxCharsReachedError() { this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS + ' characters while pretty-printing a value'; } MaxCharsReachedError.prototype = new Error(); function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { if (j$.util.has(o, key)) { keys.push(key); } } return keys; })(obj); if (!isArray) { return allKeys; } if (allKeys.length === 0) { return allKeys; } var extraKeys = []; for (var i = 0; i < allKeys.length; i++) { if (!/^[0-9]+$/.test(allKeys[i])) { extraKeys.push(allKeys[i]); } } return extraKeys; } function customFormat(value, customObjectFormatters) { var i, result; for (i = 0; i < customObjectFormatters.length; i++) { result = customObjectFormatters[i](value); if (result !== undefined) { return result; } } } return function(customObjectFormatters) { customObjectFormatters = customObjectFormatters || []; var pp = function(value) { var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp); prettyPrinter.format(value); return prettyPrinter.stringParts.join(''); }; pp.customFormat_ = function(value) { return customFormat(value, customObjectFormatters); }; return pp; }; }; getJasmineRequireObj().QueueRunner = function(j$) { var nextid = 1; function StopExecutionError() {} StopExecutionError.prototype = new Error(); j$.StopExecutionError = StopExecutionError; function once(fn, onTwice) { var called = false; return function(arg) { if (called) { if (onTwice) { onTwice(); } } else { called = true; // Direct call using single parameter, because cleanup/next does not need more fn(arg); } return null; }; } function fallbackOnMultipleDone() { console.error( new Error( "An asynchronous function called its 'done' " + 'callback more than once, in a QueueRunner without a onMultipleDone ' + 'handler.' ) ); } function emptyFn() {} function QueueRunner(attrs) { this.id_ = nextid++; this.queueableFns = attrs.queueableFns || []; this.onComplete = attrs.onComplete || emptyFn; this.clearStack = attrs.clearStack || function(fn) { fn(); }; this.onException = attrs.onException || emptyFn; this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone; this.userContext = attrs.userContext || new j$.UserContext(); this.timeout = attrs.timeout || { setTimeout: setTimeout, clearTimeout: clearTimeout }; this.fail = attrs.fail || emptyFn; this.globalErrors = attrs.globalErrors || { pushListener: emptyFn, popListener: emptyFn }; const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns); this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); } this.deprecated = attrs.deprecated; } QueueRunner.prototype.execute = function() { var self = this; this.handleFinalError = function(message, source, lineno, colno, error) { // Older browsers would send the error as the first parameter. HTML5 // specifies the the five parameters above. The error instance should // be preffered, otherwise the call stack would get lost. self.onException(error || message); }; this.globalErrors.pushListener(this.handleFinalError); this.run(0); }; QueueRunner.prototype.clearTimeout = function(timeoutId) { Function.prototype.apply.apply(this.timeout.clearTimeout, [ j$.getGlobal(), [timeoutId] ]); }; QueueRunner.prototype.setTimeout = function(fn, timeout) { return Function.prototype.apply.apply(this.timeout.setTimeout, [ j$.getGlobal(), [fn, timeout] ]); }; QueueRunner.prototype.attempt = function attempt(iterativeIndex) { var self = this, completedSynchronously = true, handleError = function handleError(error) { // TODO probably shouldn't next() right away here. // That makes debugging async failures much more confusing. onException(error); }, cleanup = once(function cleanup() { if (timeoutId !== void 0) { self.clearTimeout(timeoutId); } self.globalErrors.popListener(handleError); }), next = once( function next(err) { cleanup(); if (typeof err !== 'undefined') { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } self.recordError_(iterativeIndex); } function runNext() { self.run(self.nextFnIx_(iterativeIndex)); } if (completedSynchronously) { self.setTimeout(runNext); } else { runNext(); } }, function() { try { if (!timedOut) { self.onMultipleDone(); } } catch (error) { // Any error we catch here is probably due to a bug in Jasmine, // and it's not likely to end up anywhere useful if we let it // propagate. Log it so it can at least show up when debugging. console.error(error); } } ), timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, maybeThenable; next.fail = function nextFail() { self.fail.apply(null, arguments); self.recordError_(iterativeIndex); next(); }; self.globalErrors.pushListener(handleError); if (queueableFn.timeout !== undefined) { var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL; timeoutId = self.setTimeout(function() { timedOut = true; var error = new Error( 'Timeout - Async function did not complete within ' + timeoutInterval + 'ms ' + (queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') ); // TODO Need to decide what to do about a successful completion after a // timeout. That should probably not be a deprecation, and maybe not // an error in 4.0. (But a diagnostic of some sort might be helpful.) onException(error); next(); }, timeoutInterval); } try { if (queueableFn.fn.length === 0) { maybeThenable = queueableFn.fn.call(self.userContext); if (maybeThenable && j$.isFunction_(maybeThenable.then)) { maybeThenable.then(next, onPromiseRejection); completedSynchronously = false; return { completedSynchronously: false }; } } else { maybeThenable = queueableFn.fn.call(self.userContext, next); this.diagnoseConflictingAsync_(queueableFn.fn, maybeThenable); completedSynchronously = false; return { completedSynchronously: false }; } } catch (e) { onException(e); self.recordError_(iterativeIndex); } cleanup(); return { completedSynchronously: true }; function onException(e) { self.onException(e); self.recordError_(iterativeIndex); } function onPromiseRejection(e) { onException(e); next(); } }; QueueRunner.prototype.run = function(recursiveIndex) { var length = this.queueableFns.length, self = this, iterativeIndex; for ( iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex = this.nextFnIx_(iterativeIndex) ) { var result = this.attempt(iterativeIndex); if (!result.completedSynchronously) { return; } } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); } }); }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); } return result; }; QueueRunner.prototype.recordError_ = function(currentFnIx) { this.errored_ = true; this.skipPolicy_.fnErrored(currentFnIx); }; QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; if (retval && j$.isFunction_(retval.then)) { // Issue a warning that matches the user's code. // Omit the stack trace because there's almost certainly no user code // on the stack at this point. if (j$.isAsyncFunction_(fn)) { this.onException( 'An asynchronous before/it/after ' + 'function was defined with the async keyword but also took a ' + 'done callback. Either remove the done callback (recommended) or ' + 'remove the async keyword.' ); } else { this.onException( 'An asynchronous before/it/after ' + 'function took a done callback but also returned a promise. ' + 'Either remove the done callback (recommended) or change the ' + 'function to not return a promise.' ); } this.deprecated(msg, { omitStackTrace: true }); } }; return QueueRunner; }; getJasmineRequireObj().ReportDispatcher = function(j$) { function ReportDispatcher(methods, queueRunnerFactory, onLateError) { var dispatchedMethods = methods || []; for (var i = 0; i < dispatchedMethods.length; i++) { var method = dispatchedMethods[i]; this[method] = (function(m) { return function() { dispatch(m, arguments); }; })(method); } var reporters = []; var fallbackReporter = null; this.addReporter = function(reporter) { reporters.push(reporter); }; this.provideFallbackReporter = function(reporter) { fallbackReporter = reporter; }; this.clearReporters = function() { reporters = []; }; return this; function dispatch(method, args) { if (reporters.length === 0 && fallbackReporter !== null) { reporters.push(fallbackReporter); } var onComplete = args[args.length - 1]; args = j$.util.argsToArray(args).splice(0, args.length - 1); var fns = []; for (var i = 0; i < reporters.length; i++) { var reporter = reporters[i]; addFn(fns, reporter, method, args); } queueRunnerFactory({ queueableFns: fns, onComplete: onComplete, isReporter: true, onMultipleDone: function() { onLateError( new Error( "An asynchronous reporter callback called its 'done' callback " + 'more than once.' ) ); } }); } function addFn(fns, reporter, method, args) { var fn = reporter[method]; if (!fn) { return; } var thisArgs = j$.util.cloneArgs(args); if (fn.length <= 1) { fns.push({ fn: function() { return fn.apply(reporter, thisArgs); } }); } else { fns.push({ fn: function(done) { return fn.apply(reporter, thisArgs.concat([done])); } }); } } } return ReportDispatcher; }; getJasmineRequireObj().interface = function(jasmine, env) { var jasmineInterface = { /** * Callback passed to parts of the Jasmine base interface. * * By default Jasmine assumes this function completes synchronously. * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment. * @callback implementationCallback * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. */ /** * Create a group of specs (often called a suite). * * Calls to `describe` can be nested within other calls to compose your suite as a tree. * @name describe * @since 1.3.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ describe: function(description, specDefinitions) { return env.describe(description, specDefinitions); }, /** * A temporarily disabled [`describe`]{@link describe} * * Specs within an `xdescribe` will be marked pending and not executed * @name xdescribe * @since 1.3.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ xdescribe: function(description, specDefinitions) { return env.xdescribe(description, specDefinitions); }, /** * A focused [`describe`]{@link describe} * * If suites or specs are focused, only those that are focused will be executed * @see fit * @name fdescribe * @since 2.1.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ fdescribe: function(description, specDefinitions) { return env.fdescribe(description, specDefinitions); }, /** * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code. * * A spec whose expectations all succeed will be passing and a spec with any failures will fail. * The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the * spec more readable by connecting the function name `it` and the argument `description` as a * complete sentence. * @name it * @since 1.3.0 * @function * @global * @param {String} description Textual description of what this spec is checking * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @see async */ it: function() { return env.it.apply(env, arguments); }, /** * A temporarily disabled [`it`]{@link it} * * The spec will report as `pending` and will not be executed. * @name xit * @since 1.3.0 * @function * @global * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed. */ xit: function() { return env.xit.apply(env, arguments); }, /** * A focused [`it`]{@link it} * * If suites or specs are focused, only those that are focused will be executed. * @name fit * @since 2.1.0 * @function * @global * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} testFunction Function that contains the code of your test. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @see async */ fit: function() { return env.fit.apply(env, arguments); }, /** * Run some shared setup before each of the specs in the {@link describe} in which it is called. * @name beforeEach * @since 1.3.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @see async */ beforeEach: function() { return env.beforeEach.apply(env, arguments); }, /** * Run some shared teardown after each of the specs in the {@link describe} in which it is called. * @name afterEach * @since 1.3.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @see async */ afterEach: function() { return env.afterEach.apply(env, arguments); }, /** * Run some shared setup once before all of the specs in the {@link describe} are run. * * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. * @name beforeAll * @since 2.1.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @see async */ beforeAll: function() { return env.beforeAll.apply(env, arguments); }, /** * Run some shared teardown once after all of the specs in the {@link describe} are run. * * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. * @name afterAll * @since 2.1.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @see async */ afterAll: function() { return env.afterAll.apply(env, arguments); }, /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} * @name setSpecProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ setSpecProperty: function(key, value) { return env.setSpecProperty(key, value); }, /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} * @name setSuiteProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ setSuiteProperty: function(key, value) { return env.setSuiteProperty(key, value); }, /** * Create an expectation for a spec. * @name expect * @since 1.3.0 * @function * @global * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ expect: function(actual) { return env.expect(actual); }, /** * Create an asynchronous expectation for a spec. Note that the matchers * that are provided by an asynchronous expectation all return promises * which must be either returned from the spec or waited for using `await` * in order for Jasmine to associate them with the correct spec. * @name expectAsync * @since 3.3.0 * @function * @global * @param {Object} actual - Actual computed value to test expectations against. * @return {async-matchers} * @example * await expectAsync(somePromise).toBeResolved(); * @example * return expectAsync(somePromise).toBeResolved(); */ expectAsync: function(actual) { return env.expectAsync(actual); }, /** * Mark a spec as pending, expectation results will be ignored. * @name pending * @since 2.0.0 * @function * @global * @param {String} [message] - Reason the spec is pending. */ pending: function() { return env.pending.apply(env, arguments); }, /** * Explicitly mark a spec as failed. * @name fail * @since 2.1.0 * @function * @global * @param {String|Error} [error] - Reason for the failure. */ fail: function() { return env.fail.apply(env, arguments); }, /** * Install a spy onto an existing object. * @name spyOn * @since 1.3.0 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy}. * @param {String} methodName - The name of the method to replace with a {@link Spy}. * @returns {Spy} */ spyOn: function(obj, methodName) { return env.spyOn(obj, methodName); }, /** * Install a spy on a property installed with `Object.defineProperty` onto an existing object. * @name spyOnProperty * @since 2.6.0 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy} * @param {String} propertyName - The name of the property to replace with a {@link Spy}. * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on. * @returns {Spy} */ spyOnProperty: function(obj, methodName, accessType) { return env.spyOnProperty(obj, methodName, accessType); }, /** * Installs spies on all writable and configurable properties of an object. * @name spyOnAllFunctions * @since 3.2.1 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy}s * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties * @returns {Object} the spied object */ spyOnAllFunctions: function(obj, includeNonEnumerable) { return env.spyOnAllFunctions(obj, includeNonEnumerable); }, jsApiReporter: new jasmine.JsApiReporter({ timer: new jasmine.Timer() }), /** * @namespace jasmine */ jasmine: jasmine }; /** * Add a custom equality tester for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addCustomEqualityTester * @since 2.0.0 * @function * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise. * @see custom_equality */ jasmine.addCustomEqualityTester = function(tester) { env.addCustomEqualityTester(tester); }; /** * Add custom matchers for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addMatchers * @since 2.0.0 * @function * @param {Object} matchers - Keys from this object will be the new matcher names. * @see custom_matcher */ jasmine.addMatchers = function(matchers) { return env.addMatchers(matchers); }; /** * Add custom async matchers for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addAsyncMatchers * @since 3.5.0 * @function * @param {Object} matchers - Keys from this object will be the new async matcher names. * @see custom_matcher */ jasmine.addAsyncMatchers = function(matchers) { return env.addAsyncMatchers(matchers); }; /** * Add a custom object formatter for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addCustomObjectFormatter * @since 3.6.0 * @function * @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise. * @see custom_object_formatters */ jasmine.addCustomObjectFormatter = function(formatter) { return env.addCustomObjectFormatter(formatter); }; /** * Get the currently booted mock {Clock} for this Jasmine environment. * @name jasmine.clock * @since 2.0.0 * @function * @returns {Clock} */ jasmine.clock = function() { return env.clock; }; /** * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it. * @name jasmine.createSpy * @since 1.3.0 * @function * @param {String} [name] - Name to give the spy. This will be displayed in failure messages. * @param {Function} [originalFn] - Function to act as the real implementation. * @return {Spy} */ jasmine.createSpy = function(name, originalFn) { return env.createSpy(name, originalFn); }; /** * Create an object with multiple {@link Spy}s as its members. * @name jasmine.createSpyObj * @since 1.3.0 * @function * @param {String} [baseName] - Base name for the spies in the object. * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}. * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}. * @return {Object} */ jasmine.createSpyObj = function(baseName, methodNames, propertyNames) { return env.createSpyObj(baseName, methodNames, propertyNames); }; /** * Add a custom spy strategy for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addSpyStrategy * @since 3.5.0 * @function * @param {String} name - The name of the strategy (i.e. what you call from `and`) * @param {Function} factory - Factory function that returns the plan to be executed. */ jasmine.addSpyStrategy = function(name, factory) { return env.addSpyStrategy(name, factory); }; /** * Set the default spy strategy for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.setDefaultSpyStrategy * @function * @param {Function} defaultStrategyFn - a function that assigns a strategy * @example * beforeEach(function() { * jasmine.setDefaultSpyStrategy(and => and.returnValue(true)); * }); */ jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) { return env.setDefaultSpyStrategy(defaultStrategyFn); }; return jasmineInterface; }; getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { function SkipAfterBeforeAllErrorPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.skipping_ = false; } SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { if (this.skipping_) { return this.nextAfterAllAfter_(lastRanFnIx); } else { return lastRanFnIx + 1; } }; SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { for ( i++; i < this.queueableFns_.length && this.queueableFns_[i].type !== 'afterAll'; i++ ) {} return i; }; SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { if (this.queueableFns_[fnIx].type === 'beforeAll') { this.skipping_ = true; // Failures need to be reported for each contained spec. But we can't do // that from here because reporting is async. This function isn't async // (and can't be without greatly complicating QueueRunner). Mark the // failure so that the code that reports the suite result (which is // already async) can detect the failure and report the specs. this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true; } }; return SkipAfterBeforeAllErrorPolicy; }; getJasmineRequireObj().Spy = function(j$) { var nextOrder = (function() { var order = 0; return function() { return order++; }; })(); /** * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn}, * {@link spyOnProperty}, {@link jasmine.createSpy}, or * {@link jasmine.createSpyObj} instead. * @class Spy * @hideconstructor */ function Spy(name, matchersUtil, optionals) { const { originalFn, customStrategies, defaultStrategyFn } = optionals || {}; var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); }), strategyDispatcher = new SpyStrategyDispatcher( { name: name, fn: originalFn, getSpy: function() { return wrapper; }, customStrategies: customStrategies }, matchersUtil ), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { /** * @name Spy.callData * @property {object} object - `this` context for the invocation. * @property {number} invocationOrder - Order of the invocation. * @property {Array} args - The arguments passed for this invocation. * @property returnValue - The value that was returned from this invocation. */ var callData = { object: context, invocationOrder: nextOrder(), args: Array.prototype.slice.apply(args) }; callTracker.track(callData); var returnValue = strategyDispatcher.exec(context, args, invokeNew); callData.returnValue = returnValue; return returnValue; }; function makeFunc(length, fn) { switch (length) { case 1: return function wrap1(a) { return fn(this, arguments, this instanceof wrap1); }; case 2: return function wrap2(a, b) { return fn(this, arguments, this instanceof wrap2); }; case 3: return function wrap3(a, b, c) { return fn(this, arguments, this instanceof wrap3); }; case 4: return function wrap4(a, b, c, d) { return fn(this, arguments, this instanceof wrap4); }; case 5: return function wrap5(a, b, c, d, e) { return fn(this, arguments, this instanceof wrap5); }; case 6: return function wrap6(a, b, c, d, e, f) { return fn(this, arguments, this instanceof wrap6); }; case 7: return function wrap7(a, b, c, d, e, f, g) { return fn(this, arguments, this instanceof wrap7); }; case 8: return function wrap8(a, b, c, d, e, f, g, h) { return fn(this, arguments, this instanceof wrap8); }; case 9: return function wrap9(a, b, c, d, e, f, g, h, i) { return fn(this, arguments, this instanceof wrap9); }; default: return function wrap() { return fn(this, arguments, this instanceof wrap); }; } } for (var prop in originalFn) { if (prop === 'and' || prop === 'calls') { throw new Error( "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon" ); } wrapper[prop] = originalFn[prop]; } /** * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used * whenever the spy is called with arguments that don't match any strategy * created with {@link Spy#withArgs}. * @name Spy#and * @since 2.0.0 * @example * spyOn(someObj, 'func').and.returnValue(42); */ wrapper.and = strategyDispatcher.and; /** * Specifies a strategy to be used for calls to the spy that have the * specified arguments. * @name Spy#withArgs * @since 3.0.0 * @function * @param {...*} args - The arguments to match * @type {SpyStrategy} * @example * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42); * someObj.func(1, 2, 3); // returns 42 */ wrapper.withArgs = function() { return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments); }; wrapper.calls = callTracker; if (defaultStrategyFn) { defaultStrategyFn(wrapper.and); } return wrapper; } function SpyStrategyDispatcher(strategyArgs, matchersUtil) { var baseStrategy = new j$.SpyStrategy(strategyArgs); var argsStrategies = new StrategyDict(function() { return new j$.SpyStrategy(strategyArgs); }, matchersUtil); this.and = baseStrategy; this.exec = function(spy, args, invokeNew) { var strategy = argsStrategies.get(args); if (!strategy) { if (argsStrategies.any() && !baseStrategy.isConfigured()) { throw new Error( "Spy '" + strategyArgs.name + "' received a call with arguments " + j$.basicPrettyPrinter_(Array.prototype.slice.call(args)) + ' but all configured strategies specify other arguments.' ); } else { strategy = baseStrategy; } } return strategy.exec(spy, args, invokeNew); }; this.withArgs = function() { return { and: argsStrategies.getOrCreate(arguments) }; }; } function StrategyDict(strategyFactory, matchersUtil) { this.strategies = []; this.strategyFactory = strategyFactory; this.matchersUtil = matchersUtil; } StrategyDict.prototype.any = function() { return this.strategies.length > 0; }; StrategyDict.prototype.getOrCreate = function(args) { var strategy = this.get(args); if (!strategy) { strategy = this.strategyFactory(); this.strategies.push({ args: args, strategy: strategy }); } return strategy; }; StrategyDict.prototype.get = function(args) { var i; for (i = 0; i < this.strategies.length; i++) { if (this.matchersUtil.equals(args, this.strategies[i].args)) { return this.strategies[i].strategy; } } }; return Spy; }; getJasmineRequireObj().SpyFactory = function(j$) { function SpyFactory( getCustomStrategies, getDefaultStrategyFn, getMatchersUtil ) { var self = this; this.createSpy = function(name, originalFn) { return j$.Spy(name, getMatchersUtil(), { originalFn, customStrategies: getCustomStrategies(), defaultStrategyFn: getDefaultStrategyFn() }); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName); if (baseNameIsCollection) { propertyNames = methodNames; methodNames = baseName; baseName = 'unknown'; } var obj = {}; var spy, descriptor; var methods = normalizeKeyValues(methodNames); for (var i = 0; i < methods.length; i++) { spy = obj[methods[i][0]] = self.createSpy( baseName + '.' + methods[i][0] ); if (methods[i].length > 1) { spy.and.returnValue(methods[i][1]); } } var properties = normalizeKeyValues(propertyNames); for (var i = 0; i < properties.length; i++) { descriptor = { enumerable: true, get: self.createSpy(baseName + '.' + properties[i][0] + '.get'), set: self.createSpy(baseName + '.' + properties[i][0] + '.set') }; if (properties[i].length > 1) { descriptor.get.and.returnValue(properties[i][1]); descriptor.set.and.returnValue(properties[i][1]); } Object.defineProperty(obj, properties[i][0], descriptor); } if (methods.length === 0 && properties.length === 0) { throw 'createSpyObj requires a non-empty array or object of method names to create spies for'; } return obj; }; } function normalizeKeyValues(object) { var result = []; if (j$.isArray_(object)) { for (var i = 0; i < object.length; i++) { result.push([object[i]]); } } else if (j$.isObject_(object)) { for (var key in object) { if (object.hasOwnProperty(key)) { result.push([key, object[key]]); } } } return result; } return SpyFactory; }; getJasmineRequireObj().SpyRegistry = function(j$) { var spyOnMsg = j$.formatErrorMsg('', 'spyOn(, )'); var spyOnPropertyMsg = j$.formatErrorMsg( '', 'spyOnProperty(, , [accessType])' ); function SpyRegistry(options) { options = options || {}; var global = options.global || j$.getGlobal(); var createSpy = options.createSpy; var currentSpies = options.currentSpies || function() { return []; }; this.allowRespy = function(allow) { this.respy = allow; }; this.spyOn = function(obj, methodName) { var getErrorMsg = spyOnMsg; if (j$.util.isUndefined(obj) || obj === null) { throw new Error( getErrorMsg( 'could not find an object to spy upon for ' + methodName + '()' ) ); } if (j$.util.isUndefined(methodName) || methodName === null) { throw new Error(getErrorMsg('No method name supplied')); } if (j$.util.isUndefined(obj[methodName])) { throw new Error(getErrorMsg(methodName + '() method does not exist')); } if (obj[methodName] && j$.isSpy(obj[methodName])) { if (this.respy) { return obj[methodName]; } else { throw new Error( getErrorMsg(methodName + ' has already been spied upon') ); } } var descriptor = Object.getOwnPropertyDescriptor(obj, methodName); if (descriptor && !(descriptor.writable || descriptor.set)) { throw new Error( getErrorMsg(methodName + ' is not declared writable or has no setter') ); } var originalMethod = obj[methodName], spiedMethod = createSpy(methodName, originalMethod), restoreStrategy; if ( Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror') ) { restoreStrategy = function() { obj[methodName] = originalMethod; }; } else { restoreStrategy = function() { if (!delete obj[methodName]) { obj[methodName] = originalMethod; } }; } currentSpies().push({ restoreObjectToOriginalState: restoreStrategy }); obj[methodName] = spiedMethod; return spiedMethod; }; this.spyOnProperty = function(obj, propertyName, accessType) { var getErrorMsg = spyOnPropertyMsg; accessType = accessType || 'get'; if (j$.util.isUndefined(obj)) { throw new Error( getErrorMsg( 'spyOn could not find an object to spy upon for ' + propertyName + '' ) ); } if (j$.util.isUndefined(propertyName)) { throw new Error(getErrorMsg('No property name supplied')); } var descriptor = j$.util.getPropertyDescriptor(obj, propertyName); if (!descriptor) { throw new Error(getErrorMsg(propertyName + ' property does not exist')); } if (!descriptor.configurable) { throw new Error( getErrorMsg(propertyName + ' is not declared configurable') ); } if (!descriptor[accessType]) { throw new Error( getErrorMsg( 'Property ' + propertyName + ' does not have access type ' + accessType ) ); } if (j$.isSpy(descriptor[accessType])) { if (this.respy) { return descriptor[accessType]; } else { throw new Error( getErrorMsg( propertyName + '#' + accessType + ' has already been spied upon' ) ); } } var originalDescriptor = j$.util.clone(descriptor), spy = createSpy(propertyName, descriptor[accessType]), restoreStrategy; if (Object.prototype.hasOwnProperty.call(obj, propertyName)) { restoreStrategy = function() { Object.defineProperty(obj, propertyName, originalDescriptor); }; } else { restoreStrategy = function() { delete obj[propertyName]; }; } currentSpies().push({ restoreObjectToOriginalState: restoreStrategy }); descriptor[accessType] = spy; Object.defineProperty(obj, propertyName, descriptor); return spy; }; this.spyOnAllFunctions = function(obj, includeNonEnumerable) { if (j$.util.isUndefined(obj)) { throw new Error( 'spyOnAllFunctions could not find an object to spy upon' ); } var pointer = obj, propsToSpyOn = [], properties, propertiesToSkip = []; while ( pointer && (!includeNonEnumerable || pointer !== Object.prototype) ) { properties = getProps(pointer, includeNonEnumerable); properties = properties.filter(function(prop) { return propertiesToSkip.indexOf(prop) === -1; }); propertiesToSkip = propertiesToSkip.concat(properties); propsToSpyOn = propsToSpyOn.concat( getSpyableFunctionProps(pointer, properties) ); pointer = Object.getPrototypeOf(pointer); } for (var i = 0; i < propsToSpyOn.length; i++) { this.spyOn(obj, propsToSpyOn[i]); } return obj; }; this.clearSpies = function() { var spies = currentSpies(); for (var i = spies.length - 1; i >= 0; i--) { var spyEntry = spies[i]; spyEntry.restoreObjectToOriginalState(); } }; } function getProps(obj, includeNonEnumerable) { var enumerableProperties = Object.keys(obj); if (!includeNonEnumerable) { return enumerableProperties; } return Object.getOwnPropertyNames(obj).filter(function(prop) { return ( prop !== 'constructor' || enumerableProperties.indexOf('constructor') > -1 ); }); } function getSpyableFunctionProps(obj, propertiesToCheck) { var props = [], prop; for (var i = 0; i < propertiesToCheck.length; i++) { prop = propertiesToCheck[i]; if ( Object.prototype.hasOwnProperty.call(obj, prop) && isSpyableProp(obj, prop) ) { props.push(prop); } } return props; } function isSpyableProp(obj, prop) { var value, descriptor; try { value = obj[prop]; } catch (e) { return false; } if (value instanceof Function) { descriptor = Object.getOwnPropertyDescriptor(obj, prop); return (descriptor.writable || descriptor.set) && descriptor.configurable; } return false; } return SpyRegistry; }; getJasmineRequireObj().SpyStrategy = function(j$) { /** * @interface SpyStrategy */ function SpyStrategy(options) { options = options || {}; var self = this; /** * Get the identifying information for the spy. * @name SpyStrategy#identity * @since 3.0.0 * @member * @type {String} */ this.identity = options.name || 'unknown'; this.originalFn = options.fn || function() {}; this.getSpy = options.getSpy || function() {}; this.plan = this._defaultPlan = function() {}; var k, cs = options.customStrategies || {}; for (k in cs) { if (j$.util.has(cs, k) && !this[k]) { this[k] = createCustomPlan(cs[k]); } } /** * Tell the spy to return a promise resolving to the specified value when invoked. * @name SpyStrategy#resolveTo * @since 3.5.0 * @function * @param {*} value The value to return. */ this.resolveTo = function(value) { self.plan = function() { return Promise.resolve(value); }; return self.getSpy(); }; /** * Tell the spy to return a promise rejecting with the specified value when invoked. * @name SpyStrategy#rejectWith * @since 3.5.0 * @function * @param {*} value The value to return. */ this.rejectWith = function(value) { self.plan = function() { return Promise.reject(value); }; return self.getSpy(); }; } function createCustomPlan(factory) { return function() { var plan = factory.apply(null, arguments); if (!j$.isFunction_(plan)) { throw new Error('Spy strategy must return a function'); } this.plan = plan; return this.getSpy(); }; } /** * Execute the current spy strategy. * @name SpyStrategy#exec * @since 2.0.0 * @function */ SpyStrategy.prototype.exec = function(context, args, invokeNew) { var contextArgs = [context].concat( args ? Array.prototype.slice.call(args) : [] ); var target = this.plan.bind.apply(this.plan, contextArgs); return invokeNew ? new target() : target(); }; /** * Tell the spy to call through to the real implementation when invoked. * @name SpyStrategy#callThrough * @since 2.0.0 * @function */ SpyStrategy.prototype.callThrough = function() { this.plan = this.originalFn; return this.getSpy(); }; /** * Tell the spy to return the value when invoked. * @name SpyStrategy#returnValue * @since 2.0.0 * @function * @param {*} value The value to return. */ SpyStrategy.prototype.returnValue = function(value) { this.plan = function() { return value; }; return this.getSpy(); }; /** * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked. * @name SpyStrategy#returnValues * @since 2.1.0 * @function * @param {...*} values - Values to be returned on subsequent calls to the spy. */ SpyStrategy.prototype.returnValues = function() { var values = Array.prototype.slice.call(arguments); this.plan = function() { return values.shift(); }; return this.getSpy(); }; /** * Tell the spy to throw an error when invoked. * @name SpyStrategy#throwError * @since 2.0.0 * @function * @param {Error|Object|String} something Thing to throw */ SpyStrategy.prototype.throwError = function(something) { var error = j$.isString_(something) ? new Error(something) : something; this.plan = function() { throw error; }; return this.getSpy(); }; /** * Tell the spy to call a fake implementation when invoked. * @name SpyStrategy#callFake * @since 2.0.0 * @function * @param {Function} fn The function to invoke with the passed parameters. */ SpyStrategy.prototype.callFake = function(fn) { if ( !( j$.isFunction_(fn) || j$.isAsyncFunction_(fn) || j$.isGeneratorFunction_(fn) ) ) { throw new Error( 'Argument passed to callFake should be a function, got ' + fn ); } this.plan = fn; return this.getSpy(); }; /** * Tell the spy to do nothing when invoked. This is the default. * @name SpyStrategy#stub * @since 2.0.0 * @function */ SpyStrategy.prototype.stub = function(fn) { this.plan = function() {}; return this.getSpy(); }; SpyStrategy.prototype.isConfigured = function() { return this.plan !== this._defaultPlan; }; return SpyStrategy; }; getJasmineRequireObj().StackTrace = function(j$) { function StackTrace(error) { var lines = error.stack.split('\n').filter(function(line) { return line !== ''; }); var extractResult = extractMessage(error.message, lines); if (extractResult) { this.message = extractResult.message; lines = extractResult.remainder; } var parseResult = tryParseFrames(lines); this.frames = parseResult.frames; this.style = parseResult.style; } var framePatterns = [ // Node, Chrome, Edge // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)" // Note that the "function name" can include a surprisingly large set of // characters, including angle brackets and square brackets. { re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, fnIx: 1, fileLineColIx: 2, style: 'v8' }, // NodeJS alternate form, often mixed in with the Chrome style // e.g. " at /some/path:4320:20 { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' }, // PhantomJS on OS X, Safari, Firefox // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27" // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27" { re: /^(?:(([^@\s]+)@)|@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' } ]; // regexes should capture the function name (if any) as group 1 // and the file, line, and column as group 2. function tryParseFrames(lines) { var style = null; var frames = lines.map(function(line) { var convertedLine = first(framePatterns, function(pattern) { var overallMatch = line.match(pattern.re), fileLineColMatch; if (!overallMatch) { return null; } fileLineColMatch = overallMatch[pattern.fileLineColIx].match( /^(.*):(\d+):\d+$/ ); if (!fileLineColMatch) { return null; } style = style || pattern.style; return { raw: line, file: fileLineColMatch[1], line: parseInt(fileLineColMatch[2], 10), func: overallMatch[pattern.fnIx] }; }); return convertedLine || { raw: line }; }); return { style: style, frames: frames }; } function first(items, fn) { var i, result; for (i = 0; i < items.length; i++) { result = fn(items[i]); if (result) { return result; } } } function extractMessage(message, stackLines) { var len = messagePrefixLength(message, stackLines); if (len > 0) { return { message: stackLines.slice(0, len).join('\n'), remainder: stackLines.slice(len) }; } } function messagePrefixLength(message, stackLines) { if (!stackLines[0].match(/^\w*Error/)) { return 0; } var messageLines = message.split('\n'); var i; for (i = 1; i < messageLines.length; i++) { if (messageLines[i] !== stackLines[i]) { return 0; } } return messageLines.length; } return StackTrace; }; getJasmineRequireObj().Suite = function(j$) { /** * @interface Suite * @see Env#topSuite * @since 2.0.0 */ function Suite(attrs) { this.env = attrs.env; /** * The unique ID of this suite. * @name Suite#id * @readonly * @type {string} * @since 2.0.0 */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; /** * The description passed to the {@link describe} that created this suite. * @name Suite#description * @readonly * @type {string} * @since 2.0.0 */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.expectationResultFactory = attrs.expectationResultFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; this.onLateError = attrs.onLateError; this.beforeFns = []; this.afterFns = []; this.beforeAllFns = []; this.afterAllFns = []; this.timer = attrs.timer || new j$.Timer(); /** * The suite's children. * @name Suite#children * @type {Array.<(Spec|Suite)>} * @since 2.0.0 */ this.children = []; this.reset(); } Suite.prototype.setSuiteProperty = function(key, value) { this.result.properties = this.result.properties || {}; this.result.properties[key] = value; }; Suite.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; Suite.prototype.expectAsync = function(actual) { return this.asyncExpectationFactory(actual, this); }; /** * The full description including all ancestors of this suite. * @name Suite#getFullName * @function * @returns {string} * @since 2.0.0 */ Suite.prototype.getFullName = function() { var fullName = []; for ( var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite ) { if (parentSuite.parentSuite) { fullName.unshift(parentSuite.description); } } return fullName.join(' '); }; /* * Mark the suite with "pending" status */ Suite.prototype.pend = function() { this.markedPending = true; }; /* * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset} * Useful for fdescribe, xdescribe, where pending state should remain. */ Suite.prototype.exclude = function() { this.pend(); this.markedExcluding = true; }; Suite.prototype.beforeEach = function(fn) { this.beforeFns.unshift({ ...fn, suite: this }); }; Suite.prototype.beforeAll = function(fn) { this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); }; Suite.prototype.afterEach = function(fn) { this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); }; Suite.prototype.afterAll = function(fn) { this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); }; Suite.prototype.startTimer = function() { this.timer.start(); }; Suite.prototype.endTimer = function() { this.result.duration = this.timer.elapsed(); }; function removeFns(queueableFns) { for (var i = 0; i < queueableFns.length; i++) { queueableFns[i].fn = null; } } Suite.prototype.cleanupBeforeAfter = function() { if (this.autoCleanClosures) { removeFns(this.beforeAllFns); removeFns(this.afterAllFns); removeFns(this.beforeFns); removeFns(this.afterFns); } }; Suite.prototype.reset = function() { /** * @typedef SuiteResult * @property {Int} id - The unique id of this suite. * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} * @since 2.0.0 */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], deprecationWarnings: [], duration: null, properties: null }; this.markedPending = this.markedExcluding; this.children.forEach(function(child) { child.reset(); }); }; Suite.prototype.addChild = function(child) { this.children.push(child); }; Suite.prototype.status = function() { if (this.markedPending) { return 'pending'; } if (this.result.failedExpectations.length > 0) { return 'failed'; } else { return 'passed'; } }; Suite.prototype.canBeReentered = function() { return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; }; Suite.prototype.getResult = function() { this.result.status = this.status(); return this.result; }; Suite.prototype.sharedUserContext = function() { if (!this.sharedContext) { this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext(); } return this.sharedContext; }; Suite.prototype.clonedSharedUserContext = function() { return j$.UserContext.fromExisting(this.sharedUserContext()); }; Suite.prototype.onException = function() { if (arguments[0] instanceof j$.errors.ExpectationFailed) { return; } var data = { matcherName: '', passed: false, expected: '', actual: '', error: arguments[0] }; var failedExpectation = this.expectationResultFactory(data); if (!this.parentSuite) { failedExpectation.globalErrorType = 'afterAll'; } this.result.failedExpectations.push(failedExpectation); }; Suite.prototype.onMultipleDone = function() { let msg; // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. if (this.parentSuite) { msg = "An asynchronous beforeAll or afterAll function called its 'done' " + 'callback more than once.\n' + '(in suite: ' + this.getFullName() + ')'; } else { msg = 'A top-level beforeAll or afterAll function called its ' + "'done' callback more than once."; } this.onLateError(new Error(msg)); }; Suite.prototype.addExpectationResult = function() { if (isFailure(arguments)) { var data = arguments[1]; this.result.failedExpectations.push(this.expectationResultFactory(data)); if (this.throwOnExpectationFailure) { throw new j$.errors.ExpectationFailed(); } } }; Suite.prototype.addDeprecationWarning = function(deprecation) { if (typeof deprecation === 'string') { deprecation = { message: deprecation }; } this.result.deprecationWarnings.push( this.expectationResultFactory(deprecation) ); }; Object.defineProperty(Suite.prototype, 'metadata', { get: function() { if (!this.metadata_) { this.metadata_ = new SuiteMetadata(this); } return this.metadata_; } }); /** * @interface Suite * @see Env#topSuite */ function SuiteMetadata(suite) { this.suite_ = suite; /** * The unique ID of this suite. * @name Suite#id * @readonly * @type {string} */ this.id = suite.id; /** * The parent of this suite, or null if this is the top suite. * @name Suite#parentSuite * @readonly * @type {Suite} */ this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; /** * The description passed to the {@link describe} that created this suite. * @name Suite#description * @readonly * @type {string} */ this.description = suite.description; } /** * The full description including all ancestors of this suite. * @name Suite#getFullName * @function * @returns {string} */ SuiteMetadata.prototype.getFullName = function() { return this.suite_.getFullName(); }; /** * The suite's children. * @name Suite#children * @type {Array.<(Spec|Suite)>} */ Object.defineProperty(SuiteMetadata.prototype, 'children', { get: function() { return this.suite_.children.map(child => child.metadata); } }); function isFailure(args) { return !args[0]; } return Suite; }; getJasmineRequireObj().Timer = function() { var defaultNow = (function(Date) { return function() { return new Date().getTime(); }; })(Date); function Timer(options) { options = options || {}; var now = options.now || defaultNow, startTime; this.start = function() { startTime = now(); }; this.elapsed = function() { return now() - startTime; }; } return Timer; }; getJasmineRequireObj().TreeProcessor = function() { function TreeProcessor(attrs) { var tree = attrs.tree, runnableIds = attrs.runnableIds, queueRunnerFactory = attrs.queueRunnerFactory, nodeStart = attrs.nodeStart || function() {}, nodeComplete = attrs.nodeComplete || function() {}, failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations, orderChildren = attrs.orderChildren || function(node) { return node.children; }, excludeNode = attrs.excludeNode || function(node) { return false; }, stats = { valid: true }, processed = false, defaultMin = Infinity, defaultMax = 1 - Infinity; this.processTree = function() { processNode(tree, true); processed = true; return stats; }; this.execute = function(done) { if (!processed) { this.processTree(); } if (!stats.valid) { throw 'invalid order'; } var childFns = wrapChildren(tree, 0); queueRunnerFactory({ queueableFns: childFns, userContext: tree.sharedUserContext(), onException: function() { tree.onException.apply(tree, arguments); }, onComplete: done, onMultipleDone: tree.onMultipleDone ? tree.onMultipleDone.bind(tree) : null }); }; function runnableIndex(id) { for (var i = 0; i < runnableIds.length; i++) { if (runnableIds[i] === id) { return i; } } } function processNode(node, parentExcluded) { var executableIndex = runnableIndex(node.id); if (executableIndex !== undefined) { parentExcluded = false; } if (!node.children) { var excluded = parentExcluded || excludeNode(node); stats[node.id] = { excluded: excluded, willExecute: !excluded && !node.markedPending, segments: [ { index: 0, owner: node, nodes: [node], min: startingMin(executableIndex), max: startingMax(executableIndex) } ] }; } else { var hasExecutableChild = false; var orderedChildren = orderChildren(node); for (var i = 0; i < orderedChildren.length; i++) { var child = orderedChildren[i]; processNode(child, parentExcluded); if (!stats.valid) { return; } var childStats = stats[child.id]; hasExecutableChild = hasExecutableChild || childStats.willExecute; } stats[node.id] = { excluded: parentExcluded, willExecute: hasExecutableChild }; segmentChildren(node, orderedChildren, stats[node.id], executableIndex); if (!node.canBeReentered() && stats[node.id].segments.length > 1) { stats = { valid: false }; } } } function startingMin(executableIndex) { return executableIndex === undefined ? defaultMin : executableIndex; } function startingMax(executableIndex) { return executableIndex === undefined ? defaultMax : executableIndex; } function segmentChildren( node, orderedChildren, nodeStats, executableIndex ) { var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) }, result = [currentSegment], lastMax = defaultMax, orderedChildSegments = orderChildSegments(orderedChildren); function isSegmentBoundary(minIndex) { return ( lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1 ); } for (var i = 0; i < orderedChildSegments.length; i++) { var childSegment = orderedChildSegments[i], maxIndex = childSegment.max, minIndex = childSegment.min; if (isSegmentBoundary(minIndex)) { currentSegment = { index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax }; result.push(currentSegment); } currentSegment.nodes.push(childSegment); currentSegment.min = Math.min(currentSegment.min, minIndex); currentSegment.max = Math.max(currentSegment.max, maxIndex); lastMax = maxIndex; } nodeStats.segments = result; } function orderChildSegments(children) { var specifiedOrder = [], unspecifiedOrder = []; for (var i = 0; i < children.length; i++) { var child = children[i], segments = stats[child.id].segments; for (var j = 0; j < segments.length; j++) { var seg = segments[j]; if (seg.min === defaultMin) { unspecifiedOrder.push(seg); } else { specifiedOrder.push(seg); } } } specifiedOrder.sort(function(a, b) { return a.min - b.min; }); return specifiedOrder.concat(unspecifiedOrder); } function executeNode(node, segmentNumber) { if (node.children) { return { fn: function(done) { var onStart = { fn: function(next) { nodeStart(node, next); } }; queueRunnerFactory({ onComplete: function() { var args = Array.prototype.slice.call(arguments, [0]); node.cleanupBeforeAfter(); nodeComplete(node, node.getResult(), function() { done.apply(undefined, args); }); }, queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)), userContext: node.sharedUserContext(), onException: function() { node.onException.apply(node, arguments); }, onMultipleDone: node.onMultipleDone ? node.onMultipleDone.bind(node) : null }); } }; } else { return { fn: function(done) { node.execute( done, stats[node.id].excluded, failSpecWithNoExpectations ); } }; } } function wrapChildren(node, segmentNumber) { var result = [], segmentChildren = stats[node.id].segments[segmentNumber].nodes; for (var i = 0; i < segmentChildren.length; i++) { result.push( executeNode(segmentChildren[i].owner, segmentChildren[i].index) ); } if (!stats[node.id].willExecute) { return result; } return node.beforeAllFns.concat(result).concat(node.afterAllFns); } } return TreeProcessor; }; getJasmineRequireObj().UserContext = function(j$) { function UserContext() {} UserContext.fromExisting = function(oldContext) { var context = new UserContext(); for (var prop in oldContext) { if (oldContext.hasOwnProperty(prop)) { context[prop] = oldContext[prop]; } } return context; }; return UserContext; }; getJasmineRequireObj().version = function() { return '4.0.0'; }; jasmine-4.0.0/lib/jasmine-core/node_boot.js000066400000000000000000000027251416413636100206040ustar00rootroot00000000000000/* Copyright (c) 2008-2022 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ module.exports = function(jasmineRequire) { var jasmine = jasmineRequire.core(jasmineRequire); var env = jasmine.getEnv({ suppressLoadErrors: true }); var jasmineInterface = jasmineRequire.interface(jasmine, env); extend(global, jasmineInterface); function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; } return jasmine; }; jasmine-4.0.0/package.json000066400000000000000000000052171416413636100154410ustar00rootroot00000000000000{ "name": "jasmine-core", "license": "MIT", "version": "4.0.0", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" }, "keywords": [ "test", "testing", "jasmine", "tdd", "bdd" ], "scripts": { "posttest": "eslint \"src/**/*.js\" \"spec/**/*.js\" && prettier --check \"src/**/*.js\" \"spec/**/*.js\"", "test": "grunt --stack execSpecsInNode", "cleanup": "prettier --write \"src/**/*.js\" \"spec/**/*.js\"", "build": "grunt buildDistribution", "serve": "node spec/support/localJasmineBrowser.js", "serve:performance": "node spec/support/localJasmineBrowser.js jasmine-browser-performance.json", "ci": "node spec/support/ci.js", "ci:performance": "node spec/support/ci.js jasmine-browser-performance.json" }, "description": "Simple JavaScript testing framework for browsers and node.js", "homepage": "https://jasmine.github.io", "main": "./lib/jasmine-core.js", "files": [ "MIT.LICENSE", "README.md", "images/*.{png,svg}", "lib/**/*.{js,css}", "package.json" ], "devDependencies": { "eslint": "^7.32.0", "eslint-plugin-compat": "^4.0.0", "glob": "^7.2.0", "grunt": "^1.0.4", "grunt-cli": "^1.3.2", "grunt-contrib-compress": "^2.0.0", "grunt-contrib-concat": "^2.0.0", "grunt-css-url-embed": "^1.11.1", "grunt-sass": "^3.0.2", "jasmine": "github:jasmine/jasmine-npm#main", "jasmine-browser-runner": "github:jasmine/jasmine-browser#main", "jsdom": "^19.0.0", "load-grunt-tasks": "^5.1.0", "prettier": "1.17.1", "sass": "^1.45.1", "shelljs": "^0.8.3", "temp": "^0.9.0" }, "prettier": { "singleQuote": true }, "eslintConfig": { "extends": [ "plugin:compat/recommended" ], "env": { "browser": true, "node": true, "es2017": true }, "parserOptions": { "ecmaVersion": 2018 }, "rules": { "quotes": [ "error", "single", { "avoidEscape": true } ], "no-unused-vars": [ "error", { "args": "none" } ], "no-implicit-globals": "error", "block-spacing": "error", "func-call-spacing": [ "error", "never" ], "key-spacing": "error", "no-tabs": "error", "no-trailing-spaces": "error", "no-whitespace-before-property": "error", "semi": [ "error", "always" ], "space-before-blocks": "error" } }, "browserslist": [ "Safari >= 13", "last 2 Chrome versions", "last 2 Firefox versions", "Firefox >= 68", "last 2 Edge versions" ] } jasmine-4.0.0/release_notes/000077500000000000000000000000001416413636100157765ustar00rootroot00000000000000jasmine-4.0.0/release_notes/1.3.0.md000066400000000000000000000014571416413636100167660ustar00rootroot00000000000000# Jasmine Core 1.3.0 Release Notes ## Summary This version was a very incremental release that merged in some pull requests for bug fixes. ## Features * HTML Runner exposes UI to not swallow Exceptions, instead raising as soon as thrown * Migrated homepage content to Wiki * Made a far more useful [tutorial page](http://pivotal.github.com/jasmine) * Added a `toBeNaN` matcher ## Fixes * Better detection of in-browser vs. not * `afterEach` functions will run now even when there is a timeout * `toBeCloseTo` matcher is more accurate * More explicit matcher messages for spies * Better equality comparisons for regular expressions * Improvements to the Pretty Printer: controllable recursion depth, don't include inherited properties * Fix where `for` was being used as a property on an object (failed on IE) jasmine-4.0.0/release_notes/1.3.1.md000066400000000000000000000002441416413636100167600ustar00rootroot00000000000000# Jasmine Core 1.3.1 Release Notes ## Summary This release is for browser compatibility fixes ## Changes ### Features Fixing test runner failures in IE 6/7/8 jasmine-4.0.0/release_notes/2.0.1.md000066400000000000000000000073411416413636100167630ustar00rootroot00000000000000# Jasmine Core 2.0.1 Release Notes ## Summary This release is for small bug fixes and enhancements ahead of a real-soon-now 2.1. ## Changes ### Features * NodeJS is now supported with a jasmine-core npm * [Support browsers that don't supply a `Date.now()` by having a `mockDate` object](http://www.pivotaltracker.com/story/66606132) - Closes #361 * [Show message if no specs where loaded](http://www.pivotaltracker.com/story/12784235) * When using `jasmine.any`, the `class` will now be included in the error message * Reporters now receive the number of passed expectations in a spec * Use default failure message for `toBeNaN` * Use the latest `jasmine_selenium_runner` so we use the fix for printing objects with cycles * Add jasmine logo image to HTML runner * Stop Jasmine's CSS affecting the style of the body tag - Closes #600 * Standardized location of the standalone distributions - they now live in the repo in `/dist` as well as on the Releases page ### Bugs * Don't allow calling the same done callback multiple times - Fixes #523 * [Remove 'empty' as an option as a spec result](http://www.pivotaltracker.com/story/73741032) as this was a breaking change * Instead, we determine if a spec has no expectations using the added key of `passedExpectations` in combination of the `failedExpectations` to determine that there a spec is 'empty' * Fix build in IE8 (IE8 doesn't support `Object.freeze`) * Fix `ObjectContaining` to match recursively ### Documentation * Update release doc to use GitHub releases * Add installation instructions to README - Merges #621 * Add Ruby Gem and Python Egg to docs * Add detailed steps on how to contribute - Merges #580 from @pablofiu ## Pull Requests and Issues * Contains is explicitly false if actual is `undefined` or `null` - Fixes #627 * namespace `html-reporter` -> `jasmine_html-reporter` - Fixes #600 * Throw a more specific error when `expect` is used without a `currentSpec` - Fixes #602 * Reduced size of logo with PNG Gauntlet - Merges #588 * HTML Reporter resets previous DOM when re-initialized - Merges #594 from @plukevdh * Narrow down raise exceptions query selector; Finding by any input tag is a little bit broad - Closes #605 * Pass through custom equality testers in toHaveBeenCalledWith - Fixes #536 * Fix outdated copyright year (update to 2014) - Merges #550 from @slothmonster * [Add package.json to Python egg to get correct version number](http://www.pivotaltracker.com/story/67556148) - Fixes #551 * Allow users to set the maximum length of array that the pretty-printer will print out - Fixes #323 @mikemoraned and #374 @futuraprime * `matchersUtil.equals()` does not expect a matcher as its first argument, so send the "actual" value first and the "expected" value second. - Merges #538 from @cbandy * Add single quote check to `jshint` and fix src files for that - Closes #522 * Remove an `eval` in order to support running jasmine within CSP - Closes #503 * Allow matcher custom failure messages to be a function - Closes #520 * More color blind friendly CSS from @dleppik - Closes #463 & #509 * Use `load-grunt-tasks` Merges #521 from @robinboehm * Special case printing `-0` - Closes #496 * Allow stub or spy Date object safely using a closure to get a clean copy - Closes #506 * [Use `\d7` instead of plain 'x' for more square appearance](http://www.pivotaltracker.com/story/48434179) * Better support in pretty printer when an object has null prototype - Fixes #500 * Update link at top of README to improve access to Jasmine 2.0 docs - Merges #486 from @nextmat * Force query selector to seek within the html-reporter element - Merges #479 from @shprink * Netbeans files are in gitignore - Merges #478 from @shprink ------ _Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.0.2.md000066400000000000000000000013261416413636100167610ustar00rootroot00000000000000# Release Notes ## Summary ## Changes * keep the files for running in a webpage around in the npm package * Expose files and paths necessary to embed jasmine in an html page for nodejs * Pull out the building of the jasmine interface so node and web both get the same one. * Show a dot with color of pending spec when no expectations * Console reporter prints out failed expectation's message ### Bugs * Allow mocked Date constructor to be called with a subset of full params ## Pull Requests and Issues * a disabled suite should call resultCallback with status being disabled * disabled suite should still call onStart callback ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.1.0.md000066400000000000000000000075231416413636100167650ustar00rootroot00000000000000# Jasmine Core 2.1.0 Release Notes ## Summary This is the release of Jasmine 2.1. ## Features - Support for focused specs via `fit` and `fdescribe` - Support for `beforeAll` and `afterAll` - Support for an explicit `fail` function, both in synchronous and asynchronous specs - Allow custom timeout for `beforeEach`, `afterEach`, `beforeAll`, `afterAll` and `it` - Spies now track return values - Specs can now specify their own timeouts - Testing in Node.js via the official Jasmine Node Module - Spec results now have `suiteResults` method that behaves similarly to to `specResults` - HtmlReporter shows error alerts for afterAllExceptions ## Bugs - CI now works for IE8 (this was releated to `ConsoleReporter` below) - Detect global object properly when getting the jasmine require obj - Fixes Issue #[569][issue_569] - [Tracker Story #73684570](http://www.pivotaltracker.com/story/73684570) ## Deprecations ### `ConsoleReporter` as part of Jasmine core The Console Reporter exists nearly entirely for the old manner of running Jasmine's own specs in node.js. As we are now supporting node.js officially, this reporter code no longer needs to be in this repo and instead will be in the Jasmine npm. For now you will see a deprecation message. It will be removed entirely in Jasmine 3.0. ## Documentation - Release Notes from previous releases now live at [Jasmine's GitHub release page][releases]. See Tracker Story #[54582902][tracker_1] - Better instructions for releasing new documentation [releases]: https://github.com/pivotal/jasmine/releases [tracker_1]: http://www.pivotaltracker.com/story/54582902 ## Pull Requests and Issues - Simplification of HTMLtags in SpecRunner.html - Merges #[700][issue_700] from @tkrotoff - `toContain` works with array-like objects (Arguments, HTMLCollections, etc) - Merges #[699][issue_699] from @charleshansen - Fixed isPendingSpecException test title - Merges #[691][issue_691] from @ertrzyiks - Fixed an issue with example code in the npm - Merges #[686][issue_686] from @akoptsov - When the Jasmine clock is installed and date is mocked, `new Date() instanceof Date` should equal `true` Issue #[678][issue_678] & Issue #[679][issue_679] from @chernetsov - Support for an explicit `fail` function, both in synchronous and asynchronous specs - Fixes Issue #[567][issue_567], Issue #[568][issue_568], and Issue #[563][issue_563] - Allow custom timeout for `beforeEach`, `afterEach`, `beforeAll`, `afterAll` and `it` - Fixes Issue #[483][issue_483] - specs can now specify their own timeouts - Spies can track return values - Fixes Issue #[660][issue_660], Merged Issue #[669][issue_669] from @mkhanal - Interval handlers can now clear their interval - Fixes Issue #[655][issue_655] Merged Issue #[658][issue_658] from @tgirardi - Updated to the latest `json2.js` - Merges #[616][issue_616] from @apaladox2015 ------ _Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_ [issue_569]: http://github.com/pivotal/jasmine/issues/569 [issue_700]: http://github.com/pivotal/jasmine/issues/700 [issue_699]: http://github.com/pivotal/jasmine/issues/699 [issue_691]: http://github.com/pivotal/jasmine/issues/691 [issue_678]: http://github.com/pivotal/jasmine/issues/678 [issue_679]: http://github.com/pivotal/jasmine/issues/679 [issue_567]: http://github.com/pivotal/jasmine/issues/567 [issue_568]: http://github.com/pivotal/jasmine/issues/568 [issue_563]: http://github.com/pivotal/jasmine/issues/563 [issue_483]: http://github.com/pivotal/jasmine/issues/483 [issue_660]: http://github.com/pivotal/jasmine/issues/660 [issue_669]: http://github.com/pivotal/jasmine/issues/669 [issue_655]: http://github.com/pivotal/jasmine/issues/655 [issue_658]: http://github.com/pivotal/jasmine/issues/658 [issue_616]: http://github.com/pivotal/jasmine/issues/616 [issue_686]: http://github.com/pivotal/jasmine/issues/686 jasmine-4.0.0/release_notes/2.1.1.md000066400000000000000000000006111416413636100167550ustar00rootroot00000000000000# Jasmine Core 2.1.1 Release Notes ## Summary This is a hotfix release of jasmine core to fix a breaking change with events emitted by the top-level suite ## Issues - Top-level suite triggers suiteStarted and suiteEnd to be consistent - Fixes [#706](http://github.com/pivotal/jasmine/issues/706) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.1.2.md000066400000000000000000000006241416413636100167620ustar00rootroot00000000000000# Jasmine Core 2.1.2 Release Notes ## Summary This is a hotfix release of jasmine core to fix a breaking change with reporting when all of the specs in a suite are pending. ## Changes - Suites still run their children even if none are executable - Fixes [#707](http://github.com/pivotal/jasmine/issues/707) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.1.3.md000066400000000000000000000012521416413636100167610ustar00rootroot00000000000000# Jasmine Core 2.1.3 Release Notes ## Summary This release is primarily a bug-fix release to clean up some recent regressions. ## Pull Requests & Issues * Top level suite no longer reports suiteStart and suiteDone - Fixes [#716](https://github.com/jasmine/jasmine/issues/716) * Don't keep the expected and actual for a passed expectation - Fixes [#640](https://github.com/jasmine/jasmine/issues/640) - Fixes [#690](https://github.com/jasmine/jasmine/issues/690) * Use the new build env on Travis - Merges [#712](https://github.com/jasmine/jasmine/issues/712) from @joshk ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.2.0.md000066400000000000000000000102301416413636100167530ustar00rootroot00000000000000# Jasmine Core 2.2.0 Release Notes ## Changes * `ObjectContaining` no longer tries to track exact mismatches * HTML reporter keeps extra query params when focusing on a spec or suite * Check custom properties on Arrays when computing equality * Better error message if `spyOn` is called without a method name * Rename `jasmineMatches` to `asymmetricMatch` * Don't double escape focus spec links * Jasmine equality checks if either side implements `asymmetricMatch` * Add asymmetric equality tester to match a string with a RegExp * Add jshint to node build on Travis for pull request builds * Restructure node examples directory to look more realistic ## Pull Requests & Issues * Add a basic bower config - Fixes [#719](https://github.com/jasmine/jasmine/issues/719) * Allow `pending` to take a reason and show it in the HtmlReporter - Fixes [#671](https://github.com/jasmine/jasmine/issues/671) * Set jasmineGlobal correctly in GJS - Merges [#757](https://github.com/jasmine/jasmine/issues/757) from @ptomato - Fixes [#751](https://github.com/jasmine/jasmine/issues/751) * Fix some SpiderMonkey lint warnings - Merges [#752](https://github.com/jasmine/jasmine/issues/752) from @ptomato - Fixes [#751](https://github.com/jasmine/jasmine/issues/751) * Prevents *Alls from running when runnables are explicitly set - Fixes [#732](https://github.com/jasmine/jasmine/issues/732) * Update contribution guide to mention possible ffi dependencies for Ubuntu - Fixes [#755](https://github.com/jasmine/jasmine/issues/755) * Fix spelling mistake in contributors guide - Merges [#746](https://github.com/jasmine/jasmine/issues/746) from @swirlycheetah * Use new jasmine github repo url - Merges [#745](https://github.com/jasmine/jasmine/issues/745) rohit * Allow `createSpyObj` to be called with just an array of method names - Fixes [#321](https://github.com/jasmine/jasmine/issues/321) * Add `arrayContaining` matcher - Merges [#440](https://github.com/jasmine/jasmine/issues/440) from @slackersoft * Use the stack trace from the Error object if supplied - Fixes [#734](https://github.com/jasmine/jasmine/issues/734) * Update readme with link to upgrading doc and mention browser support. - Fixes [#739](https://github.com/jasmine/jasmine/issues/739) * Link to the Jasmine NPM module - Merges [#736](https://github.com/jasmine/jasmine/issues/736) from @moonmaster9000 * Allow null prototype objects to be compared for equality - Merges [#731](https://github.com/jasmine/jasmine/issues/731) from @rohit - Fixes [#729](https://github.com/jasmine/jasmine/issues/729) * Fix URL's of Jasmine repositories on Github - Merges [#730](https://github.com/jasmine/jasmine/issues/730) from @rohit * Add `anything` matcher to match any value that is neither null or undefined - Fixes [#186](https://github.com/jasmine/jasmine/issues/186) * Allow asymmetric equality testers to preempt their symmetric brethren - Fixes [#540](https://github.com/jasmine/jasmine/issues/540) * Check for `ObjectContaining` on either side of equality - Fixes [#682](https://github.com/jasmine/jasmine/issues/682) * Display the name of the constructor when pretty printing objects - Fixes [#598](https://github.com/jasmine/jasmine/issues/598) * `toMatch` requires the `expected` to be a String or RegExp - Fixes [#723](https://github.com/jasmine/jasmine/issues/723) * Better equality comparison of Dom nodes - Merges [#657](https://github.com/jasmine/jasmine/issues/657) from @alexeibs * Hide unnecessary files from the npm package - Fixes [#726](https://github.com/jasmine/jasmine/issues/726) * Properly record finishing an `xdescribe` so further cleanup works - Fixes [#724](https://github.com/jasmine/jasmine/issues/724) * Reschedule all functions for a tick before executing any. This allows any function run during a tick to cancel any other in the same tick. - Fixes [#708](https://github.com/jasmine/jasmine/issues/708) * Pass through all args from external interface for befores, afters, its - Fixes [#483](https://github.com/jasmine/jasmine/issues/483) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.2.1.md000066400000000000000000000006341416413636100167630ustar00rootroot00000000000000# Jasmine Core 2.2.1 Release Notes ## Summary This is a hotfix release to fix the packaging for bower ## Changes * Fix missing comma on bower.json - Merges [#763](https://github.com/jasmine/jasmine/issues/763) from @gabrielhpugliese - Merges [#764](https://github.com/jasmine/jasmine/issues/764) from @joshuacc ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.3.0.md000066400000000000000000000071271416413636100167670ustar00rootroot00000000000000# Jasmine Core 2.3.0 Release Notes ## Changes * Style disabled specs in the results list * Use `onclick` directly to better support older webkit * Don't use deprecated `onComplete` syntax for jasmine-npm * Allow the clock to be installed for the duration of a single closure * Add safari 7 & 8 to browser matrix * Remove unused standaloneBuilder var from Gruntfile * Add test script to package.json * Update bower.json keywords to match package.json keywords * Add keywords to package.json * refuse to execute an order if it would cause a suite with a beforeAll or afterAll to be re-entered after leaving once ## Pull Requests & Issues * Specify a main entry point for bower so it can be loaded easier - Merges [#827](https://github.com/jasmine/jasmine/issues/827) from @davetron5000 * Use `instanceof` when checking Error types in toThrowError - Fixes [#819](https://github.com/jasmine/jasmine/issues/819) * Remove periods from bullet points for consistency with rest of document - Merge [#818](https://github.com/jasmine/jasmine/issues/818) from @lpww * Subjective readability improvements to CONTRIBUTING.md - Merge [#815](https://github.com/jasmine/jasmine/issues/815) from @jhamon * Don't install the clock if the current timing functions aren't the originals - Fixes [#782](https://github.com/jasmine/jasmine/issues/782) * Properly pass `j$` to `Any` so it can use other jasmine stuff - Fixes [#806](https://github.com/jasmine/jasmine/issues/806) * Correctly handle functions that are scheduled after the clock is uninstalled and reinstalled from within Clock#tick. - Merges [#804](https://github.com/jasmine/jasmine/issues/804) from @sgravrock - Fixes [#790](https://github.com/jasmine/jasmine/issues/790). * Allow user to stop a specs execution when an expectation fails - Fixes [#577](https://github.com/jasmine/jasmine/issues/577) * Remove unnecessary conditional - Merges [#788](https://github.com/jasmine/jasmine/issues/788) from @toddbranch * Show the name of the constructor function when printing an `any` instead of a `toString` of the entire constructor - Fixes [#796](https://github.com/jasmine/jasmine/issues/796) * Don't use hardcoded temporary directory paths - Merges [#789](https://github.com/jasmine/jasmine/issues/789) from sgravrock * Execute beforeAll/afterAll once per suite instead of once per child when running focused specs/suites - Fixes [#773](https://github.com/jasmine/jasmine/issues/773) * Report children of an xdescribe similarly to how they would be reported if they were themselves x'd out - Fixes [#774](https://github.com/jasmine/jasmine/issues/774) - Fixes [#776](https://github.com/jasmine/jasmine/issues/776) * Fixes issue where mock clock was being used by QueueRunner - Fixes [#783](https://github.com/jasmine/jasmine/issues/783) - Fixes [#792](https://github.com/jasmine/jasmine/issues/792) * add missing semicolon - Merges [#775](https://github.com/jasmine/jasmine/issues/775) from @joscha * ObjectContaining matches prototype properties - Fixes [#769](https://github.com/jasmine/jasmine/issues/769) * Updates pretty printer to include array properties - Fixes [#766](https://github.com/jasmine/jasmine/issues/766) * Update year copyright - Merges [#768](https://github.com/jasmine/jasmine/issues/768) from @danilovaz * Allow arrays from different frames or contexts to be equal - Merges [#767](https://github.com/jasmine/jasmine/issues/767) from @juliemr - Fixes [#765](https://github.com/jasmine/jasmine/issues/765) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.3.1.md000066400000000000000000000005451416413636100167650ustar00rootroot00000000000000# Jasmine 2.3.1 Release Notes ## Summary This release is a packaging update for bower only. ## Pull Requests & Issues * Point Bower's main field to jasmine.js, which is browser-friendly. - Merge [#843](https://github.com/jasmine/jasmine/issues/843) from @evoL ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.3.2.md000066400000000000000000000006031416413636100167610ustar00rootroot00000000000000# Jasmine 2.3.2 Release Notes ## Summary This is a hotfix release to fix a regression with specs declared without a function body ## Pull Requests & Issues * A spec without a function provided should be `pending` not `disabled` - Fixes [#840](https://github.com/jasmine/jasmine/issues/840) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.3.3.md000066400000000000000000000006051416413636100167640ustar00rootroot00000000000000# Jasmine 2.3.3 Release Notes ## Summary This is a hotfix release to fix a regression with the execution context for `beforeAll` ## Pull Requests & Issues * Set the shared user context correctly when executing the top level suite - Fixes [#846](https://github.com/jasmine/jasmine/issues/846) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.3.4.md000066400000000000000000000014001416413636100167570ustar00rootroot00000000000000# Jasmine 2.3.4 Release Notes ## Summary This is a hotfix release to fix a regression with execution ordering ## Pull Requests & Issues * Fix ordering for suites with more than 11 direct children. - Fixes [#850](https://github.com/jasmine/jasmine/issues/850) * Update standalone installation instructions to reference the releases page - Fixes [#603](https://github.com/jasmine/jasmine/issues/603) * Remove dead CSS class styles - Merges [#849](https://github.com/jasmine/jasmine/issues/849) from @prather-mcs - Merges [#848](https://github.com/jasmine/jasmine/issues/848) from @prather-mcs - Fixes [#847](https://github.com/jasmine/jasmine/issues/847) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.4.0.md000066400000000000000000000074371416413636100167740ustar00rootroot00000000000000# Jasmine Core 2.4.0 Release Notes ## Summary This release contains a number of fixes and pull requests. The most notable is probably that Jasmine now supports randomization of spec order ## Changes * Run jasmine's specs in random order * Add support for returning run details for reporting randomness * Use className instead of class when creating DOM elements ## Pull Requests & Issues * Syntax highlighting in README.md - Merges [#973](https://github.com/jasmine/jasmine/issues/973) from @brunoqc * Added a throw error block in describe incase a function with arguments is passed in describe - Fixes [#896](https://github.com/jasmine/jasmine/issues/896) - Merges [#955](https://github.com/jasmine/jasmine/issues/955) from @himajasuman * Remove unused `queueableFn` arg from `onException` - Fixes [#958](https://github.com/jasmine/jasmine/issues/958) * Remove unused parameter from toThrowError - Merges [#957](https://github.com/jasmine/jasmine/issues/957) from @FuzzySockets * Abort spying when the target cannot be spied upon - Fixes [#948](https://github.com/jasmine/jasmine/issues/948) - Merges [#949](https://github.com/jasmine/jasmine/issues/949) from @StephanBijzitter * Removed GOALS_2.0.md, doesn't seem to be needed anymore - Merges [#954](https://github.com/jasmine/jasmine/issues/954) from @matthewhuff89 * Change #xit so that it will output a more BDD-style pending message - Merges [#942](https://github.com/jasmine/jasmine/issues/942) from @lalunamel - Fixes [#930](https://github.com/jasmine/jasmine/issues/930) - Fixes [#912](https://github.com/jasmine/jasmine/issues/912) * Allow tests to run in random order - Merges [#927](https://github.com/jasmine/jasmine/issues/927) from @marcioj * Use toString for objects if it has been overriden - Merges [#929](https://github.com/jasmine/jasmine/issues/929) from @myitcv - Fixes [#928](https://github.com/jasmine/jasmine/issues/928) * Fix circles/x from getting cut off on Mac/chrome - Merges [#932](https://github.com/jasmine/jasmine/issues/932) from @James-Dunn * Postpone find() until it is needed - Merges [#924](https://github.com/jasmine/jasmine/issues/924) from @danielalexiuc - Fixes [#917](https://github.com/jasmine/jasmine/issues/917) * check for global before assigning * Reverse suite afterEach behavior to match semantics? - Merges [#908](https://github.com/jasmine/jasmine/issues/908) from @mcamac * Use badges from shields.io - Merges [#902](https://github.com/jasmine/jasmine/issues/902) from @SimenB * xdescribe marks pending, plus associated tests. - Merges [#869](https://github.com/jasmine/jasmine/issues/869) from @ljwall - Fixes [#855](https://github.com/jasmine/jasmine/issues/855) * Update glob to latest - Merge [#892](https://github.com/jasmine/jasmine/issues/892) from @obastemur - Fixes [#891](https://github.com/jasmine/jasmine/issues/891) * Remove moot `version` property from bower.json - Merges [#874](https://github.com/jasmine/jasmine/issues/874) from @kkirsche * add toHaveBeenCalledTimes matcher - Merges [#871](https://github.com/jasmine/jasmine/issues/871) from @logankd - Fixes [#853](https://github.com/jasmine/jasmine/issues/853) * Update CONTRIBUTING.md - Merges [#856](https://github.com/jasmine/jasmine/issues/856) from @lpww * Make the HtmlReport CSS classes "unique enough" - Merges [#851](https://github.com/jasmine/jasmine/issues/851) from @prather-mcs - Fixes [#844](https://github.com/jasmine/jasmine/issues/844) * Raise an error when jasmine.any() isn't passed a constructor - Merges [#854](https://github.com/jasmine/jasmine/issues/854) from @danfinnie - Fixes [#852](https://github.com/jasmine/jasmine/issues/852) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.4.1.md000066400000000000000000000004041416413636100167600ustar00rootroot00000000000000# Jasmine Core 2.4.1 Release Notes ## Changes * Run `afterEach` in reverse order declared as before - Reverts [#908](https://github.com/jasmine/jasmine/issues/908) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.5.0.md000066400000000000000000000117421416413636100167670ustar00rootroot00000000000000# Jasmine 2.5.0 Release Notes ## Summary This release contains a number of fixes and pull requests. ## Changes * Rename `j$` to `jasmineUnderTest` for specs - Please update any pull requests to simplify merging, thanks. ## Pull Requests & Issues * Prettyprint objects whose constructors have custom toString method - Fixes [#1019](https://github.com/jasmine/jasmine/issues/1019) - Merges [#1099](https://github.com/jasmine/jasmine/issues/1099) from @mbildner * Add gulp-jasmine-browser link to readme - Fixes [#1089](https://github.com/jasmine/jasmine/issues/1089) * Exclude lib directory from codeclimate - Fixes [#1171](https://github.com/jasmine/jasmine/issues/1171) * Add instructions for testing in IE - Merges [#1170](https://github.com/jasmine/jasmine/issues/1170) from @benchristel * Update devDependencies and fix issues from this - Merges [#1162](https://github.com/jasmine/jasmine/issues/1162) from @amavisca * Remove runnableLookupTable which is no longer used - Merges [#1129](https://github.com/jasmine/jasmine/issues/1129) from @gregeninfrank * Make `toEqual` pass for arrays with equivalent properties - Merges [#1155](https://github.com/jasmine/jasmine/issues/1155) from @benchristel * Update ruby version on travis to let rack install - Merges [#1152](https://github.com/jasmine/jasmine/issues/1152) from @amavisca * Fix jasmine setup in Electron environment - Merges [#1079](https://github.com/jasmine/jasmine/issues/1079) from @skupr - Fixes [#964](https://github.com/jasmine/jasmine/issues/964) * Improve errors with the domain and how to use the API - Merges [#1026](https://github.com/jasmine/jasmine/issues/1026) from @dhoko - Fixes [#1025](https://github.com/jasmine/jasmine/issues/1025) * The done function now returns null - Merges [#1062](https://github.com/jasmine/jasmine/issues/1062) from @marneborn - Fixes [#992](https://github.com/jasmine/jasmine/issues/992) * Add .editorconfig file - Merges [#1058](https://github.com/jasmine/jasmine/issues/1058) from @kapke - Fixes [#1057](https://github.com/jasmine/jasmine/issues/1057) * Improve error message when passing a non-function to callFake - Merges [#1059](https://github.com/jasmine/jasmine/issues/1059) from @kapke - Fixes [#1016](https://github.com/jasmine/jasmine/issues/1016) * Allow expectations in a global beforeAll or afterAll - Fixes [#811](https://github.com/jasmine/jasmine/issues/811) * Correctly tear down spies on inherited methods - Merges [#1036](https://github.com/jasmine/jasmine/issues/1036) from @benchristel - Fixes [#737](https://github.com/jasmine/jasmine/issues/737) * Array equality treats undefined elements as equal however they got in there - Fixes [#786](https://github.com/jasmine/jasmine/issues/786) * Add support for a fallback reporter - Merges [#1009](https://github.com/jasmine/jasmine/issues/1009) from @mauricioborges * Grunt task for compass should prefix command with 'bundle exec' - Merges [#1047](https://github.com/jasmine/jasmine/issues/1047) from @d-reinhold * Fix `toEqual` for Microsoft Edge - Merges [#1041](https://github.com/jasmine/jasmine/issues/1041) from @everedifice * Update describe error message to no longer assume errant args are `done` - Fixes [#896](https://github.com/jasmine/jasmine/issues/896) * Add toBeGreatThanOrEqual and toBeLessThanOrEqual matchers - Merges [#1049](https://github.com/jasmine/jasmine/issues/1049) from @rullopat - Fixes [#1013](https://github.com/jasmine/jasmine/issues/1013) * Support call count of 0 with toHaveBeenCalledTimes matcher - Merges [#1048](https://github.com/jasmine/jasmine/issues/1048) from @logankd - Fixes [#994](https://github.com/jasmine/jasmine/issues/994) * Correctly clean up spies after a spy is replaced and re-spied upon - Merges [#1011](https://github.com/jasmine/jasmine/issues/1011) from @bodawei - Fixes [#1010](https://github.com/jasmine/jasmine/issues/1010) * remove extra topSuite `queueRunner` construction parameter - Merges [#1006](https://github.com/jasmine/jasmine/issues/1006) from @jurko-gospodnetic * add option to shallow clone args in call tracker - Merges [#1000](https://github.com/jasmine/jasmine/issues/1000) from @a-r-d - Fixes [#872](https://github.com/jasmine/jasmine/issues/872) * Update license year range to 2016 - Merges [#1021](https://github.com/jasmine/jasmine/issues/1021) from pra85 * Persist randomize param in 'run all' links - Merges [#990](https://github.com/jasmine/jasmine/issues/990) from @basawyer * make DelayedFunctionScheduler update the mockDate - Fixes [#915](https://github.com/jasmine/jasmine/issues/915) - Merges [#980](https://github.com/jasmine/jasmine/issues/980) from @andrewiggings * Allow `spyOn` to allow a respy for functions that have already been spied upon - Merges [#953](https://github.com/jasmine/jasmine/issues/953) from @guy-mograbi-at-gigaspaces - Fixes [#931](https://github.com/jasmine/jasmine/issues/931) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.5.1.md000066400000000000000000000012171416413636100167640ustar00rootroot00000000000000# Jasmine 2.5.1 Release Notes ## Pull Requests & Issues * fallback on assignment when a spy cannot be deleted - Merges [#1193](https://github.com/jasmine/jasmine/issues/1193) from @seanparmlee - Fixes [#1189](https://github.com/jasmine/jasmine/issues/1189) * Fix issue with equality of Arrays in PhantomJS - Merges [#1192](https://github.com/jasmine/jasmine/issues/1192) from @logankd - Fixes [#1188](https://github.com/jasmine/jasmine/issues/1188) * Properly tick date along with clock - Fixes [#1190](https://github.com/jasmine/jasmine/issues/1190) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.5.2.md000066400000000000000000000006261416413636100167700ustar00rootroot00000000000000# Jasmine 2.5.2 Release Notes ## Pull Requests & Issues * Allow currently registered reporters to be cleared - [jasmine/jasmine-npm#88](https://github.com/jasmine/jasmine-npm/issues/88) * Use `isFunction` to check for functionness in `callFake` - Fixes [#1191](https://github.com/jasmine/jasmine/issues/1191) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.6.0.md000066400000000000000000000115371416413636100167720ustar00rootroot00000000000000# Jasmine 2.6.0 Release Notes ## Summary This release contains a number of fixes and pull requests. ## Pull Requests & Issues Updating introduction url to last version - Merges [#1316](https://github.com/jasmine/jasmine/issues/1316) from @rachelcarmena * Throw a recognizable Error message when `fail` outside of a spec. - Fixes [#1017](https://github.com/jasmine/jasmine/issues/1017) * Allow the matcher provide a custom error message - Merges [#1298](https://github.com/jasmine/jasmine/issues/1298) from @deckar01 - Fixes [#1123](https://github.com/jasmine/jasmine/issues/1123) * Fix the order in which afterAll hooks are run to match afterEach - Merges [#1312](https://github.com/jasmine/jasmine/issues/1312) from @gdborton - Fixes [#1311](https://github.com/jasmine/jasmine/issues/1311) * Add matchers for positive and negative infinity - Merges [#1300](https://github.com/jasmine/jasmine/issues/1300) from @toubou91 - Fixes [#1294](https://github.com/jasmine/jasmine/issues/1294) * Add a first pass at JSDocs for the intended public API - Fixes [#596](https://github.com/jasmine/jasmine/issues/596) * Pretty print objects passed to fail method - Merges [#1283](https://github.com/jasmine/jasmine/issues/1283) from @mmmichl - Fixes [#1090](https://github.com/jasmine/jasmine/issues/1090) * Properly check for Error constructor from a different frame - Merges [#1275](https://github.com/jasmine/jasmine/issues/1275) from @anseki - Fixes [#1252](https://github.com/jasmine/jasmine/issues/1252) * Add toHaveBeenCalledBefore matcher - Merges [#1242](https://github.com/jasmine/jasmine/issues/1242) from @DamienCassou * Collect unhandled exceptions and pass them to the current runnable - Fixes [#529](https://github.com/jasmine/jasmine/issues/529) - Fixes [#937](https://github.com/jasmine/jasmine/issues/937) * Nicer error messages for `spyOn` when `null` is provided - Fixes [#1258](https://github.com/jasmine/jasmine/issues/1258) * Require arguments to beforeEach, it, etc, to be actual functions - Merges [#1222](https://github.com/jasmine/jasmine/issues/1222) from @voithos - Fixes [#1004](https://github.com/jasmine/jasmine/issues/1004) * Update MIT.LICENSE for new year - Merges [#1249](https://github.com/jasmine/jasmine/issues/1249) from @Scottkao85 * Update README.md for new year - Merges [#1248](https://github.com/jasmine/jasmine/issues/1248) from @Nebojsaa * Remove unused `message` param from Suite#pend - See [#1132](https://github.com/jasmine/jasmine/issues/1132) * Fix bug where before/afterAll were being executed in disabled suites. - Merges [#1225](https://github.com/jasmine/jasmine/issues/1225) from @voithos - Fixes [#1175](https://github.com/jasmine/jasmine/issues/1175) * Make toEqual matcher report the difference between objects - Merges [#1163](https://github.com/jasmine/jasmine/issues/1163) from @benchristel - Fixes [#675](https://github.com/jasmine/jasmine/issues/675) - Merges [#1236](https://github.com/jasmine/jasmine/issues/1236) from @benchristel * Implement spies for get/set functions on accessor properties - Merges [#1203](https://github.com/jasmine/jasmine/issues/1203) from @celluj34 - Merges [#1008](https://github.com/jasmine/jasmine/issues/1008) from @smacker - Fixes [#943](https://github.com/jasmine/jasmine/issues/943) * When the HtmlReporter has a 'spec' query param, the spec list only shows matching specs/suites - Merges [#1046](https://github.com/jasmine/jasmine/issues/1046) from @d-reinhold - Fixes [#510](https://github.com/jasmine/jasmine/issues/510) * createSpyObj may use object for method/response shorthand - Merges [#1101](https://github.com/jasmine/jasmine/issues/1101) from @mbildner * Separate clear stack and run it after each spec - Fixes [#985](https://github.com/jasmine/jasmine/issues/985) - Fixes [#945](https://github.com/jasmine/jasmine/issues/945) - Fixes [#366](https://github.com/jasmine/jasmine/issues/366) * Now spies preserve original function arity - Merges [#1055](https://github.com/jasmine/jasmine/issues/1055) from @kapke - Fixes [#991](https://github.com/jasmine/jasmine/issues/991) * Added support for ES6 sets to toContain and toEqual. - Merges [#1067](https://github.com/jasmine/jasmine/issues/1067) from @alur * Correctly pretty print objects from other contexts (e.g. iframes) and which do not override toString - Merges [#1091](https://github.com/jasmine/jasmine/issues/1091) from @thatfulvioguy - Fixes [#1087](https://github.com/jasmine/jasmine/issues/1087) * Pass custom testers to asymmetric testers - Merges [#1139](https://github.com/jasmine/jasmine/issues/1139) from @joeyparrish - Fixes [#1138](https://github.com/jasmine/jasmine/issues/1138) * Fix bad url in README - Merges [#1215](https://github.com/jasmine/jasmine/issues/1215) from @mattc41190 ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.6.1.md000066400000000000000000000013141416413636100167630ustar00rootroot00000000000000# Jasmine 2.6.1 Release Notes ## Summary This is a patch release to fix some regressions in the 2.6.0 release ## Pull Requests & Issues * Update README.md to make installation instructions more version-agnostic - Merges #1319 from @reinrl * Check for `process.listeners` as well, for GlobalErrors - Fixes #1333 * allow explicit undefined as function for `it` and `xit` - Merges #1329 from @UziTech - Fixes #1328 * remove eval to create spy wrapper - Merges #1330 from @UziTech - Fixes #1325 * iterate through keys with a regular for loop - Merges #1326 from @seanparmelee - Fixes #1321 - Fixes #1324 ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.6.2.md000066400000000000000000000011461416413636100167670ustar00rootroot00000000000000# Jasmine 2.6.2 Release Notes ## Summary This is a patch release to fix some regressions and performance problems in the 2.6.0 release ## Changes * Clear the stack if onmessage is called before the previous invocation finishes - Fixes #1327 - Fixes jasmine/gulp-jasmine-browser#48 * Correctly route errors that occur while a QueueRunner is clearing stack - Merges #1352 from @sgravrock - Fixes #1344 - Fixes #1349 * Don't mask errors that occur when no handlers are installed - Merges #1347 from @sgravrock ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.6.3.md000066400000000000000000000010231416413636100167620ustar00rootroot00000000000000# Jasmine 2.6.3 Release Notes ## Summary This is a patch release to fix some regressions and performance problems in the 2.6.0 release ## Changes * Make sure the queue runner goes async for async specs - Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327) - Fixes [#1334](https://github.com/jasmine/jasmine/issues/1334) - Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.6.4.md000066400000000000000000000011201416413636100167610ustar00rootroot00000000000000# Jasmine 2.6.4 Release Notes ## Summary This is a patch release to fix some regressions and performance problems in the 2.6.0 release ## Changes * Break into a `setTimeout` every once in a while allowing the CPU to run other things that used the real `setTimeout` - Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327) - See [#1334](https://github.com/jasmine/jasmine/issues/1334) - Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.7.0.md000066400000000000000000000053431416413636100167710ustar00rootroot00000000000000# Jasmine 2.7.0 Release Notes ## Summary This release contains a number of fixes and pull requests. ## Pull Requests & Issues * Add class UserContext - Merges [#1400](https://github.com/jasmine/jasmine/issues/1400) from @darthjee * Send unfocused tests through the same queue as focused tests - Merges [#1399](https://github.com/jasmine/jasmine/issues/1399) from @jberney * PrettyPrinter allows an object to have a `toString` that isn't a function - Fixes [#1389](https://github.com/jasmine/jasmine/issues/1389) * Fix rounding in toBeCloseTo - Fixes [#1382](https://github.com/jasmine/jasmine/issues/1382) * When stop on failure is enabled, skip subsequent it() and beforeEach(). Note: afterEach() functions are still run, because skipping them is highly likely to pollute specs that run after the failure. - Fixes [#577](https://github.com/jasmine/jasmine/issues/577) - Fixes [#807](https://github.com/jasmine/jasmine/issues/807) * Only clear out the `spec` param for Run all link - Fixes [#1369](https://github.com/jasmine/jasmine/issues/1369) * Pretty printer will now use MAX_PRETTY_PRINT_ARRAY_LENGTH for objects - Fixes [#1291](https://github.com/jasmine/jasmine/issues/1291) - Fixes [#1360](https://github.com/jasmine/jasmine/issues/1360) * updated package glob from 7.0.5 to 7.1.2 - Merges [#1368](https://github.com/jasmine/jasmine/issues/1368) from @EsrefDurna * Fix bower.json url to be https instead of http - Merges [#1365](https://github.com/jasmine/jasmine/issues/1365) from @kant * Fail when one of the arguments passed into toBeCloseTo matcher is null - Merges [#1362](https://github.com/jasmine/jasmine/issues/1362) from @beatrichartz * Fixed HTML snippet in README - Closes [#1366](https://github.com/jasmine/jasmine/issues/1366). * Report the random seed at the beginning and end of execution. This allows reporters to provide the seed to the user even in cases where Jasmine crashes before completing. - Merges [#1348](https://github.com/jasmine/jasmine/issues/1348) from @sgravrock * Add ES6 map support to Jasmine - Merges [#1340](https://github.com/jasmine/jasmine/issues/1340) from @rmehlinger - Fixes [#1257](https://github.com/jasmine/jasmine/issues/1257) * Added support for async before/it/after functions that return promises and added support for ES2017 async functions - Merges [#1356](https://github.com/jasmine/jasmine/issues/1356) from @sgravrock - Fixes [#1336](https://github.com/jasmine/jasmine/issues/1336) - Fixes [#1270](https://github.com/jasmine/jasmine/issues/1270) - Fixes [#1350](https://github.com/jasmine/jasmine/issues/1350) - Fixes [#1320](https://github.com/jasmine/jasmine/issues/1320) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.8.0.md000066400000000000000000000034321416413636100167670ustar00rootroot00000000000000# Jasmine 2.8.0 Release Notes ## Summary This release contains a number of fixes and pull requests. 2.8 should be the last 2.x release of Jasmine, as we aim for 3.0. ## Changes * Create CODE_OF_CONDUCT.md * Add jsdocs for reporter events * Update jsApiReporter docs to link to new suite and spec results * Add explicit docs for the callback function passed to `it` etc. * Update afterAll documentation ## Pull Requests & Issues * Add 'nothing' matcher and tests - Merges [#1412](https://github.com/jasmine/jasmine/issues/1412) from @ksvitkovsky - Fixes [#1221](https://github.com/jasmine/jasmine/issues/1221) * Make toEqual matcher report the difference between array elements when arrays have different length - Closes [#1375](https://github.com/jasmine/jasmine/issues/1375) from @kiewic * Add arrayWithExactContents asymmetric matcher - Fixes [#817](https://github.com/jasmine/jasmine/issues/817) * Ensure no message added on asym. match success - Closes [#1408](https://github.com/jasmine/jasmine/issues/1408) from @ksvitkovsky - Fixes [#1388](https://github.com/jasmine/jasmine/issues/1388) * Better primitives detection for saveArgsByValue - Closes [#1407](https://github.com/jasmine/jasmine/issues/1407) from @ksvitkovsky - Fixes [#1403](https://github.com/jasmine/jasmine/issues/1403) * Better pretty printing for typed arrays - Closes [#1404](https://github.com/jasmine/jasmine/issues/1404) from @ksvitkovsky - Fixes [#1180](https://github.com/jasmine/jasmine/issues/1180) * Rewrite ES6 Set and Map comparison to ignore insertion order - Merges [#1406](https://github.com/jasmine/jasmine/issues/1406) from @theefer - Fixes [#1402](https://github.com/jasmine/jasmine/issues/1402) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.9.0.md000066400000000000000000000070121416413636100167660ustar00rootroot00000000000000# Jasmine 2.9 Release Notes ## Summary This release contains a number of fixes and pull requests. ## Changes * Fixed DelayedFunctionScheduler IE 8 compatibility issue * Fixed SPEC HAS NO EXPECTATIONS warning in HTML reporter * Correctly remove spies of window.onerror on IE * Truncate pretty printer output that is more than j$.MAX_PRETTY_PRINT_CHARS long * Reduced pretty printer limits to much smaller values * Update contributing for new naming of `jasmineUnderTest` * Allowed async functions to be passed into spy#callFake ## Pull Requests & Issues * Added complete support for Set also for IE11. - Merges [#1478](https://github.com/jasmine/jasmine/issues/1478) from @Volox - Fixes [#1355](https://github.com/jasmine/jasmine/issues/1355) * Added complete support for Map also for IE11. - Merges [#1477](https://github.com/jasmine/jasmine/issues/1477) from @Volox - Fixes [#1472](https://github.com/jasmine/jasmine/issues/1472) * Use timeout objects when in node - Merges [#1470](https://github.com/jasmine/jasmine/issues/1470) from @chris--young - Fixes [#1469](https://github.com/jasmine/jasmine/issues/1469) * Fixed `pending()` for `async`/promise-returning specs - Fixes [#1449](https://github.com/jasmine/jasmine/issues/1449) - Fixes [#1450](https://github.com/jasmine/jasmine/issues/1450) * Added test steps for other major node versions - Merges [#1448](https://github.com/jasmine/jasmine/issues/1448) from @mrlannigan * Fix equality computation for ES6 Sets. - Merges [#1445](https://github.com/jasmine/jasmine/issues/1445) from @b-3-n - Fixes [#1444](https://github.com/jasmine/jasmine/issues/1444) * Add instruction to sync local master with upstream - Merges [#1440](https://github.com/jasmine/jasmine/issues/1440) from aaronang * Add some unit tests that exercise jasmine.anything() and Map matching. - Merges [#1437](https://github.com/jasmine/jasmine/issues/1437) from @voithos * Add special handling of asymmetric matcher objects as keys in Maps. - Merges [#1436](https://github.com/jasmine/jasmine/issues/1436) from @voithos - Fixes [#1432](https://github.com/jasmine/jasmine/issues/1432) * Add support for jasmine.any(Symbol). - Merge [#1435](https://github.com/jasmine/jasmine/issues/1435) from @voithos - Fixes [#1431](https://github.com/jasmine/jasmine/issues/1431) * Throw an error for invalid nesting of a suite functions - Merges [#1411](https://github.com/jasmine/jasmine/issues/1411) from @ksvitkovsky - Fixes [#1295](https://github.com/jasmine/jasmine/issues/1295) * Deep clone args before passing them to reporters - Merges [#1424](https://github.com/jasmine/jasmine/issues/1424) from @aj-dev * Fix "Before Committing" section of CONTRIBUTING.md. - Merges [#1429](https://github.com/jasmine/jasmine/issues/1429) from @voithos * Fix lint warning in CallTracker. - Merges [#1428](https://github.com/jasmine/jasmine/issues/1428) from @voithos * clearTimeout should now correctly clear a timeout that is also scheduled to run at the same tick. - Merges [#1427](https://github.com/jasmine/jasmine/issues/1427) from @leahciMic - Fixes [#1426](https://github.com/jasmine/jasmine/issues/1426) * Add a note about `defineProperty` for `spyOnProperty` - Fixes [#1415](https://github.com/jasmine/jasmine/issues/1415) * Add Promise checking to eq - Merges [#1386](https://github.com/jasmine/jasmine/issues/1386) from @sderickson - Fixes [#1314](https://github.com/jasmine/jasmine/issues/1314) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.9.1.md000066400000000000000000000004701416413636100167700ustar00rootroot00000000000000# Jasmine Core 2.9.1 Release Notes ## Summary This is a hotfix release to fix a breaking change from the 2.9.0 release ## Changes * Clear timeouts when starting to process a milli instead of at the end - Fixes #1482 ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/2.99.md000066400000000000000000000015231416413636100167220ustar00rootroot00000000000000# Jasmine-Core 2.99 Release Notes ## Summary This release is part of the upgrade path to Jasmine 3.0. It deprecates some functionality that will change. ## Changes * Add ability to report deprecation warnings from within the suite and display them in the HTML reporter * Add deprecation messages for things that will change/break in 3.0 * * done for async functionality will now add a failure if it is invoked with an Error * * Env.catchExceptions and the query param are going away, in favor of a more fully functional fail fast handler * * jasmine.Any(Object) will no longer match null * * Unhandled errors during suite load will be caught and reported as failures by Jasmine * * Calling execute more than once on the same spec will definitely fail in 3.0 ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/20.md000066400000000000000000000267371416413636100165600ustar00rootroot00000000000000# Jasmine Core 2.0 Release Notes ## Summary These notes are for Jasmine Core 2.0. ## Breaking Changes The [`introduction.js`][intro] page covers the current syntax, highlighting the changes. Here are the known interface changes that are not backwards compatible with 1.x. * New syntax for asynchronous specs * New syntax for spies * New interface for reporters * Better Equality testing * Replaced custom matchers for ease of use * Change to `toThrow` matcher * Clock now remains installed when a spec finishes * More Jasmine internal variables/functions have been moved into closures ### New syntax for asynchronous specs Similar to [Mocha][mocha], Jasmine `before`s, `spec`s, and `after`s can take an optional `done` callback in order to force asynchronous tests. The next function, whether it's a `before`, `spec` or `after`, will wait until this function is called or until a timeout is reached. ### New syntax for spies Spies have a slightly modified syntax. The idea came from a desire to preserve any of the properties on a spied-upon function and some better testing patterns. ### New interface for reporters The reporter interface has been **replaced**. The callbacks are different and more consistent. The objects passed in should only provide what is needed to report results. This enforces an interface to result data so custom reporters will be less coupled to the Jasmine implementation. The Jasmine reporter API now includes a slot for a `timer` object. ### Better Equality testing We removed the previous equality code and are now using new code for testing equality. We started with [Underscore.js][underscore]'s `isEqual`, refactored a bit and added some additional tests. ### Replaced custom matchers for ease of use The interface for adding custom matchers has been **replaced**. It has always been possible to add custom matchers, but the API was barely documented and difficult to test. We've changed how matchers are added and tested. Jasmine adds its own matchers by the same mechanism that custom matchers use. Dogfooding FTW. ### Change to `toThrow` matcher We've changed the behavior of the `toThrow` matcher, moving some functionality to the `toThrowError` matcher. This should allow more of the requested use cases. ### Clock now remains installed when a spec finishes After installing the Jasmine Clock, it will stay installed until `uninstall` is called -- clearing up any ambiguity for when those timing functions will revert to using the global clock object. ## More Jasmine internal variables/functions have been moved into closures Certain variables/functions like a function to get the next spec id have been moved into closures, making the Jasmine interface cleaner. ## Other Changes * Massive refactoring and better testing * Environment setup now in `boot.js` * Development and Build moved to Grunt * Changes to how Jasmine is loaded * Changes to how Jasmine is tested * Better node.js support * Better Continuous Integration Environment at Travis * Support matrix updated * Removed JsDoc Pages * Adding Code Climate for JavaScript ## Massive refactoring and better testing This is the biggest set of changes. We've touched nearly every file and every object. We've merged objects together and factored out code. We styled the code more consistently. We've improved nearly every test. In general, Jasmine is made of smaller, more-loosely-coupled objects, unit-tested with explicit dependencies injected. This made tests easier to read, write, and maintain. We know this has made Jasmine development easier for the core team. We expect (and hope) this makes it easier for the community to extend Jasmine and provide pull requests that make more sense the first time out. ## Environment setup now in `boot.js` Instantiation and setup of the Jasmine environment, including building reporters, exposing the "global" functions, and executing tests has moved into its own file: `boot.js`. This should make it easier to add custom reporters, configure some objects, or just in general change how you use Jasmine from the outside. For example, during development, Jasmine uses its own `devboot.js` to load itself twice - once from `jasmine.js` and once from the source directories. ## Development and Build moved to Grunt We've moved away from Ruby and embraced [Node.js][node] and [Grunt.js][grunt] for the various command line tasks during development. Yes, it's a just a different set of dependencies. But it's less code for the team to maintain - it turns out that JavaScript tools are pretty good at building JavaScript projects. This will make it easier for the community to make sure contributions work in browsers and in Node.js before submitting Pull Requests. There is more detail in the [Contributor's Guide][contrib]. ## Changes to how Jasmine is loaded We did not want to add new run-time dependencies, yet we needed to be cleaner when loading Jasmine. So we wrote a custom "require" scheme that works in Node.js and in browsers. This only affects pull requests which add files - please be careful in these cases. Again, the [Contributor's Guide][contrib] should help. ## Changes to how Jasmine is tested with Jasmine Writing a custom require system helped enforce self-testing - the built `jasmine.js` testing Jasmine from the source directories. Overall this has improved the stability of the code. When you look at Jasmine's tests, you'll see both `jasmine` and `j$` used. The former, `jasmine`, will always be used to test the code from source, which is loaded into the reference `j$`. Please adhere to this pattern when writing tests for contributions. ## Better node.js support `Node.js` is now officially a first-class citizen. For a long time we've made sure tests were green in Node before releasing. But it is now officially part of Jasmine's CI build at [Travis][travis]. For the curious, the [`node_suite.js`][node_suite], is essentially a `boot.js` for Node. An official `npm` is coming. ## Better Continuous Integration Environment at Travis The [CI build at Travis][travis_jasmine] now runs the core specs in a build matrix across browsers. It's far from complete on the operating system matrix, but you will see that Jasmine runs against: Firefox, Chrome, Safari 5, Safari 6, [Phantom.js][phantom], [Node.js][node], and IE versions 8, 9, and 10. Big thanks to [SauceLabs][sauce] for their support of open source projects. We will happily take pull requests for additional OS/Browser combos within the matrix. ## Support Matrix Updated We're dropping support for IE < 8. [Jasmine 1.x][jasmine_downloads] remains for projects that need to support older browsers. ## Removed JsDoc Pages Comments in code are lies waiting to happen. Jasmine's JsDoc comments were no exception. The comments were out of date, the generated pages were even more out of date, and frankly they were not helpful. So they're gone. Last year saw the posting of the [`introduction.js`][intro] page to document the real, practical interface for projects to use. This page has received a lot of positive feedback so expect more pages like this one. ## Adding Code Climate for JavaScript We are running Code Climate for Jasmine. We have some work to do here but it's helping us easily find code hotspots. ## Pull Requests and Issues The following Pull Requests were merged: * ObjectContaining wrong filed value error message #[394](https://github.com/pivotal/jasmine/issues/394) from albertandrejev * Removed unnecessary parameter from `suiteFactory()` call #[397](https://github.com/pivotal/jasmine/issues/397) from valera-rozuvan * `jasmine.Any` supports `Boolean` #[392](https://github.com/pivotal/jasmine/issues/392) from albertandrejev * Reporters get execution time #[30](https://github.com/pivotal/jasmine/issues/30) * `toThrow` matchers handle falsy exceptions #[317](https://github.com/pivotal/jasmine/issues/371) * Removed deprecated `jasmine.Matchers.pp` #[363](https://github.com/pivotal/jasmine/issues/363) from robinboehm * Fix for Clock ticking to default to 0 #[340](https://github.com/pivotal/jasmine/issues/340) from Caio Cunha * Whitespace failures should be easier to understand #[332](https://github.com/pivotal/jasmine/issues/332) from bjornblomqvist * Fix for more markdown-y image for Build status #[329](https://github.com/pivotal/jasmine/issues/329) from sunliwen * UTF-8 encoding fixes #[333](https://github.com/pivotal/jasmine/issues/333) from bjornblomqvist * Replaced deprecated octal literal with hexadecimal from kris7t * Make getGlobal() work in strict mode from metaweta * Clears timeout timer even when async spec throws an exception from tidoust * Timeouts scheduled within a delayed function are correctly scheduled and executed from maciej-filip-sz ### Bug Fixes * Improved the performance of the HTML output with a CSS change #[428](https://github.com/pivotal/jasmine/issues/428) - Thanks @tjgrathwell * Removed an accidental global pollution of `j$` as a reference to Jasmine. Thanks to Morten Maxild from the mailing list * There is now a consistent `this` between `beforeEach`, `it` and `afterEach` for a spec * A spy's strategy now has properties `returnValue` and `throwError` because they are better names * Make it easy to copy the title of failing specs from the HTML output * Don't add periods to the full name of a spec fix #[427](https://github.com/pivotal/jasmine/issues/427) * Allow Env to take optional spec/suite ids when asked to `execute` * [Mock clock now less intrusive, replacing global timer functions only when clock is installed](http://www.pivotaltracker.com/story/54168708) * Restore custom failure messages for `toHaveBeenCalledWith` * Jasmine global object has a addCustomEqualityTester and addMatchers (no longer directly on global) * Fixed a global leak of `timer` * Remove currentRunner from Env (users can use topSuite from Env instead) * [Specs without expectations are now considered passing](http://www.pivotaltracker.com/story/59422744) * Improve error message when a spec does not call the async callback within the default time interval * Allow passing a negativeCompare in a custom matcher for more custom implementations when `.not` is called * Update favicon to be higher resolution * Make all async functions be subject to the timeout There were several other pull requests that either had already been fixed, or were good starting points for the various changes above. Thank you for all of the hard work to keep Jasmine awesome. ## Other Bugs and Features There were a few small changes and fixes that didn't fit into any of the above categories: * HTML Reporter refactored for simplicity and performance * Default character encoding on the HTML runner page is UTF-8 * [Escape special regex characters from the spec param](http://www.pivotaltracker.com/story/52731407) * Favicon returns * [Clock supports `eval`'d strings as functions](http://www.pivotaltracker.com/story/40853563) * There should always be stack traces on failures * Removed references to unused `jasmine.VERBOSE` * Removed references to unused `jasmine.XmlHttpRequest` [mocha]: http://visionmedia.github.io/mocha/ [underscore]: http://underscorejs.org/ [grunt]: http://gruntjs.com [node]: http://nodejs.org [phantom]: http://phantomjs.org [jasmine_downloads]: https://github.com/pivotal/jasmine/downloads [contrib]: https://github.com/pivotal/jasmine/blob/master/CONTRIBUTING.md [travis]: http://travis-ci.org [travis_jasmine]: http://travis-ci.org/jasmine [sauce]: http://saucelabs.com [node_suite]: https://github.com/pivotal/jasmine/blob/master/spec/node_suite.js [intro]: http://jasmine.github.io/2.0/introduction.html ------ _Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.0.md000066400000000000000000000060311416413636100166200ustar00rootroot00000000000000# Jasmine-Core 3.0 Release Notes ## Summary Jasmine 3.0 is a major release of Jasmine, and as such includes some breaking changes in addition to various new features. There is also a 2.99 release of Jasmine that will present deprecation warnings for suites that will encounter different behavior in 3.0. ## Breaking Changes * Replace old "catch exceptions" logic with proper fail fast with error reporting - Fixes [#414](https://github.com/jasmine/jasmine/issues/414) - Fixes [jasmine/jasmine-npm#16](https://github.com/jasmine/jasmine-npm/issues/16) * Detect an Error passed to `done` and add an expectation failure - Fixes [#567](https://github.com/jasmine/jasmine/issues/567) * Unify status for xdescribe and xit - Ensure *All's only execute if at least one child will run - Specs will report a status of `excluded` instead of disabled - Fixes [#1418](https://github.com/jasmine/jasmine/issues/1418) * Suite level errors all report the same way (on suiteDone) * Refactor QueueRunner and remove references to functions that Jasmine is done with * expect(null).toEqual(jasmine.any(Object)) no longer passes - Fixes [#1255](https://github.com/jasmine/jasmine/issues/1255) * Default to running tests in random order * The `identity` of a Jasmnine Spy is now a property and no longer a method * Additionally, Jasmine 3.0 drops support for older browsers and environments. Notably: - Internet Explorer 8 and 9 - Ruby 1.x (for the Ruby gem) - Rails 3.x (for the Ruby gem) - Python 2.x (for the Python wheel) - Nodejs 0.x (for the NPM package) ## Changes * Remove node modules from python wheel, and update languages * Allow reporter callbacks to be asynchronous - Fixes [#842](https://github.com/jasmine/jasmine/issues/842) * Allow adding custom spy strategies * Add the ability to specify the strategy to use for a spy based on which parameters are passed * Added links to re-run the suites containing a failing spec * Added a toHaveClass matcher * More informative pretty-printing of DOM elements * Allow jasmine-npm to handle its own load errors * Treat random= as a no-op rather than disabling randomization * Use prototype for spy strategy for better memory management * Remove console.js altogether * Add safari 10 and update readme to include edge * Determine overall status in core, not reporters * Filter Jasmine frames from stack traces * Treat afterAll errors at any level as failures * Improved reporting of load errors and afterAll errors - Pass file and line number to reporters when present - Show file and line number in the HTML reporter when present - Visually separate adjacent errors in the HTML reporter * Report loading errors as loading errors, not afterAll errors * HTML reporter reports overall failure if there are any global errors * Fail if error events (e.g. syntax errors) occur during loading * Allow use of a predicate function to validate thrown exceptions * Check truthiness of toThrowError args, not arg count ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.1.0.md000066400000000000000000000036051416413636100167630ustar00rootroot00000000000000# Jasmine-Core 3.1 Release Notes ## Summary This release contains a number of fixes and pull requests ## Pull Requests and Issues * Display error properties for failed specs - Merges [#1516](https://github.com/jasmine/jasmine/issues/1516) from @jbunton-atlassian * Allow node to report load time errors - Fixes [#1519](https://github.com/jasmine/jasmine/issues/1519) * Fixing missing semi-colons - Merges [#1512](https://github.com/jasmine/jasmine/issues/1512) from @Sylhare * Fixed release notes link * Added matchers: truthy, falsy, empty and notEmpty - Merges [#1460](https://github.com/jasmine/jasmine/issues/1460) from @sjolicoeur * Add API docs for async reporters * Return for functions that have no actual words between keyword and ( - Also fixes a potential catastrophic backtracking if someone has severely damaged their own `toString` during test execution. * Moved toHaveClass matcher into core so that it can be used in Karma - Fixes [#1503](https://github.com/jasmine/jasmine/issues/1503) * allow adding a deprecation object - Merges [#1498](https://github.com/jasmine/jasmine/issues/1498) from @UziTech * Add CodeTriage badge to jasmine/jasmine - Merges [#1505](https://github.com/jasmine/jasmine/issues/1505) from @codetriage-readme-bot * Resolve merge conflict - Merges [#1501](https://github.com/jasmine/jasmine/issues/1501) from @aptx4869 - Fixes [#1500](https://github.com/jasmine/jasmine/issues/1500) * Fix release note typo - Merges [#1499](https://github.com/jasmine/jasmine/issues/1499) @bcaudan * Only show deprecation for catch exceptions if you tell Jasmine not to catch - Fixes [#1497](https://github.com/jasmine/jasmine/issues/1497) * Add notes for environments that have lost support - Fixes [#1495](https://github.com/jasmine/jasmine/issues/1495) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.10.0.md000066400000000000000000000032321416413636100170370ustar00rootroot00000000000000# Jasmine Core 3.10 Release Notes ## New features and bug fixes * Added support for running Jasmine multiple times * If the env is configured with `autoCleanClosures: false`, then it can be executed repeatedly. * Merges #1934 from @nicojs * Fixes #1925 * Improved error message when an async expectation occurs after the spec finishes * Merges #1937 from @AndreWillomitzer * Fixes #1854 * Reject timeout values that are too large for setTimeout * See #1930 * Don't immediately move to the next queueable fn on async error This allows assertion failures and other errors that occur after the async error to be routed to the correct spec/suite. * Added a stringContaining asymmetric equality tester * Fixes #1923. * The jasmine-core Ruby gem now prints a deprecation message when loaded unless the SUPPRESS_JASMINE_DEPRECATION environment variable is set. ## Documentation updates * Added discussion of max timeout value to jsdocs * Merges #1931 from @trusktr * Added missing @since annotations * Improved jsdocs for asymmetric equality testers * Added a deprecation notice to the jasmine-core Ruby gem's description ## Supported environments jasmine-core 3.10.0 has been tested in the following environments. | Environment | Supported versions | |-------------------|--------------------| | Node | 10, 12, 14, 16 | | Safari | 8-14 | | Chrome | 94 | | Firefox | 93, 78, 68 | | Edge | 94 | | Internet Explorer | 10, 11 | ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.10.1.md000066400000000000000000000005251416413636100170420ustar00rootroot00000000000000# Jasmine Core 3.10.1 Release Notes ## Bugfixes * Fixed missing pendingReason in pending spec results * Fixes [#1939](https://github.com/jasmine/jasmine/issues/1939) * Merges [#1940](https://github.com/jasmine/jasmine/pull/1940) from @jan-molak ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.2.0.md000066400000000000000000000044741416413636100167710ustar00rootroot00000000000000# Jasmine-Core 3.2 Release Notes ## Summary This release contains a number of fixes and pull requests ## Changes * Add spyOnAllFunctions function - Merges [#1581](https://github.com/jasmine/jasmine/issues/1581) from @aeisenberg - Fixes [#1421](https://github.com/jasmine/jasmine/issues/1421) * Improve timeout error message - Merges [#1567](https://github.com/jasmine/jasmine/issues/1567) from @ikonst * Fix JSDoc naming for Env functions - See [#1565](https://github.com/jasmine/jasmine/issues/1565) * Add documentation for more public functions on Env - Fixes [#1565](https://github.com/jasmine/jasmine/issues/1565) * Added a basic set of async matchers - Fixes [#1447](https://github.com/jasmine/jasmine/issues/1447) - Fixes [#1547](https://github.com/jasmine/jasmine/issues/1547) * Properly cascade StopExecutionError's up the tree - Fixes [#1563](https://github.com/jasmine/jasmine/issues/1563) * Implemented hiding of disabled specs - Merges [#1561](https://github.com/jasmine/jasmine/issues/1561) from @SamFare * Line-break long expectation failure messages - See [#296](https://github.com/jasmine/jasmine/issues/296) * Better detection of DOM Nodes for equality - Fixes [#1172](https://github.com/jasmine/jasmine/issues/1172) * Fix typo from `incimplete` to `incomplete` - Merges [#1555](https://github.com/jasmine/jasmine/issues/1555) from @yinm * Allow omitting the name argument: `createSpy(func)` - Merges [#1551](https://github.com/jasmine/jasmine/issues/1551) from @riophae * name new global status stuff correctly in API docs * Check for accidental global variable creation * Fixed global variable leak - Fixes [#1534](https://github.com/jasmine/jasmine/issues/1534) * Correctly format stack traces for errors with multiline messages - Fixes [#1526](https://github.com/jasmine/jasmine/issues/1526) * Change message for extra elements at end of actual array - Merges [#1527](https://github.com/jasmine/jasmine/issues/1527) from @majidmade - Fixes [#1485](https://github.com/jasmine/jasmine/issues/1485) * Report unhandled rejections as globalErrors. - Merges [#1521](https://github.com/jasmine/jasmine/issues/1521) from @johnjbarton * add some links to more tutorials from the api docs ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.2.1.md000066400000000000000000000003611416413636100167610ustar00rootroot00000000000000# Jasmine-Core 3.2.1 Release Notes ## Changes * Correctly expose `spyOnAllFunctions` - See [#1581](https://github.com/jasmine/jasmine/issues/1581) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.3.0.md000066400000000000000000000036631416413636100167710ustar00rootroot00000000000000# Jasmine Core 3.3 Release Notes ## Summary This release includes a new way to configure Jasmine, the ability to provide additional context with your expectations, and other things ## Changes * Added expect().withContext() to provide additional information in failure messages * Implement `withContext` for async expectations too - Fixes [#641](https://github.com/jasmine/jasmine/issues/641) * New asynchronous matcher `toBeRejectedWith` - Merges [#1615](https://github.com/jasmine/jasmine/issues/1615) from @codymikol - Closes [#1600](https://github.com/jasmine/jasmine/issues/1600) - Fixes [#1595](https://github.com/jasmine/jasmine/issues/1595) * Show a tip for `toBe` failures for how to get deep equality - Merges [#1616](https://github.com/jasmine/jasmine/issues/1616) from @tdurtshi - Fixes [#1614](https://github.com/jasmine/jasmine/issues/1614) * `expectAsync` now works with non-native promises - Merges [#1613](https://github.com/jasmine/jasmine/issues/1613) from @codymikol - Fixes [#1612](https://github.com/jasmine/jasmine/issues/1612) * Show status marks next to spec description in HTML reporter - Merges [#1610](https://github.com/jasmine/jasmine/issues/1610) from @m1010j - Fixes [#1596](https://github.com/jasmine/jasmine/issues/1596) * Show error messages for `Error`s without a name - Merges [#1601](https://github.com/jasmine/jasmine/issues/1601) from @nitobuendia - Fixes [#1594](https://github.com/jasmine/jasmine/issues/1594) * Optimized clearTimeout cpu usage - Merges [#1599](https://github.com/jasmine/jasmine/issues/1599) from @Havunen * Introduce a configuration object to `Env` deprecating old single use functions - [finishes #159158038](http://www.pivotaltracker.com/story/159158038) * Specify https for github urls in package.json - Merges [#1597](https://github.com/jasmine/jasmine/issues/1597) @limonte ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.4.0.md000066400000000000000000000041021416413636100167570ustar00rootroot00000000000000# Jasmine Core 3.4 Release Notes ## Summary This is a maintenance release of Jasmine with a number of new features and fixes ## Changes * Handle WebSocket events in IE when detecting Errors - Fixes [#1623](https://github.com/jasmine/jasmine/issues/1623) * bump dependencies for security fixes - Merges [#1672](https://github.com/jasmine/jasmine/issues/1672) from @wood1986 * Make node execution default and override for browsers - Merges [#1658](https://github.com/jasmine/jasmine/issues/1658) from @wood1986 - Fixes [#883](https://github.com/jasmine/jasmine/issues/883) * feat(result.duration): report test duration in ms - Merges [#1660](https://github.com/jasmine/jasmine/issues/1660) from @johnjbarton - Fixes [#1646](https://github.com/jasmine/jasmine/issues/1646) * refactor(Timer): share htmlReporter noopTimer via Timer.js - Merges [#1669](https://github.com/jasmine/jasmine/issues/1669) from @johnjbarton * Fix various typos - Merges [#1666](https://github.com/jasmine/jasmine/issues/1666) from @FelixRilling - Merges [#1667](https://github.com/jasmine/jasmine/issues/1667) from @FelixRilling - Merges [#1665](https://github.com/jasmine/jasmine/issues/1665) from @FelixRilling - Merges [#1664](https://github.com/jasmine/jasmine/issues/1664) from @FelixRilling - Fixes [#1663](https://github.com/jasmine/jasmine/issues/1663) * When catching a global error in Node.js, print the type of error - Merges [#1632](https://github.com/jasmine/jasmine/issues/1632) from @jbunton-atlassian * Support Error.stack in globalErrors. - Merges [#1644](https://github.com/jasmine/jasmine/issues/1644) from @johnjbarton * Stop treating objects with a `nodeType` as if they are DOM Nodes - Fixes [#1638](https://github.com/jasmine/jasmine/issues/1638) * Fixes issue where PhantomJS 2 and IE 10 - 11 crashed when reporting SVG element equality - Merges [#1621](https://github.com/jasmine/jasmine/issues/1621) from @Havunen - Fixes [#1618](https://github.com/jasmine/jasmine/issues/1618) ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.5.0.md000066400000000000000000000163321416413636100167700ustar00rootroot00000000000000# Jasmine Core 3.5 Release Notes ## Summary This is a maintenance release of Jasmine with a number of new features and fixes ### Highlights * The output of toHaveBeenCalledWith should now be more readable This breaks each call out onto its own line, so that it's much easier to see where each call starts and how they differ. E.g. previously the output would be: Expected spy foo to have been called with [ 'bar', 'baz', 'qux' ] but actual calls were [ [ 42, 'wibble' ], [ 'bar' 'qux' ], [ 'grault '] ] Now it's: Expected spy foo to have been called with: [ 'bar', 'baz', 'qux' ] but actual calls were: [ 42, 'wibble' ], [ 'bar' 'qux' ], [ 'grault ']. * Add new spy strategies to resolve and reject Promises `resolveTo` and `rejectWith` * Add the ability to have custom async matchers ### Internal notes * Stop testing against PhantomJS * PhantomJS is at end of life, and the last version of Selenium that supported it was 3.6.0, released almost three years ago. We can't test Jasmine against PhantomJS without pinning key pieces of the project to increasingly outdated versions of key libraries. * Fail Jasmine's CI build if the promise returned from `jasmineBrowser.runSpecs` is rejected * A bunch of other rejiggering of the Travis-CI builds to make them easier to work with * Also released a new browser runner that is being used by Jasmine * See [jasmine-browser-runner](https://github.com/jasmine/jasmine-browser) * This is a first pass at getting this to work for other projects as well. Please try it out and let us know what isn't working for you. * add prettier and eslint ## All Changes * Adds new configuration option to failSpecWithNoExpectations that will report specs without expectations as failures if enabled * Merges [#1743](https://github.com/jasmine/jasmine/issues/1743) from @dtychshenko * Fixes [#1740](https://github.com/jasmine/jasmine/issues/1740) * Correctly propagate the `Error` object caught by the global error handler to reporters, etc. - Merges [#1738](https://github.com/jasmine/jasmine/issues/1738) from @prantlf - Fixes [#1728](https://github.com/jasmine/jasmine/issues/1728) * Show argument diffs in toHaveBeenCalledWith failure messages * Fixes [#1641](https://github.com/jasmine/jasmine/issues/1641) * Updated arrayContaining to require actual values to be arrays * Merges [#1746](https://github.com/jasmine/jasmine/issues/1746) from @divido * Fixes [#1745](https://github.com/jasmine/jasmine/issues/1745) * Add the ability to have custom async matchers * Merges [#1732](https://github.com/jasmine/jasmine/issues/1732) from @UziTech * Allow users to set a default spy strategy - Merges [#1716](https://github.com/jasmine/jasmine/issues/1716) from @elliot-nelson * Accept configurations with `Promise: undefined`. * PrettyPrinter survives if objects throw in toString - Merges [#1718](https://github.com/jasmine/jasmine/issues/1718) from @johnjbarton - Fixes [#1726](https://github.com/jasmine/jasmine/issues/1726) * Add `mapContaining` and `setContaining` asymmetric matchers * Merges [#1741](https://github.com/jasmine/jasmine/issues/1741) from @eventlistener * Use the same spec file pattern for both node and browser * Gemspec: Drop EOL'd property rubyforge_project * Merges [#1736](https://github.com/jasmine/jasmine/issues/1736) from @olleolleolle * Updated async timeout message to include all of the ways that async code can be run in Jasmine * Allow users to pass property names to createSpyObj - Merges [#1722](https://github.com/jasmine/jasmine/issues/1722) from @elliot-nelson - Closes [#1569](https://github.com/jasmine/jasmine/issues/1569) - Fixes [#1442](https://github.com/jasmine/jasmine/issues/1442) * don't attempt to normalize PNGs (gitattributes) - Merges [#1721](https://github.com/jasmine/jasmine/issues/1721) from @elliot-nelson * Add `@since` to most JSDoc comments - See [jasmine/jasmine.github.io#117](https://github.com/jasmine/jasmine.github.io/issues/117) * Make no expectations in HTML Reporter message a console warning - Fixes [#1704](https://github.com/jasmine/jasmine/issues/1704) * Prevent page overflow in HTML reporter under some situations by setting an explicit width - Merges [#1713](https://github.com/jasmine/jasmine/issues/1713) from @pixelpax * Cleanup: minor dead code removal and style fixes - Merges [#1708](https://github.com/jasmine/jasmine/issues/1708) from @elliot-nelson * Pretty Printer can now handle printing an object whose `toString` function has been spied upon - Merges [#1712](https://github.com/jasmine/jasmine/issues/1712) from @johnjbarton * PrettyPrinter handles objects with invalid toString implementations - Merges [#1711](https://github.com/jasmine/jasmine/issues/1711) from @elliot-nelson - Closes [#1700](https://github.com/jasmine/jasmine/issues/1700) - Closes [#1575](https://github.com/jasmine/jasmine/issues/1575) * Fix toBeCloseTo matcher for Node.js 12 and Chrome 74 - Merges [#1710](https://github.com/jasmine/jasmine/issues/1710) from @paulvanbrenk - Fixes [#1695](https://github.com/jasmine/jasmine/issues/1695) * spyOnProperty jasmine-style error messages with usage note - Merges [#1706](https://github.com/jasmine/jasmine/issues/1706) from @elliot-nelson * spyOnProperty respects the allowRespy flag - Merges [#1705](https://github.com/jasmine/jasmine/issues/1705) from @elliot-nelson * Introduce matchers#toBeInstanceOf - Merges [#1697](https://github.com/jasmine/jasmine/issues/1697) from @elliot-nelson * Print global errors encountered during CI runs - Merges [#1701](https://github.com/jasmine/jasmine/issues/1701) from @elliot-nelson * Update contributing doc based on some of the newer tooling - Fixes [#1702](https://github.com/jasmine/jasmine/issues/1702) * Extend spyOnAllFunctions to include prototype and parent methods - Merges [#1699](https://github.com/jasmine/jasmine/issues/1699) from @elliot-nelson - Fixes [#1677](https://github.com/jasmine/jasmine/issues/1677) * Improve error handling in CI test launcher - Merges [#1598](https://github.com/jasmine/jasmine/issues/1598) from @elliot-nelson * Add new spy strategies to resolve and reject Promises `resolveTo` and `rejectWith` - Merges [#1688](https://github.com/jasmine/jasmine/issues/1688) from @enelson - See [#1590](https://github.com/jasmine/jasmine/issues/1590) - Fixes [#1715](https://github.com/jasmine/jasmine/issues/1715) * Update deprecation messages to indicate _future_ removal - Fixes [#1628](https://github.com/jasmine/jasmine/issues/1628) * Add toBeRejectedWithError matcher - Merges [#1686](https://github.com/jasmine/jasmine/issues/1686) from @megahertz - Fixes [#1625](https://github.com/jasmine/jasmine/issues/1625) * Ignore internal ci.js from npm package - See [#1684](https://github.com/jasmine/jasmine/issues/1684) * Fix failure messages for positive/negative infinity matchers - Fixes [#1674](https://github.com/jasmine/jasmine/issues/1674) * nit: fix typo - Merges [#1680](https://github.com/jasmine/jasmine/issues/1680) from @acinader * added #toBeTrue and #toBeFalse matchers - Merges [#1679](https://github.com/jasmine/jasmine/issues/1679) from @FelixRilling ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.6.0.md000066400000000000000000000132021416413636100167620ustar00rootroot00000000000000# Jasmine Core 3.6 Release Notes ## Summary This is a maintenance release of Jasmine with a number of new features and fixes. ## Highlights * Added support for custom object formatters * Allows customizing how an object is stringified in matcher failure messages * [Tutorial](https://jasmine.github.io/tutorials/custom_object_formatter) * [API reference](https://jasmine.github.io/api/3.6/jasmine.html#.addCustomObjectFormatter) * Don't require matchers and asymmetric equality testers to pass custom object formatters back to Jasmine - Supports custom object formatters. - Makes it easier to write high quality matchers and asymmetric equality testers. - The old API will still work until 4.0. * Properly import jasmineRequire object before using - Improves compatibility with Webpack - Merges [#1766](https://github.com/jasmine/jasmine/pull/1766) from @amilligan * Added a toHaveBeenCalledOnceWith matcher - Merges [#1801](https://github.com/jasmine/jasmine/pull/1801) from @Maximaximum - Fixes [#1717](https://github.com/jasmine/jasmine/issues/1717) * Added a toHaveSize matcher - Merges [#1796](https://github.com/jasmine/jasmine/pull/1796) from @wokier * Added a toBePending async matcher - Merges [#1808](https://github.com/jasmine/jasmine/pull/1808) from @DCtheTall - Fixes [#1803](https://github.com/jasmine/jasmine/issues/1803) * Added support for user-defined spec/suite properties - Allows specs/suites to pass data to custom reporters - Merges [#1763](https://github.com/jasmine/jasmine/pull/1763) from @johnjbarton * Route unhandled promise rejections to onerror - Merges [#1778](https://github.com/jasmine/jasmine/pull/1778) from @johnjbarton - Fixes [#1777](https://github.com/jasmine/jasmine/issues/1777) ## Internal notes * Use a version of eslint that works on Node 8 * Check for syntax and standard library objects that don't work in IE * Run eslint against all files * Add Additional Test for equals Matcher - Merges [#1829](https://github.com/jasmine/jasmine/pull/1829) from @tobiasschweizer - Fixes [#1821](https://github.com/jasmine/jasmine/issues/1821) * Depend on head of jasmine-browser to fix IE failures in CI * Fixed test failure in Firefox 74 * Added test for resolveTo/rejectWith with empty parameters - Merges [#1802](https://github.com/jasmine/jasmine/pull/1802) from @chivesrs * Removed unnecessary uses of new in tests * Realigned the browser testing matrix to match current reality - Use Windows instead of Linux so we can get current browsers from Sauce. - Test against the version of Firefox that corresponds to ESR as well as latest. - Test the latest Edge rather than a specific older version. - Test Safari 8 and 13 instead of 8, 9 and 10. What works in those versions is likely to work in the ones in between. * Don't leak global error handlers between Jasmine's own tests * Added basic property tests for matchersUtil.equals * Added integration tests for existing matcher interfaces * Added integration tests for asymmetric equality testers * Test IE before other browsers on Travis ## Other Changes * Show diffs involving root-level asymmetric equality testers - Fixes [#1831](https://github.com/jasmine/jasmine/issues/1831) * Fixed references to master in docs * Allow spy throwError to throw an Object - Merges [#1822](https://github.com/jasmine/jasmine/pull/1822) from @terencehonles * Added missing periods to README - Merges [#1828](https://github.com/jasmine/jasmine/pull/1828) from @dirkpuge * Expose setSpec/SuiteProperty on interface - Merges [#1820](https://github.com/jasmine/jasmine/pull/1820) from @johnjbarton * Prevent undesired reloads when karma-jasmine-html-reporter is used - Merges [#1807](https://github.com/jasmine/jasmine/pull/1807) from @parloti - Fixes [#1775](https://github.com/jasmine/jasmine/issues/1775) * Correctly report spec and suite duration - Fixes [#1676](https://github.com/jasmine/jasmine/issues/1676). * Added jsdocs for MatchersUtil * Allow the .callThrough spy strategy to call constructor functions without errors - Merges [#1782](https://github.com/jasmine/jasmine/pull/1782) from @enelson - Fixes [#1760](https://github.com/jasmine/jasmine/issues/1760) * Inject a per-runable pretty printer into MatchersUtil - Supports custom object formatters * Include stack traces in unhandled promise rejection messages * Describe the naming for the function it - Merges [#1772](https://github.com/jasmine/jasmine/pull/1772) from @johnlinp * Correctly extract error messages from stack traces that don't start with `Error` - Merges [#1776](https://github.com/jasmine/jasmine/pull/1776) from @vhermannitk - Fixes [#1771](https://github.com/jasmine/jasmine/issues/1771) * Fixed objectContaining to not match when the expected is the empty object and the actual is a non-object * Fixed toEqual(0, Number.MIN_VALUE) to fail instead of passing - Merges [#1764](https://github.com/jasmine/jasmine/pull/1764) from @dubzzz * Fixed comparison between ObjectContaining and non-objects on IE * Provide better diffs for object graphs that include `objectContaining` * Indent multiline failure messages in the output of `withContext` * This makes it easier to see where each failure message begins and ends. * Report async expectations that complete after the runable completes - See [#1752](https://github.com/jasmine/jasmine/issues/1752). * Treat NodeJS assertion failures as expectation failures - Merges [#1678](https://github.com/jasmine/jasmine/pull/1678) from @apla ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.7.0.md000066400000000000000000000051701416413636100167700ustar00rootroot00000000000000# Jasmine Core 3.7 Release Notes ## Summary This is a maintenance release of Jasmine with a number of new features and fixes. ## New features and bug fixes * Allow custom object formatters to be added in beforeAll - Fixes [#1876](http://github.com/jasmine/jasmine/issues/1876) * Allow specs to disable Jasmine's global error handling by overwriting `onerror`. - Merges [#1860](https://github.com/jasmine/jasmine/pull/1860) from @greghuc * Fixed comparison between URL objects - Fixes [#1866](http://github.com/jasmine/jasmine/issues/1866) * Added support for stack traces created by `node --enable-source-maps` with tools like the Typescript compiler. - Merges [#1862](https://github.com/jasmine/jasmine/pull/1862) from @JannesMeyer * Made properties added by createSpyObj() enumerable. - Merges [#1859](https://github.com/jasmine/jasmine/pull/1859) from DCtheTall - Fixes [#1837](http://github.com/jasmine/jasmine/issues/1837) * Show the name of the spec/suite that caused a deprecation * Warn if a spec or before/after function both takes a callback and returns a promise * Don't overwrite MatchersUtil methods with ones that were added to `Array.prototype`, esp. `contains` - Fixes [#1849](http://github.com/jasmine/jasmine/issues/1849) * Allow generator functions to be passed to `.and.callFake` - Fixes [#1848](http://github.com/jasmine/jasmine/issues/1848) ## Documentation updates * Fixed instructions for contributors to run Jasmine's ci script * Updated supported Node versions in README * Fixed script and CSS URLs in standalone example in README - Merges [#1839](https://github.com/jasmine/jasmine/pull/1839) from @snowman * Fixed typo in asyncMatcher toBePending comment - Merges [#1847](https://github.com/jasmine/jasmine/pull/1847) from @SnailCoil * Fixed link to custom object formatter tutorial * Added jasmine.isSpy to the public interface - Fixes [#1880](http://github.com/jasmine/jasmine/issues/1880) ## Internal notes * Fixed intermittent test failures * Added additional assertions to tests for toBeTruthy and toBeFalsy - Merges [#1875](https://github.com/jasmine/jasmine/pull/1875) from @yasinkocak * Pointed Travis badge at travis-ci.com, not .org * Fixed file globs so that Prettier runs on all files * Check for forgotten console and debugger statements * Fixed code in Jasmine that will trigger deprecations in 3.99 * Use jasmine-browser from npm rather than from the main branch - The current released version now works with IE, so we no longer need to depend on main. ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.7.1.md000066400000000000000000000005011416413636100167620ustar00rootroot00000000000000# Jasmine Core 3.7.1 Release Notes ## Summary This is a bug fix release of Jasmine. It's identical to 3.7.0 except that it correctly reports its version number. Please see the [3.7.0 release notes](https://github.com/jasmine/jasmine/blob/main/release_notes/3.7.0.md) if you're upgrading directly from 3.6.0 or earlier. jasmine-4.0.0/release_notes/3.8.0.md000066400000000000000000000112541416413636100167710ustar00rootroot00000000000000# Jasmine Core 3.8 Release Notes ## Summary This is a maintenance release of Jasmine with a number of new features and fixes. ## Python deprecation The Jasmine packages for Python are deprecated. We intend to continue releasing them through the end of the 3.x series, but after that they will be discontinued. We recommend migrating to the following alternatives: * The [jasmine-browser-runner](https://github.com/jasmine/jasmine-browser) npm package to run specs in browsers, including headless Chrome and Saucelabs. This is the most direct replacement for the `jasmine server` and `jasmine ci` commands provided by the `jasmine` Python package. * The [jasmine](https://github.com/jasmine/jasmine-npm) npm package ( `npm install jasmine`) to run specs under Node.js. * The standalone distribution from the [latest Jasmine release](https://github.com/jasmine/jasmine/releases) to run specs in browsers with no additional tools. * The [jasmine-core](https://github.com/jasmine/jasmine) npm package if all you need is the Jasmine assets. This is the direct equivalent of the jasmine-core Python package. ## New features and bug fixes * Fixed spec filtering in Karma * Merges [#1920](https://github.com/jasmine/jasmine/pull/1920) from @jlpstolwijk * Fixes [#1906](https://github.com/jasmine/jasmine/issues/1906) * Added expectAsync(...).already * Causes async matchers to immediately fail if the promise is pending * See https://jasmine.github.io/api/3.8/async-matchers.html#already * Fixes [#1845](https://github.com/jasmine/jasmine/issues/1845) * Include rejection details in failure messages for toBeResolved and toBeResolvedWith * Fixed "stop spec on expectation failure" checkbox in standalone * Added option for spyOnAllFunctions to include non-enumerable props * Makes spyOnAllFunctions work on instance methods of ES6 classes * Merges [#1909](https://github.com/jasmine/jasmine/pull/1909) from @Dari-k * Fixes [#1897](https://github.com/jasmine/jasmine/issues/1897) * Added Spy#calls#thisFor * Provides the `this` value for a given spy call * Merges [#1903](https://github.com/jasmine/jasmine/pull/1903) from @ajvincent * Improved handling of unhandled promise rejections with no error in Node * Fixes [#1759](https://github.com/jasmine/jasmine/issues/1759) ## Documentation updates * Updated package description * Updated contributing guide * Added TypeScript typings and jasmine-browser-runner to issue template * Removed constructors from jsdocs of classes that aren't user-constructable * Fixed config.seed type in jsdocs * Merges [#1892](https://github.com/jasmine/jasmine/pull/1892) from @UziTech * Added jsdocs for the following: * asymmetric equality testers * Env#execute * Env#allowRespy * The public portion of Spec * Spy.callData.returnValue * Env#topSuite and Suite * Added a jsdoc cross-reference from Configuration to its usage * Added a note about correct usage of async matchers * Added support for ArrayBuffers to matchersUtil.equals * Merges [#1891](https://github.com/jasmine/jasmine/pull/1892) from @Finesse * Merges [#1689](https://github.com/jasmine/jasmine/pull/1892) from @dankurka * Fixes [#1687](https://github.com/jasmine/jasmine/issues/1687) ## Internal notes * Fixed typo in spec name * Merges [#1918](https://github.com/jasmine/jasmine/pull/1918) from @eltociear * Specify files to include in the NPM package rather than files to exclude * Added test coverage for MatchersUtil#equals with typed arrays * Removed checks for typed array support in the test suite * All supported browsers have all typed arrays except for Uint8ClampedArray, BigInt64Array, and BigUint64Array. * Fixed test failures on IE 10 * Test matrix updates * Added Node 16 * Added Safari 14 * Added Firefox 78 (closest match to current ESR) * Removed Safari 10-12 to speed up CI. The newer and older versions we test provide a good measure of safety. * Replaced node-sass dev dependency that isn't compatible with Node 16 * Removed unused dev dependencies * Migrated CI from Travis to Circle * Compensate for clock jitter in specs ## Supported environments jasmine-core 3.8.0 has been tested in the following environments. | Environment | Supported versions | |-------------------|--------------------| | Node | 10, 12, 14, 16 | | Safari | 8-14 | | Chrome | 91 | | Firefox | 89, 68, 78 | | Edge | 91 | | Internet Explorer | 10, 11 | ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.9.0.md000066400000000000000000000050161416413636100167710ustar00rootroot00000000000000# Jasmine Core 3.9 Release Notes ## New features and bug fixes * Fixed Trusted Types error in `j$.isError_` in Chromium-based browsers * Merges [#1921](https://github.com/jasmine/jasmine/pull/1921) from @bjarkler * Fixes [#1910](https://github.com/jasmine/jasmine/issues/1910) * Fixes [#1653](https://github.com/jasmine/jasmine/issues/1653) * Better reporting of unhandled promise rejections with truthy but non-`Error` reasons on Node * `Env#execute` returns a promise in environments that support promises * Renamed `failFast` and `oneFailurePerSpec` config props to `stopOnSpecFailure` and `stopSpecOnExpectationFailure` The new names are more self-explanatory and consistent with jasmine-npm. The old names are deprecated but will still work until the next major release. * Split `boot.js` into two files to allow the env to be configured in between This is mainly intended to support jasmine-browser-runner, which will load a script that configures the env in between the two boot files (`boot0.js` and `boot1.js`). The single-file `boot.js` will still be included until the next major release. ## Ruby deprecation The Jasmine Ruby gems are deprecated. There will be no further releases after the end of the Jasmine 3.x series. We recommend that most users migrate to the [jasmine-browser-runner](https://github.com/jasmine/jasmine-browser) npm package, which is the direct replacement for the `jasmine` gem. If `jasmine-browser-runner` doesn't meet your needs, one of these might: * The [jasmine](https://github.com/jasmine/jasmine-npm) npm package to run specs in Node.js. * The [standalone distribution](https://github.com/jasmine/jasmine#installation) to run specs in browsers with no additional tools. * The [jasmine-core](https://github.com/jasmine/jasmine) npm package if all you need is the Jasmine assets. This is the direct equivalent of the `jasmine-core` Ruby gem. ## Documentation updates * Added API docs for `Suite#id` and `Spec#id` * Marked `Env#hideDisabled` deprecated in jsdocs ------ ## Supported environments jasmine-core 3.9.0 has been tested in the following environments. | Environment | Supported versions | |-------------------|--------------------| | Node | 10, 12, 14, 16 | | Safari | 8-14 | | Chrome | 92 | | Firefox | 91, 78, 68 | | Edge | 92 | | Internet Explorer | 10, 11 | _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/3.99.0.md000066400000000000000000000007771416413636100170730ustar00rootroot00000000000000# Jasmine Core 3.99.0 Release Notes ## Summary This release adds deprecation warnings for breaking changes that will be introduced in Jasmine 4.0. Please see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0) for more information. This is the last planned release of jasmine-core for Ruby or Python. Versions 4.0 and later will be offered only via NPM and the standalone distribution. ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/4.0.0.md000066400000000000000000000174671416413636100167760ustar00rootroot00000000000000# Jasmine Core 4.0.0 Release Notes ## Summary This is a major release. In addition to new features and bug fixes it contains a number of breaking changes that are intended to diagnose common errors, improve awkward or outdated APIs, and make Jasmine easier to maintain and contribute to. If you're upgrading from Jasmine 3.x, we recommend installing 3.99 and fixing any deprecation warnings that it emits before updating to 4.0. Please see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0) for more information. If you use the `jasmine` or `jasmine-browser-runner` NPM packages, please read the release notes for those packages as well. ## Highlights * Obsolete environments, most notably Internet Explorer, are no longer supported. Jasmine now expects to run in an environment that provides most of ES2017 and, in the case of Node, good interoperability between CommonJS modules and ES modules. * The Jasmine packages for Ruby and Python have been discontinued. * Errors in `beforeAll` and `beforeEach` functions are handled better. * Jasmine can optionally be used without creating globals in Node. * Certain common async testing bugs are now reported as errors. * A new debug logging feature makes it easier to debug failing specs, particularly intermittent failures. See details below. ## Breaking changes ### Changes to supported environments The following previously supported environments are no longer supported: * Internet Explorer * PhantomJS * Safari 8-13 * Firefox 68 and 78 * Node 10 and 12.0-12.16 * Python * Ruby * Bower Although Jasmine 4.0 may still work in some of those environments, we no longer test against them and won't try to maintain compatibility with them in future 4.x releases. The [`jasmine-browser-runner`](https://jasmine.github.io/setup/browser.html) NPM package is the direct replacement for the `jasmine` Ruby and Python packages. ### Changes that affect how specs are written * When a `beforeAll` function fails in any way other than a failed expectation, Jasmine will not run the contents of the suite or any child suites except for any `afterAll` functions defined in the same suite as the failed `beforeAll` function. All affected specs will still be reported as failed. See [#1533](https://github.com/jasmine/jasmine/issues/1533). * When a `beforeEach` function fails in any way other than a failed expectation, Jasmine will skip any subsequent `beforeEach` functions, the corresponding spec, and any `afterEach` functions defined in child suites. `afterEach` functions defined at the same or higher levels will still run. The spec will still be reported as failed. See [#1533](https://github.com/jasmine/jasmine/issues/1533). * `MatchersUtil#contains` and the `toContain` matcher use deep equality rather than `===` to compare set members. This matches how arrays are handled but may cause some previously passing `.not.toContain()` expectations to fail. * `jasmine.clock().mockDate()` throws if its argument is not a `Date`. Previous versions ignored non-`Date` arguments. * Multiple calls to an asynchronous function's `done` callback are treated as errors. * Any argument passed to a `done` callback (other than `undefined`) is treated as an error. Previous versions ignored any argument that wasn't an `Error` instance. * Jasmine will report an error rather than a warning when a function tries to combine two different forms of async (e.g. taking a callback and also returning a promise). * `this` in `describe` functions is no longer a `Suite` object. * Empty suites are treated as errors. * Merges [#1742](https://github.com/jasmine/jasmine/pull/1742) from @johnjbarton * The current time value does not decrease when `jasmine.clock().tick()` is called from a `setTimeout` or `setInterval` callback. * Merges [#1948](https://github.com/jasmine/jasmine/pull/1948) from @thw0rted * Fixes [#1929](https://github.com/jasmine/jasmine/issues/1929). ### Changes to how Jasmine is configured * Individual configuration property getters and setters such as `Env#randomTests` and `Env#randomizeTests` have been removed. Use `Env#configuration` and `Env#configure` instead. * The `failFast` and `oneFailurePerSpec` configuration properties have been removed. Use `stopOnSpecFailure` and `stopSpecOnExpectationFailure` instead. * The `Promise` configuration property has been removed. Jasmine can still consume non-native promises but will always use the global `Promise` to create promises. ### Changes that affect custom matchers * The old style of using custom equality testers, where matchers received them from Jasmine and had to pass them back to `matchersUtil` methods, is no longer supported. * `matchersUtil` and `pp` are no longer available globally. Instead, use the instances that are passed to custom matcher factories and to `jasmineToString`. See the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0) for more information about these changes and how to update custom matchers that use the old APIs. ### Changes that affect custom reporters * The [`Suite`](https://jasmine.github.io/api/4.0/Suite.html) and [`Spec`](https://jasmine.github.io/api/4.0/Spec.html) objects returned from `describe`, `it`, and `Env#topSuite` no longer expose private APIs. ### Other breaking changes * `boot.js` is no longer included. Use `boot0.js` and `boot1.js` instead. * Boot files in `lib/jasmine-core/boot` are no longer included in the NPM package. Use the boot files in `lib/jasmine-core` instead. * `json2.js` is no longer included, since all supported environments provide a JSON parser. ## Other new features and bug fixes * Jasmine can optionally be used without creating globals in Node.js. * See https://jasmine.github.io/api/4.0/module-jasmine-core.html#.noGlobals * If you're using the `jasmine` package, see [its documentation](https://jasmine.github.io/api/npm/4.0/JasmineOptions.html#globals). * Fixes [#1235](https://github.com/jasmine/jasmine/issues/1235) * Custom spy strategies are inherited from parent suites like other runnable resources. * `pending()` can now be called from `beforeEach` functions. * Fixes [#1579](https://github.com/jasmine/jasmine/issues/1579) * Removed duplicate message from errors (including. matcher failures) in V8-based environments. * `Spy#withArgs` supports custom equality testers. * Fixes [#1836](https://github.com/jasmine/jasmine/issues/1836) * The promise returned by `Env#execute` is resolved to the [jasmineDoneInfo](https://jasmine.github.io/api/4.0/global.html#JasmineDoneInfo). * Fixed stack trace filtering on Safari 15. * The HTML reporter includes top suite failures in the reported failure count. * `afterAll` functions are run after a failure even if the `stopOnSpecFailure` config property is set. * Added a debug logging feature to make it easier to debug failing specs. * Call `jasmine#debugLog` during spec execution to add a log entry. * If the spec fails, log entries are reported as part of the [specDone](https://jasmine.github.io/api/4.0/Reporter.html#specDone) reporter event. * The HTML reporter no longer says that expectations occurring after the spec finishes are AfterAll errors. ## Documentation updates * Added a [4.0 migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0) * Updated the README and contributing guide for 4.0 ## Supported environments jasmine-core 4.0.0 has been tested in the following environments. | Environment | Supported versions | |-------------------|--------------------| | Node | 12.17+, 14, 16 | | Safari | 14-15 | | Chrome | 96 | | Firefox | 91, 95 | | Edge | 96 | ------ _Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ jasmine-4.0.0/release_notes/older_versions.md000066400000000000000000000072461416413636100213660ustar00rootroot00000000000000# Release 1.0.1.1 — November 9, 2010 ## Jasmine Gem ## Bugs fixed * Rails 3.0 and RSpec 2.0 are now supported. ## Known issues * Rails 3 generators are not yet implemented -- coming soon! ----- # Release 1.0.1 — October 5, 2010 ----- ## Jasmine Core ## Bugs fixed * Bug fixes for Internet Explorer (thanks fschwiet, fabiomcosta, and jfirebaugh). ## Jasmine Gem ## Bugs fixed * Bug fix for Windows (thanks jfirebaugh). ----- # Release 1.0 — September 14, 2010 ----- ## Jasmine Core ## Features * `waitsFor()` arguments can now be specified in any order. Timeout and message are optional. * The default `waitsFor()` timeout period is now specified in `env.defaultTimeoutInterval`; the default value is 5 seconds. * Added link to jasmine site from html runner. * Added license file to standalone distribution. * New friendly version number. ## Bugs fixed * `waitsFor()` hanged forever if latch function never returned true. * The `not.toThrow()` matcher threw an exception when used with no args. * The `toThrow()` matcher, when inverted, gave misleading failure messages. * Spy matchers, when inverted, gave misleading failure messages. ## Deprecations * Deprecated `waits()` block in favor of `waitsFor()`; `waits()` will be removed in a future release. * Deprecated `toNotBe()`, `toNotEqual()`, `toNotMatch()`, and `toNotContain()` matchers; they will be removed in a future release. * Console X was removed from the distribution as it was no longer used. * To give us some flexibility for future features, wrapped matcher functions now return `undefined` (they previously returned `true` or `false`, but this was undocumented). ## Jasmine Gem ## Features * Jasmine now supports JRuby. * Jasmine now supports Ruby 1.9. ## Bugs fixed * Various generator issues fixed. ## Known issues * Rails 3 and RSpec 2 are not yet fully supported. ----- # Release 0.11.1 — June 25, 2010 ----- ## Jasmine Core ### Features * Jasmine no longer logs "Jasmine Running…" messages to the log by default. This can be enabled in runner.html by adding 'trivialReporter.logRunningSpecs = true;'. * The `wasCalled()`, `wasCalledWith()`, `wasNotCalled()` and `wasNotCalledWith()` matchers have been deprecated. The new matchers `toHaveBeenCalled()` and `toHaveBeenCalledWith()` have been added. You can use the `not` prefix to achieve equivalent of the `wasNot…()` expectation (e.g. `not.toHaveBeenCalled()`). ## Notables * A barebones version of Jasmine is now available on http://pivotal.github.com/jasmine/. ----- # Release 0.11.0 — June 23, 2010 ----- ## Jasmine Core ## Features * The version number has been removed from the generated single-file /lib/jasmine.js. We're also now uploading this file, with the version number in the filename, to github's Downloads page. * Old-style matchers (those using this.report(), from before 0.10.x) are no longer supported. See the README for instructions on writing new-style matchers. * jasmine.log pretty-prints its parameters to the spec's output. * Jasmine no longer depends on 'window'. * HTML runner should show number of passes/fails by spec, not expectation. * Small modification to JsApiReporter data format. ## Bugs fixed: * If multiple beforeEach blocks were declared, they were executed in reverse order. * Specs with duplicate names confused TrivialReporter output. * Errors in describe functions caused later tests to be weirdly nested. * Nested specs weren't reported properly by the JsApiReporter. ## Known issues: * If you turn on the mock clock, you'll get a spurious log message at the end of your spec. jasmine-4.0.0/scripts/000077500000000000000000000000001416413636100146355ustar00rootroot00000000000000jasmine-4.0.0/scripts/run-all-browsers000077500000000000000000000013241416413636100200010ustar00rootroot00000000000000#!/bin/sh run_browser() { browser=$1 version=$2 description="$browser $version" if [ $version = "latest" ]; then version="" fi echo echo echo "Running $description" echo USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version npm run ci if [ $? -eq 0 ]; then echo "PASS: $description" >> "$passfile" else echo "FAIL: $description" >> "$failfile" fi } passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 run_browser chrome latest run_browser firefox latest run_browser firefox 91 run_browser safari 15 run_browser safari 14 run_browser MicrosoftEdge latest echo cat "$passfile" "$failfile" if [ -s "$failfile" ]; then exit 1 fi jasmine-4.0.0/scripts/start-sauce-connect000077500000000000000000000015021416413636100204430ustar00rootroot00000000000000#!/usr/bin/env bash set -o errexit set -o pipefail if [ $# -gt 1 -o "$1" = "--help" ]; then echo "Usage: $0 [pidfile]" 1>&2 exit fi if [ -z "$1" ]; then pidfile=`mktemp` else pidfile="$1" fi outfile=`mktemp` echo "Starting Sauce Connect" if [ -z "$SAUCE_TUNNEL_IDENTIFIER" ]; then sc -u "$SAUCE_USERNAME" -k "$SAUCE_ACCESS_KEY" -X 4445 --pidfile "$pidfile" 2>&1 | tee "$outfile" & else sc -u "$SAUCE_USERNAME" -k "$SAUCE_ACCESS_KEY" -X 4445 --pidfile "$pidfile" -i "$SAUCE_TUNNEL_IDENTIFIER" 2>&1 | tee "$outfile" & fi while ! fgrep "Sauce Connect is up, you may start your tests." "$outfile" > /dev/null; do sleep 1 if ! ps -p $(cat "$pidfile") > /dev/null; then echo "Sauce Connect exited" exit 1 fi done if ! nc -z localhost 4445; then echo "Can't connect to Sauce tunnel" killall sc exit 1 fi jasmine-4.0.0/scripts/stop-sauce-connect000077500000000000000000000014361416413636100203010ustar00rootroot00000000000000#!/usr/bin/env bash set -o errexit set -o pipefail if [ -z "$1" ]; then echo "Usage: $0 sauce-connect-pid" 1>&2 exit fi pid="$1" echo "PID: $pid" echo "Stopping Sauce Connect" # Sauce Connect docs say that we can just kill -9 it if we don't care about # failing any ongoing sessions. In practice, that sometimes works but usually # leaks a tunnel so badly that you can't even stop it from the web UI. # Instead of doing that, we give Sauce Connect some time to shut down # gracefully and then give up. kill -INT $pid # Wait up to 2 minutes, then give up if it's still running n=0 while [ $n -lt 120 ] && ps -p $pid > /dev/null; do sleep 1 kill -INT $pid 2> /dev/null || true n=$(($n + 1)) done if ps -p $pid > /dev/null; then echo "Could not shut down Sauce Connect" fi exit $exitcode jasmine-4.0.0/spec/000077500000000000000000000000001416413636100141005ustar00rootroot00000000000000jasmine-4.0.0/spec/.eslintrc.js000066400000000000000000000012441416413636100163400ustar00rootroot00000000000000module.exports = { ignorePatterns: ['support/ci.js', 'support/jasmine-browser.js'], rules: { // Relax rules for now to allow for the quirks of the test suite // TODO: We should probably remove these & fix the resulting errors quotes: 'off', semi: 'off', 'key-spacing': 'off', 'space-before-blocks': 'off', 'no-unused-vars': 'off', 'no-trailing-spaces': 'off', 'block-spacing': 'off', // Since linting is done at the end of the process and doesn't stop us // from running tests, it makes sense to fail if debugger statements // or console references are present. 'no-debugger': 'error', 'no-console': 'error' } }; jasmine-4.0.0/spec/core/000077500000000000000000000000001416413636100150305ustar00rootroot00000000000000jasmine-4.0.0/spec/core/AsyncExpectationSpec.js000066400000000000000000000602741416413636100214730ustar00rootroot00000000000000describe('AsyncExpectation', function() { beforeEach(function() { jasmineUnderTest.Expectation.addAsyncCoreMatchers( jasmineUnderTest.asyncMatchers ); }); describe('#not', function() { it('converts a pass to a fail', function() { var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve(), pp = jasmineUnderTest.makePrettyPrinter(), expectation = jasmineUnderTest.Expectation.asyncFactory({ matchersUtil: new jasmineUnderTest.MatchersUtil({ pp: pp }), actual: actual, addExpectationResult: addExpectationResult }); return expectation.not.toBeResolved().then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ passed: false, message: 'Expected [object Promise] not to be resolved.' }) ); }); }); it('converts a fail to a pass', function() { var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.reject(), expectation = jasmineUnderTest.Expectation.asyncFactory({ matchersUtil: new jasmineUnderTest.MatchersUtil({ pp: function() {} }), actual: actual, addExpectationResult: addExpectationResult }); return expectation.not.toBeResolved().then(function() { expect(addExpectationResult).toHaveBeenCalledWith( true, jasmine.objectContaining({ passed: true, message: '' }) ); }); }); }); it('propagates rejections from the comparison function', function() { var error = new Error('ExpectationSpec failure'); var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = dummyPromise(), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: actual, addExpectationResult: addExpectationResult }); spyOn(expectation, 'toBeResolved').and.returnValue(Promise.reject(error)); return expectation.toBeResolved().then( function() { fail('Expected a rejection'); }, function(e) { expect(e).toBe(error); } ); }); describe('#withContext', function() { it('prepends the context to the generated failure message', function() { var matchersUtil = { pp: function(val) { return val.toString(); } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: Promise.reject('rejected'), addExpectationResult: addExpectationResult, matchersUtil: matchersUtil }); return expectation .withContext('Some context') .toBeResolved() .then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: Expected a promise to be resolved but it was rejected with rejected.' }) ); }); }); it('prepends the context to a custom failure message', function() { var matchersUtil = { buildFailureMessage: function() { return 'failure message'; }, pp: jasmineUnderTest.makePrettyPrinter() }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: Promise.reject('b'), addExpectationResult: addExpectationResult, matchersUtil: matchersUtil }); return expectation .withContext('Some context') .toBeResolvedTo('a') .then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: "Some context: Expected a promise to be resolved to 'a' " + "but it was rejected with 'b'." }) ); }); }); it('prepends the context to a custom failure message from a function', function() { pending('should actually work, but no custom matchers for async yet'); var matchersUtil = { buildFailureMessage: function() { return 'failure message'; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.reject(), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: actual, addExpectationResult: addExpectationResult, matchersUtil: matchersUtil }); return expectation .withContext('Some context') .toBeResolved() .then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: msg' }) ); }); }); it('works with #not', function() { var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve(), pp = jasmineUnderTest.makePrettyPrinter(), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: actual, addExpectationResult: addExpectationResult, matchersUtil: new jasmineUnderTest.MatchersUtil({ pp: pp }) }); return expectation .withContext('Some context') .not.toBeResolved() .then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: Expected [object Promise] not to be resolved.' }) ); }); }); it('works with #not and a custom message', function() { var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve('a'), expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: actual, addExpectationResult: addExpectationResult, matchersUtil: new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }) }); return expectation .withContext('Some context') .not.toBeResolvedTo('a') .then(function() { expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: "Some context: Expected a promise not to be resolved to 'a'." }) ); }); }); }); describe('async matchers', function() { it('makes custom matchers available to this expectation', function() { var asyncMatchers = { toFoo: function() {}, toBar: function() {} }, expectation; expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: asyncMatchers }); expect(expectation.toFoo).toBeDefined(); expect(expectation.toBar).toBeDefined(); }); it("wraps matchers's compare functions, passing in matcher dependencies", function() { var fakeCompare = function() { return Promise.resolve({ pass: true }); }, matcherFactory = jasmine .createSpy('matcher') .and.returnValue({ compare: fakeCompare }), matchers = { toFoo: matcherFactory }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.asyncFactory({ matchersUtil: matchersUtil, customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(matcherFactory).toHaveBeenCalledWith(matchersUtil); }); }); it("wraps matchers's compare functions, passing the actual and expected", function() { var fakeCompare = jasmine .createSpy('fake-compare') .and.returnValue(Promise.resolve({ pass: true })), matchers = { toFoo: function() { return { compare: fakeCompare }; } }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.asyncFactory({ matchersUtil: matchersUtil, customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(fakeCompare).toHaveBeenCalledWith('an actual', 'hello'); }); }); it('reports a passing result to the spec when the comparison passes', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true }); } }; } }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, matchersUtil: matchersUtil, actual: 'an actual', addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, message: '', error: undefined, expected: 'hello', actual: 'an actual', errorForStack: errorWithStack }); }); }); it('reports a failing result to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: false }); } }; } }, matchersUtil = { buildFailureMessage: function() { return ''; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, matchersUtil: matchersUtil, actual: 'an actual', addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: '', error: undefined, errorForStack: errorWithStack }); }); }); it('reports a failing result and a custom fail message to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: false, message: 'I am a custom message' }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: 'an actual', customAsyncMatchers: matchers, addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: false, message: function() { return 'I am a custom message'; } }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); it('reports a passing result to the spec when the comparison fails for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: false }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, message: '', error: undefined, expected: 'hello', actual: actual, errorForStack: errorWithStack }); }); }); it('reports a failing result to the spec when the comparison passes for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true }); } }; } }, matchersUtil = { buildFailureMessage: function() { return 'default message'; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', matchersUtil: matchersUtil, addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: 'default message', error: undefined, errorForStack: errorWithStack }); }); }); it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true, message: 'I am a custom message' }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true }); }, negativeCompare: function() { return Promise.resolve({ pass: true }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, expected: 'hello', actual: actual, message: '', error: undefined, errorForStack: errorWithStack }); }); }); it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true }); }, negativeCompare: function() { return Promise.resolve({ pass: false, message: "I'm a custom message" }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ customAsyncMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: "I'm a custom message", error: undefined, errorForStack: errorWithStack }); }); }); it('reports errorWithStack when a custom error message is returned', function() { var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: false, message: 'I am a custom message', error: customError }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: 'an actual', customAsyncMatchers: matchers, addExpectationResult: addExpectationResult }); return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); it("reports a custom message to the spec when a 'not' comparison fails", function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true, message: 'I am a custom message' }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: 'an actual', customAsyncMatchers: matchers, addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); it("reports a custom message func to the spec when a 'not' comparison fails", function() { var matchers = { toFoo: function() { return { compare: function() { return Promise.resolve({ pass: true, message: function() { return 'I am a custom message'; } }); } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), errorWithStack = new Error('errorWithStack'), expectation; spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue( errorWithStack ); expectation = jasmineUnderTest.Expectation.asyncFactory({ actual: 'an actual', customAsyncMatchers: matchers, addExpectationResult: addExpectationResult }).not; return expectation.toFoo('hello').then(function() { expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: errorWithStack }); }); }); }); function dummyPromise() { return new Promise(function(resolve, reject) {}); } }); jasmine-4.0.0/spec/core/CallTrackerSpec.js000066400000000000000000000110401416413636100203640ustar00rootroot00000000000000describe('CallTracker', function() { it('tracks that it was called when executed', function() { var callTracker = new jasmineUnderTest.CallTracker(); expect(callTracker.any()).toBe(false); callTracker.track(); expect(callTracker.any()).toBe(true); }); it('tracks that number of times that it is executed', function() { var callTracker = new jasmineUnderTest.CallTracker(); expect(callTracker.count()).toEqual(0); callTracker.track(); expect(callTracker.count()).toEqual(1); }); it('tracks the params from each execution', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track({ object: void 0, args: [] }); callTracker.track({ object: {}, args: [0, 'foo'] }); expect(callTracker.argsFor(0)).toEqual([]); expect(callTracker.argsFor(1)).toEqual([0, 'foo']); }); it("tracks the 'this' object from each execution", function() { var callTracker = new jasmineUnderTest.CallTracker(); var this0 = {}, this1 = {}; callTracker.track({ object: this0, args: [] }); callTracker.track({ object: this1, args: [] }); callTracker.track({ args: [] }); expect(callTracker.thisFor(0)).toBe(this0); expect(callTracker.thisFor(1)).toBe(this1); expect(callTracker.thisFor(2)).toBe(undefined); }); it('returns any empty array when there was no call', function() { var callTracker = new jasmineUnderTest.CallTracker(); expect(callTracker.argsFor(0)).toEqual([]); }); it('allows access for the arguments for all calls', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track({ object: {}, args: [] }); callTracker.track({ object: {}, args: [0, 'foo'] }); expect(callTracker.allArgs()).toEqual([[], [0, 'foo']]); }); it('tracks the context and arguments for each call', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track({ object: {}, args: [] }); callTracker.track({ object: {}, args: [0, 'foo'] }); expect(callTracker.all()[0]).toEqual({ object: {}, args: [] }); expect(callTracker.all()[1]).toEqual({ object: {}, args: [0, 'foo'] }); }); it('simplifies access to the arguments for the last (most recent) call', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track(); callTracker.track({ object: {}, args: [0, 'foo'] }); expect(callTracker.mostRecent()).toEqual({ object: {}, args: [0, 'foo'] }); }); it("returns a useful falsy value when there isn't a last (most recent) call", function() { var callTracker = new jasmineUnderTest.CallTracker(); expect(callTracker.mostRecent()).toBeFalsy(); }); it('simplifies access to the arguments for the first (oldest) call', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track({ object: {}, args: [0, 'foo'] }); expect(callTracker.first()).toEqual({ object: {}, args: [0, 'foo'] }); }); it("returns a useful falsy value when there isn't a first (oldest) call", function() { var callTracker = new jasmineUnderTest.CallTracker(); expect(callTracker.first()).toBeFalsy(); }); it('allows the tracking to be reset', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.track(); callTracker.track({ object: {}, args: [0, 'foo'] }); callTracker.reset(); expect(callTracker.any()).toBe(false); expect(callTracker.count()).toEqual(0); expect(callTracker.argsFor(0)).toEqual([]); expect(callTracker.all()).toEqual([]); expect(callTracker.mostRecent()).toBeFalsy(); }); it('allows object arguments to be shallow cloned', function() { var callTracker = new jasmineUnderTest.CallTracker(); callTracker.saveArgumentsByValue(); var objectArg = { foo: 'bar' }, arrayArg = ['foo', 'bar']; callTracker.track({ object: {}, args: [objectArg, arrayArg, false, undefined, null, NaN, '', 0, 1.0] }); expect(callTracker.mostRecent().args[0]).not.toBe(objectArg); expect(callTracker.mostRecent().args[0]).toEqual(objectArg); expect(callTracker.mostRecent().args[1]).not.toBe(arrayArg); expect(callTracker.mostRecent().args[1]).toEqual(arrayArg); }); it('saves primitive arguments by value', function() { var callTracker = new jasmineUnderTest.CallTracker(), args = [undefined, null, false, '', /\s/, 0, 1.2, NaN]; callTracker.saveArgumentsByValue(); callTracker.track({ object: {}, args: args }); expect(callTracker.mostRecent().args).toEqual(args); }); }); jasmine-4.0.0/spec/core/ClearStackSpec.js000066400000000000000000000110551416413636100202170ustar00rootroot00000000000000describe('ClearStack', function() { it('works in an integrationy way', function(done) { var clearStack = jasmineUnderTest.getClearStack( jasmineUnderTest.getGlobal() ); clearStack(function() { done(); }); }); it('uses setImmediate when available', function() { var setImmediate = jasmine .createSpy('setImmediate') .and.callFake(function(fn) { fn(); }), global = { setImmediate: setImmediate }, clearStack = jasmineUnderTest.getClearStack(global), called = false; clearStack(function() { called = true; }); expect(called).toBe(true); expect(setImmediate).toHaveBeenCalled(); }); it('uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU', function() { var setImmediate = jasmine.createSpy('setImmediate'), setTimeout = jasmine.createSpy('setTimeout'), global = { setImmediate: setImmediate, setTimeout: setTimeout }, clearStack = jasmineUnderTest.getClearStack(global); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); expect(setImmediate).toHaveBeenCalled(); expect(setTimeout).not.toHaveBeenCalled(); clearStack(function() {}); expect(setImmediate.calls.count()).toEqual(9); expect(setTimeout.calls.count()).toEqual(1); clearStack(function() {}); expect(setImmediate.calls.count()).toEqual(10); expect(setTimeout.calls.count()).toEqual(1); }); it('uses MessageChannels when available', function() { var fakeChannel = { port1: {}, port2: { postMessage: function() { fakeChannel.port1.onmessage(); } } }, global = { MessageChannel: function() { return fakeChannel; } }, clearStack = jasmineUnderTest.getClearStack(global), called = false; clearStack(function() { called = true; }); expect(called).toBe(true); }); it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() { var fakeChannel = { port1: {}, port2: { postMessage: jasmine .createSpy('postMessage') .and.callFake(function() { fakeChannel.port1.onmessage(); }) } }, setTimeout = jasmine.createSpy('setTimeout'), global = { MessageChannel: function() { return fakeChannel; }, setTimeout: setTimeout }, clearStack = jasmineUnderTest.getClearStack(global); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); clearStack(function() {}); expect(fakeChannel.port2.postMessage).toHaveBeenCalled(); expect(setTimeout).not.toHaveBeenCalled(); clearStack(function() {}); expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9); expect(setTimeout.calls.count()).toEqual(1); clearStack(function() {}); expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10); expect(setTimeout.calls.count()).toEqual(1); }); it('calls setTimeout when onmessage is called recursively', function() { var fakeChannel = { port1: {}, port2: { postMessage: function() { fakeChannel.port1.onmessage(); } } }, setTimeout = jasmine.createSpy('setTimeout'), global = { MessageChannel: function() { return fakeChannel; }, setTimeout: setTimeout }, clearStack = jasmineUnderTest.getClearStack(global), fn = jasmine.createSpy('second clearStack function'); clearStack(function() { clearStack(fn); }); expect(fn).not.toHaveBeenCalled(); expect(setTimeout).toHaveBeenCalledWith(fn, 0); }); it('falls back to setTimeout', function() { var setTimeout = jasmine.createSpy('setTimeout').and.callFake(function(fn) { fn(); }), global = { setTimeout: setTimeout }, clearStack = jasmineUnderTest.getClearStack(global), called = false; clearStack(function() { called = true; }); expect(called).toBe(true); expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 0); }); }); jasmine-4.0.0/spec/core/ClockSpec.js000066400000000000000000000763751416413636100172560ustar00rootroot00000000000000describe('Clock', function() { var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string'; it('does not replace setTimeout until it is installed', function() { var fakeSetTimeout = jasmine.createSpy('global setTimeout'), fakeGlobal = { setTimeout: fakeSetTimeout }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['scheduleFunction'] ), delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); fakeGlobal.setTimeout(delayedFn, 0); expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0); expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled(); fakeSetTimeout.calls.reset(); clock.install(); fakeGlobal.setTimeout(delayedFn, 0); expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled(); expect(fakeSetTimeout).not.toHaveBeenCalled(); }); it('does not replace clearTimeout until it is installed', function() { var fakeClearTimeout = jasmine.createSpy('global cleartimeout'), fakeGlobal = { clearTimeout: fakeClearTimeout }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['removeFunctionWithId'] ), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); fakeGlobal.clearTimeout('foo'); expect(fakeClearTimeout).toHaveBeenCalledWith('foo'); expect( delayedFunctionScheduler.removeFunctionWithId ).not.toHaveBeenCalled(); fakeClearTimeout.calls.reset(); clock.install(); fakeGlobal.clearTimeout('foo'); expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled(); expect(fakeClearTimeout).not.toHaveBeenCalled(); }); it('does not replace setInterval until it is installed', function() { var fakeSetInterval = jasmine.createSpy('global setInterval'), fakeGlobal = { setInterval: fakeSetInterval }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['scheduleFunction'] ), delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); fakeGlobal.setInterval(delayedFn, 0); expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 0); expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled(); fakeSetInterval.calls.reset(); clock.install(); fakeGlobal.setInterval(delayedFn, 0); expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled(); expect(fakeSetInterval).not.toHaveBeenCalled(); }); it('does not replace clearInterval until it is installed', function() { var fakeClearInterval = jasmine.createSpy('global clearinterval'), fakeGlobal = { clearInterval: fakeClearInterval }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['removeFunctionWithId'] ), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); fakeGlobal.clearInterval('foo'); expect(fakeClearInterval).toHaveBeenCalledWith('foo'); expect( delayedFunctionScheduler.removeFunctionWithId ).not.toHaveBeenCalled(); fakeClearInterval.calls.reset(); clock.install(); fakeGlobal.clearInterval('foo'); expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled(); expect(fakeClearInterval).not.toHaveBeenCalled(); }); it('does not install if the current setTimeout is not the original function on the global', function() { var originalFakeSetTimeout = function() {}, replacedSetTimeout = function() {}, fakeGlobal = { setTimeout: originalFakeSetTimeout }, delayedFunctionSchedulerFactory = jasmine.createSpy( 'delayedFunctionSchedulerFactory' ), mockDate = {}, clock = new jasmineUnderTest.Clock( fakeGlobal, delayedFunctionSchedulerFactory, mockDate ); fakeGlobal.setTimeout = replacedSetTimeout; expect(function() { clock.install(); }).toThrowError(/unable to install/); expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled(); expect(fakeGlobal.setTimeout).toBe(replacedSetTimeout); }); it('does not install if the current clearTimeout is not the original function on the global', function() { var originalFakeClearTimeout = function() {}, replacedClearTimeout = function() {}, fakeGlobal = { clearTimeout: originalFakeClearTimeout }, delayedFunctionSchedulerFactory = jasmine.createSpy( 'delayedFunctionSchedulerFactory' ), mockDate = {}, clock = new jasmineUnderTest.Clock( fakeGlobal, delayedFunctionSchedulerFactory, mockDate ); fakeGlobal.clearTimeout = replacedClearTimeout; expect(function() { clock.install(); }).toThrowError(/unable to install/); expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled(); expect(fakeGlobal.clearTimeout).toBe(replacedClearTimeout); }); it('does not install if the current setInterval is not the original function on the global', function() { var originalFakeSetInterval = function() {}, replacedSetInterval = function() {}, fakeGlobal = { setInterval: originalFakeSetInterval }, delayedFunctionSchedulerFactory = jasmine.createSpy( 'delayedFunctionSchedulerFactory' ), mockDate = {}, clock = new jasmineUnderTest.Clock( fakeGlobal, delayedFunctionSchedulerFactory, mockDate ); fakeGlobal.setInterval = replacedSetInterval; expect(function() { clock.install(); }).toThrowError(/unable to install/); expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled(); expect(fakeGlobal.setInterval).toBe(replacedSetInterval); }); it('does not install if the current clearInterval is not the original function on the global', function() { var originalFakeClearInterval = function() {}, replacedClearInterval = function() {}, fakeGlobal = { clearInterval: originalFakeClearInterval }, delayedFunctionSchedulerFactory = jasmine.createSpy( 'delayedFunctionSchedulerFactory' ), mockDate = {}, clock = new jasmineUnderTest.Clock( fakeGlobal, delayedFunctionSchedulerFactory, mockDate ); fakeGlobal.clearInterval = replacedClearInterval; expect(function() { clock.install(); }).toThrowError(/unable to install/); expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled(); expect(fakeGlobal.clearInterval).toBe(replacedClearInterval); }); it('replaces the global timer functions on uninstall', function() { var fakeSetTimeout = jasmine.createSpy('global setTimeout'), fakeClearTimeout = jasmine.createSpy('global clearTimeout'), fakeSetInterval = jasmine.createSpy('global setInterval'), fakeClearInterval = jasmine.createSpy('global clearInterval'), fakeGlobal = { setTimeout: fakeSetTimeout, clearTimeout: fakeClearTimeout, setInterval: fakeSetInterval, clearInterval: fakeClearInterval }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['scheduleFunction', 'reset'] ), delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); clock.uninstall(); fakeGlobal.setTimeout(delayedFn, 0); fakeGlobal.clearTimeout('foo'); fakeGlobal.setInterval(delayedFn, 10); fakeGlobal.clearInterval('bar'); expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0); expect(fakeClearTimeout).toHaveBeenCalledWith('foo'); expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10); expect(fakeClearInterval).toHaveBeenCalledWith('bar'); expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled(); }); it('can be installed for the duration of a passed in function and uninstalled when done', function() { var fakeSetTimeout = jasmine.createSpy('global setTimeout'), fakeClearTimeout = jasmine.createSpy('global clearTimeout'), fakeSetInterval = jasmine.createSpy('global setInterval'), fakeClearInterval = jasmine.createSpy('global clearInterval'), fakeGlobal = { setTimeout: fakeSetTimeout, clearTimeout: fakeClearTimeout, setInterval: fakeSetInterval, clearInterval: fakeClearInterval }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['scheduleFunction', 'reset', 'removeFunctionWithId'] ), delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), passedFunctionCalled = false; clock.withMock(function() { fakeGlobal.setTimeout(delayedFn, 0); fakeGlobal.clearTimeout('foo'); fakeGlobal.setInterval(delayedFn, 10); fakeGlobal.clearInterval('bar'); passedFunctionCalled = true; }); expect(passedFunctionCalled).toBe(true); expect(fakeSetTimeout).not.toHaveBeenCalled(); expect(fakeClearTimeout).not.toHaveBeenCalled(); expect(fakeSetInterval).not.toHaveBeenCalled(); expect(fakeClearInterval).not.toHaveBeenCalled(); expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled(); delayedFunctionScheduler.scheduleFunction.calls.reset(); fakeGlobal.setTimeout(delayedFn, 0); fakeGlobal.clearTimeout('foo'); fakeGlobal.setInterval(delayedFn, 10); fakeGlobal.clearInterval('bar'); expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0); expect(fakeClearTimeout).toHaveBeenCalledWith('foo'); expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10); expect(fakeClearInterval).toHaveBeenCalledWith('bar'); expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled(); }); it('can be installed for the duration of a passed in function and uninstalled if an error is thrown', function() { var fakeSetTimeout = jasmine.createSpy('global setTimeout'), fakeClearTimeout = jasmine.createSpy('global clearTimeout'), fakeSetInterval = jasmine.createSpy('global setInterval'), fakeClearInterval = jasmine.createSpy('global clearInterval'), fakeGlobal = { setTimeout: fakeSetTimeout, clearTimeout: fakeClearTimeout, setInterval: fakeSetInterval, clearInterval: fakeClearInterval }, delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['scheduleFunction', 'reset', 'removeFunctionWithId'] ), delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), passedFunctionCalled = false; expect(function() { clock.withMock(function() { fakeGlobal.setTimeout(delayedFn, 0); fakeGlobal.clearTimeout('foo'); fakeGlobal.setInterval(delayedFn, 10); fakeGlobal.clearInterval('bar'); passedFunctionCalled = true; throw 'oops'; }); }).toThrow('oops'); expect(passedFunctionCalled).toBe(true); expect(fakeSetTimeout).not.toHaveBeenCalled(); expect(fakeClearTimeout).not.toHaveBeenCalled(); expect(fakeSetInterval).not.toHaveBeenCalled(); expect(fakeClearInterval).not.toHaveBeenCalled(); expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled(); delayedFunctionScheduler.scheduleFunction.calls.reset(); fakeGlobal.setTimeout(delayedFn, 0); fakeGlobal.clearTimeout('foo'); fakeGlobal.setInterval(delayedFn, 10); fakeGlobal.clearInterval('bar'); expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0); expect(fakeClearTimeout).toHaveBeenCalledWith('foo'); expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10); expect(fakeClearInterval).toHaveBeenCalledWith('bar'); expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled(); }); it('schedules the delayed function (via setTimeout) with the fake timer', function() { var fakeSetTimeout = jasmine.createSpy('setTimeout'), scheduleFunction = jasmine.createSpy('scheduleFunction'), delayedFunctionScheduler = { scheduleFunction: scheduleFunction }, fakeGlobal = { setTimeout: fakeSetTimeout }, delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), timeout = new clock.FakeTimeout(); clock.install(); clock.setTimeout(delayedFn, 0, 'a', 'b'); expect(fakeSetTimeout).not.toHaveBeenCalled(); if (!NODE_JS) { expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith( delayedFn, 0, ['a', 'b'] ); } else { expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith( delayedFn, 0, ['a', 'b'], false, timeout ); } }); it('returns an id for the delayed function', function() { var fakeSetTimeout = jasmine.createSpy('setTimeout'), scheduleId = 123, scheduleFunction = jasmine .createSpy('scheduleFunction') .and.returnValue(scheduleId), delayedFunctionScheduler = { scheduleFunction: scheduleFunction }, fakeGlobal = { setTimeout: fakeSetTimeout }, delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), timeout; clock.install(); timeout = clock.setTimeout(delayedFn, 0); if (!NODE_JS) { expect(timeout).toEqual(123); } else { expect(timeout.constructor.name).toEqual('FakeTimeout'); } }); it('clears the scheduled function with the scheduler', function() { var fakeClearTimeout = jasmine.createSpy('clearTimeout'), delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['removeFunctionWithId'] ), fakeGlobal = { setTimeout: fakeClearTimeout }, mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); clock.clearTimeout(123); expect(fakeClearTimeout).not.toHaveBeenCalled(); expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalledWith( 123 ); }); it('schedules the delayed function with the fake timer', function() { var fakeSetInterval = jasmine.createSpy('setInterval'), scheduleFunction = jasmine.createSpy('scheduleFunction'), delayedFunctionScheduler = { scheduleFunction: scheduleFunction }, fakeGlobal = { setInterval: fakeSetInterval }, delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), timeout = new clock.FakeTimeout(); clock.install(); clock.setInterval(delayedFn, 0, 'a', 'b'); expect(fakeSetInterval).not.toHaveBeenCalled(); if (!NODE_JS) { expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith( delayedFn, 0, ['a', 'b'], true ); } else { expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith( delayedFn, 0, ['a', 'b'], true, timeout ); } }); it('returns an id for the delayed function', function() { var fakeSetInterval = jasmine.createSpy('setInterval'), scheduleId = 123, scheduleFunction = jasmine .createSpy('scheduleFunction') .and.returnValue(scheduleId), delayedFunctionScheduler = { scheduleFunction: scheduleFunction }, fakeGlobal = { setInterval: fakeSetInterval }, delayedFn = jasmine.createSpy('delayedFn'), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ), interval; clock.install(); interval = clock.setInterval(delayedFn, 0); if (!NODE_JS) { expect(interval).toEqual(123); } else { expect(interval.constructor.name).toEqual('FakeTimeout'); } }); it('clears the scheduled function with the scheduler', function() { var clearInterval = jasmine.createSpy('clearInterval'), delayedFunctionScheduler = jasmine.createSpyObj( 'delayedFunctionScheduler', ['removeFunctionWithId'] ), fakeGlobal = { setInterval: clearInterval }, mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( fakeGlobal, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); clock.clearInterval(123); expect(clearInterval).not.toHaveBeenCalled(); expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalledWith( 123 ); }); it('gives you a friendly reminder if the Clock is not installed and you tick', function() { var clock = new jasmineUnderTest.Clock( {}, jasmine.createSpyObj('delayedFunctionScheduler', ['tick']) ); expect(function() { clock.tick(50); }).toThrow(); }); }); describe('Clock (acceptance)', function() { it('can run setTimeouts/setIntervals synchronously', function() { var delayedFn1 = jasmine.createSpy('delayedFn1'), delayedFn2 = jasmine.createSpy('delayedFn2'), delayedFn3 = jasmine.createSpy('delayedFn3'), recurring1 = jasmine.createSpy('recurring1'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); clock.setTimeout(delayedFn1, 0); var intervalId = clock.setInterval(recurring1, 50); clock.setTimeout(delayedFn2, 100); clock.setTimeout(delayedFn3, 200); expect(delayedFn1).not.toHaveBeenCalled(); expect(delayedFn2).not.toHaveBeenCalled(); expect(delayedFn3).not.toHaveBeenCalled(); clock.tick(0); expect(delayedFn1).toHaveBeenCalled(); expect(delayedFn2).not.toHaveBeenCalled(); expect(delayedFn3).not.toHaveBeenCalled(); clock.tick(50); expect(recurring1).toHaveBeenCalled(); expect(recurring1.calls.count()).toBe(1); expect(delayedFn2).not.toHaveBeenCalled(); expect(delayedFn3).not.toHaveBeenCalled(); clock.tick(50); expect(recurring1.calls.count()).toBe(2); expect(delayedFn2).toHaveBeenCalled(); expect(delayedFn3).not.toHaveBeenCalled(); clock.tick(100); expect(recurring1.calls.count()).toBe(4); expect(delayedFn3).toHaveBeenCalled(); clock.clearInterval(intervalId); clock.tick(50); expect(recurring1.calls.count()).toBe(4); }); it('can clear a previously set timeout', function() { var clearedFn = jasmine.createSpy('clearedFn'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ), timeoutId; clock.install(); timeoutId = clock.setTimeout(clearedFn, 100); expect(clearedFn).not.toHaveBeenCalled(); clock.clearTimeout(timeoutId); clock.tick(100); expect(clearedFn).not.toHaveBeenCalled(); }); it("can clear a previously set interval using that interval's handler", function() { var spy = jasmine.createSpy('spy'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setInterval: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ), intervalId; clock.install(); intervalId = clock.setInterval(function() { spy(); clock.clearInterval(intervalId); }, 100); clock.tick(200); expect(spy.calls.count()).toEqual(1); }); it('correctly schedules functions after the Clock has advanced', function() { var delayedFn1 = jasmine.createSpy('delayedFn1'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); clock.tick(100); clock.setTimeout(delayedFn1, 10, ['some', 'arg']); clock.tick(5); expect(delayedFn1).not.toHaveBeenCalled(); clock.tick(5); expect(delayedFn1).toHaveBeenCalled(); }); it('correctly schedules functions while the Clock is advancing', function() { var delayedFn1 = jasmine.createSpy('delayedFn1'), delayedFn2 = jasmine.createSpy('delayedFn2'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ); delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 0); }); clock.install(); clock.setTimeout(delayedFn1, 5); clock.tick(5); expect(delayedFn1).toHaveBeenCalled(); expect(delayedFn2).not.toHaveBeenCalled(); clock.tick(); expect(delayedFn2).toHaveBeenCalled(); }); it('correctly calls functions scheduled while the Clock is advancing', function() { var delayedFn1 = jasmine.createSpy('delayedFn1'), delayedFn2 = jasmine.createSpy('delayedFn2'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ); delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 1); }); clock.install(); clock.setTimeout(delayedFn1, 5); clock.tick(6); expect(delayedFn1).toHaveBeenCalled(); expect(delayedFn2).toHaveBeenCalled(); }); it('correctly schedules functions scheduled while the Clock is advancing but after the Clock is uninstalled', function() { var delayedFn1 = jasmine.createSpy('delayedFn1'), delayedFn2 = jasmine.createSpy('delayedFn2'), delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} }, clock = new jasmineUnderTest.Clock( { setTimeout: function() {} }, function() { return delayedFunctionScheduler; }, mockDate ); delayedFn1.and.callFake(function() { clock.uninstall(); clock.install(); clock.setTimeout(delayedFn2, 0); }); clock.install(); clock.setTimeout(delayedFn1, 1); clock.tick(1); expect(delayedFn1).toHaveBeenCalled(); expect(delayedFn2).not.toHaveBeenCalled(); clock.tick(1); expect(delayedFn2).toHaveBeenCalled(); }); it('does not mock the Date object by default', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); expect(global.Date).toEqual(Date); var now = new global.Date().getTime(); clock.tick(50); expect(new global.Date().getTime() - now).not.toEqual(50); }); it('mocks the Date object and sets it to current time', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ); clock.install().mockDate(); var now = new global.Date().getTime(); clock.tick(50); expect(new global.Date().getTime() - now).toEqual(50); var timeoutDate = 0; clock.setTimeout(function() { timeoutDate = new global.Date().getTime(); }, 100); clock.tick(100); expect(timeoutDate - now).toEqual(150); }); it('mocks the Date object and sets it to a given time', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ), baseTime = new Date(2013, 9, 23); clock.install().mockDate(baseTime); var now = new global.Date().getTime(); expect(now).toEqual(baseTime.getTime()); clock.tick(50); expect(new global.Date().getTime()).toEqual(baseTime.getTime() + 50); var timeoutDate = 0; clock.setTimeout(function() { timeoutDate = new global.Date().getTime(); }, 100); clock.tick(100); expect(timeoutDate).toEqual(baseTime.getTime() + 150); }); it('throws mockDate is called with a non-Date', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ), env = jasmineUnderTest.getEnv(); expect(() => clock.mockDate(12345)).toThrowError( 'The argument to jasmine.clock().mockDate(), if specified, should be ' + 'a Date instance.' ); }); it('mocks the Date object and updates the date per delayed function', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( { setTimeout: setTimeout }, function() { return delayedFunctionScheduler; }, mockDate ), baseTime = new Date(); clock.install().mockDate(baseTime); var actualTimes = []; var pushCurrentTime = function() { actualTimes.push(global.Date().getTime()); }; delayedFunctionScheduler.scheduleFunction(pushCurrentTime); delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 1); delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 3); clock.tick(1); expect(global.Date().getTime()).toEqual(baseTime.getTime() + 1); clock.tick(3); expect(global.Date().getTime()).toEqual(baseTime.getTime() + 4); clock.tick(1); expect(global.Date().getTime()).toEqual(baseTime.getTime() + 5); expect(actualTimes).toEqual([ baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3 ]); }); it('correctly clears a scheduled timeout while the Clock is advancing', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date, setTimeout: undefined }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( global, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); var timerId2; global.setTimeout(function() { global.clearTimeout(timerId2); }, 100); timerId2 = global.setTimeout(fail, 100); clock.tick(100); }); it('correctly clears a scheduled interval while the Clock is advancing', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date, setTimeout: undefined }, mockDate = new jasmineUnderTest.MockDate(global), clock = new jasmineUnderTest.Clock( global, function() { return delayedFunctionScheduler; }, mockDate ); clock.install(); var timerId2; global.setInterval(function() { global.clearInterval(timerId2); }, 100); timerId2 = global.setInterval(fail, 100); clock.tick(400); }); }); jasmine-4.0.0/spec/core/CompleteOnFirstErrorSkipPolicySpec.js000066400000000000000000000073051416413636100243040ustar00rootroot00000000000000describe('CompleteOnFirstErrorSkipPolicy', function() { describe('#skipTo', function() { describe('Before anything has errored', function() { it('returns the next index', function() { const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( arrayOfArbitraryFns(4), 4 ); expect(policy.skipTo(1)).toEqual(2); }); }); describe('After something has errored', function() { it('skips non cleanup fns', function() { const fns = arrayOfArbitraryFns(4); fns[2].type = arbitraryCleanupType(); fns[3].type = arbitraryCleanupType(); const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(2); expect(policy.skipTo(2)).toEqual(3); expect(policy.skipTo(3)).toEqual(4); }); for (const type of ['afterEach', 'specCleanup', 'afterAll']) { it(`does not skip ${type} fns`, function() { const fns = arrayOfArbitraryFns(2); fns[1].type = type; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( fns ); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); }); } describe('When the error was in a beforeEach fn', function() { it('runs cleanup fns defined by the current and containing suites', function() { const parentSuite = { description: 'parentSuite' }; const suite = { description: 'suite', parentSuite }; const fns = [ { suite: suite }, { fn: () => {} }, { fn: () => {}, suite: suite, type: arbitraryCleanupType() }, { fn: () => {}, suite: parentSuite, type: arbitraryCleanupType() } ]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( fns ); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(2); expect(policy.skipTo(2)).toEqual(3); }); it('skips cleanup fns defined by nested suites', function() { const parentSuite = { description: 'parentSuite' }; const suite = { description: 'suite', parentSuite }; const fns = [ { fn: () => {}, type: 'beforeEach', suite: parentSuite }, { fn: () => {} }, { fn: () => {}, suite: suite, type: arbitraryCleanupType() }, { fn: () => {}, suite: parentSuite, type: arbitraryCleanupType() } ]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( fns ); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(3); }); }); it('does not skip cleanup fns that have no suite, such as the spec complete fn', function() { const fns = [ { fn: () => {} }, { fn: () => {}, type: arbitraryCleanupType() } ]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); }); }); }); function arrayOfArbitraryFns(n) { const result = []; for (let i = 0; i < n; i++) { result.push({ fn: () => {} }); } return result; } function arbitraryCleanupType() { return 'specCleanup'; } }); jasmine-4.0.0/spec/core/DelayedFunctionSchedulerSpec.js000066400000000000000000000230031416413636100231130ustar00rootroot00000000000000describe('DelayedFunctionScheduler', function() { it('schedules a function for later execution', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'); scheduler.scheduleFunction(fn, 0); expect(fn).not.toHaveBeenCalled(); scheduler.tick(0); expect(fn).toHaveBeenCalled(); }); it('schedules a string for later execution', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), strfn = 'horrible = true;'; scheduler.scheduleFunction(strfn, 0); scheduler.tick(0); expect(horrible).toEqual(true); }); it('#tick defaults to 0', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'); scheduler.scheduleFunction(fn, 0); expect(fn).not.toHaveBeenCalled(); scheduler.tick(); expect(fn).toHaveBeenCalled(); }); it('defaults delay to 0', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'); scheduler.scheduleFunction(fn); expect(fn).not.toHaveBeenCalled(); scheduler.tick(0); expect(fn).toHaveBeenCalled(); }); it('optionally passes params to scheduled functions', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'); scheduler.scheduleFunction(fn, 0, ['foo', 'bar']); expect(fn).not.toHaveBeenCalled(); scheduler.tick(0); expect(fn).toHaveBeenCalledWith('foo', 'bar'); }); it('scheduled fns can optionally reoccur', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'); scheduler.scheduleFunction(fn, 20, [], true); expect(fn).not.toHaveBeenCalled(); scheduler.tick(20); expect(fn.calls.count()).toBe(1); scheduler.tick(40); expect(fn.calls.count()).toBe(3); scheduler.tick(21); expect(fn.calls.count()).toBe(4); }); it('increments scheduled fns ids unless one is passed', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(); expect(scheduler.scheduleFunction(function() {}, 0)).toBe(1); expect(scheduler.scheduleFunction(function() {}, 0)).toBe(2); expect(scheduler.scheduleFunction(function() {}, 0, [], false, 123)).toBe( 123 ); expect(scheduler.scheduleFunction(function() {}, 0)).toBe(3); }); it('#removeFunctionWithId removes a previously scheduled function with a given id', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), timeoutKey; timeoutKey = scheduler.scheduleFunction(fn, 0); expect(fn).not.toHaveBeenCalled(); scheduler.removeFunctionWithId(timeoutKey); scheduler.tick(0); expect(fn).not.toHaveBeenCalled(); }); it('executes recurring functions interleaved with regular functions in the correct order', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), recurringCallCount = 0, recurring = jasmine.createSpy('recurring').and.callFake(function() { recurringCallCount++; if (recurringCallCount < 5) { expect(fn).not.toHaveBeenCalled(); } }); scheduler.scheduleFunction(recurring, 10, [], true); scheduler.scheduleFunction(fn, 50); scheduler.tick(60); expect(recurring).toHaveBeenCalled(); expect(recurring.calls.count()).toBe(6); expect(fn).toHaveBeenCalled(); }); it('schedules a function for later execution during a tick', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10; scheduler.scheduleFunction(function() { scheduler.scheduleFunction(fn, fnDelay); }, 0); expect(fn).not.toHaveBeenCalled(); scheduler.tick(fnDelay); expect(fn).toHaveBeenCalled(); }); it('#removeFunctionWithId removes a previously scheduled function with a given id during a tick', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10, timeoutKey; scheduler.scheduleFunction(function() { scheduler.removeFunctionWithId(timeoutKey); }, 0); timeoutKey = scheduler.scheduleFunction(fn, fnDelay); expect(fn).not.toHaveBeenCalled(); scheduler.tick(fnDelay); expect(fn).not.toHaveBeenCalled(); }); it('executes recurring functions interleaved with regular functions and functions scheduled during a tick in the correct order', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), recurringCallCount = 0, recurring = jasmine.createSpy('recurring').and.callFake(function() { recurringCallCount++; if (recurringCallCount < 5) { expect(fn).not.toHaveBeenCalled(); } }), innerFn = jasmine.createSpy('innerFn').and.callFake(function() { expect(recurring.calls.count()).toBe(4); expect(fn).not.toHaveBeenCalled(); }), scheduling = jasmine.createSpy('scheduling').and.callFake(function() { expect(recurring.calls.count()).toBe(3); expect(fn).not.toHaveBeenCalled(); scheduler.scheduleFunction(innerFn, 10); // 41ms absolute }); scheduler.scheduleFunction(recurring, 10, [], true); scheduler.scheduleFunction(fn, 50); scheduler.scheduleFunction(scheduling, 31); scheduler.tick(60); expect(recurring).toHaveBeenCalled(); expect(recurring.calls.count()).toBe(6); expect(fn).toHaveBeenCalled(); expect(scheduling).toHaveBeenCalled(); expect(innerFn).toHaveBeenCalled(); }); it('executes recurring functions after rescheduling them', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), recurring = function() { expect(scheduler.scheduleFunction).toHaveBeenCalled(); }; scheduler.scheduleFunction(recurring, 10, [], true); spyOn(scheduler, 'scheduleFunction'); scheduler.tick(10); }); it('removes functions during a tick that runs the function', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), spy = jasmine.createSpy('fn'), spyAndRemove = jasmine.createSpy('fn'), fnDelay = 10, timeoutKey; spyAndRemove.and.callFake(function() { scheduler.removeFunctionWithId(timeoutKey); }); scheduler.scheduleFunction(spyAndRemove, fnDelay); timeoutKey = scheduler.scheduleFunction(spy, fnDelay, [], true); scheduler.tick(2 * fnDelay); expect(spy).not.toHaveBeenCalled(); expect(spyAndRemove).toHaveBeenCalled(); }); it('removes functions during the first tick that runs the function', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10, timeoutKey; timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true); scheduler.scheduleFunction(function() { scheduler.removeFunctionWithId(timeoutKey); }, fnDelay); expect(fn).not.toHaveBeenCalled(); scheduler.tick(3 * fnDelay); expect(fn).toHaveBeenCalled(); expect(fn.calls.count()).toBe(1); }); it("does not remove a function that hasn't been added yet", function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10; scheduler.removeFunctionWithId('foo'); scheduler.scheduleFunction(fn, fnDelay, [], false, 'foo'); expect(fn).not.toHaveBeenCalled(); scheduler.tick(fnDelay + 1); expect(fn).toHaveBeenCalled(); }); it('updates the mockDate per scheduled time', function() { var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), tickDate = jasmine.createSpy('tickDate'); scheduler.scheduleFunction(function() {}); scheduler.scheduleFunction(function() {}, 1); scheduler.tick(1, tickDate); expect(tickDate).toHaveBeenCalledWith(0); expect(tickDate).toHaveBeenCalledWith(1); }); describe('ticking inside a scheduled function', function() { let clock; // Runner function calls the callback until it returns false function runWork(workCallback) { while (workCallback()) {} } // Make a worker that takes a little time and tracks when it finished function mockWork(times) { return () => { clock.tick(1); const now = new Date().getTime(); expect(lastWork) .withContext('Previous function calls should always be in the past') .toBeLessThan(now); lastWork = now; times--; return times > 0; }; } let lastWork = 0; beforeEach(() => { clock = jasmineUnderTest.getEnv().clock; clock.install(); clock.mockDate(new Date(1)); }); afterEach(function() { jasmineUnderTest.getEnv().clock.uninstall(); }); it('preserves monotonically-increasing current time', () => { const work1 = mockWork(3); setTimeout(() => { runWork(work1); }, 1); clock.tick(1); expect(lastWork) .withContext('tick should advance past last-scheduled function') .toBeLessThanOrEqual(new Date().getTime()); const work2 = mockWork(3); setTimeout(() => { runWork(work2); }, 1); clock.tick(1); expect(lastWork) .withContext('tick should advance past last-scheduled function') .toBeLessThanOrEqual(new Date().getTime()); }); }); }); jasmine-4.0.0/spec/core/DeprecatorSpec.js000066400000000000000000000263251416413636100203010ustar00rootroot00000000000000/* eslint no-console: 0 */ describe('Deprecator', function() { describe('#deprecate', function() { beforeEach(function() { spyOn(console, 'error'); }); it('logs the mesage without context when the runnable is the top suite', function() { var runnable = { addDeprecationWarning: function() {} }; var deprecator = new jasmineUnderTest.Deprecator(runnable); deprecator.verboseDeprecations(true); deprecator.addDeprecationWarning(runnable, 'the message', { omitStackTrace: true }); expect(console.error).toHaveBeenCalledWith('DEPRECATION: the message'); }); it('logs the message in a descendant suite', function() { var runnable = { addDeprecationWarning: function() {}, getFullName: function() { return 'the suite'; }, children: [] }; var deprecator = new jasmineUnderTest.Deprecator({}); deprecator.verboseDeprecations(true); deprecator.addDeprecationWarning(runnable, 'the message', { omitStackTrace: true }); expect(console.error).toHaveBeenCalledWith( 'DEPRECATION: the message (in suite: the suite)' ); }); it('logs and reports the message in a spec', function() { var runnable = { addDeprecationWarning: function() {}, getFullName: function() { return 'the spec'; } }; var deprecator = new jasmineUnderTest.Deprecator({}); deprecator.verboseDeprecations(true); deprecator.addDeprecationWarning(runnable, 'the message', { omitStackTrace: true }); expect(console.error).toHaveBeenCalledWith( 'DEPRECATION: the message (in spec: the spec)' ); }); it('logs and reports the message without runnable info when ignoreRunnable is true', function() { var topSuite = jasmine.createSpyObj('topSuite', [ 'addDeprecationWarning', 'getFullName' ]); var deprecator = new jasmineUnderTest.Deprecator(topSuite); var runnable = jasmine.createSpyObj('spec', [ 'addDeprecationWarning', 'getFullName' ]); runnable.getFullName.and.returnValue('a spec'); deprecator.addDeprecationWarning(runnable, 'the message', { ignoreRunnable: true }); expect(topSuite.addDeprecationWarning).toHaveBeenCalledWith( jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ); expect(runnable.addDeprecationWarning).not.toHaveBeenCalled(); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching(/the message/) ); expect(console.error).not.toHaveBeenCalledWith( jasmine.stringMatching(/a spec/) ); }); describe('with no options', function() { it('includes the stack trace', function() { testStackTrace(undefined); }); }); it('omits the stack trace when omitStackTrace is true', function() { testNoStackTrace({ omitStackTrace: true }); }); it('includes the stack trace when omitStackTrace is false', function() { testStackTrace({ omitStackTrace: false }); }); it('includes the stack trace when omitStackTrace is undefined', function() { testStackTrace({ includeStackTrace: undefined }); }); it('emits the deprecation only once when verboseDeprecations is not set', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable1 = jasmine.createSpyObj('runnable1', [ 'addDeprecationWarning', 'getFullName' ]); var runnable2 = jasmine.createSpyObj('runnable2', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable2, 'the message'); expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(1); expect(runnable2.addDeprecationWarning).not.toHaveBeenCalled(); }); it('emits the deprecation only once when verboseDeprecations is false', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable1 = jasmine.createSpyObj('runnable1', [ 'addDeprecationWarning', 'getFullName' ]); var runnable2 = jasmine.createSpyObj('runnable2', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.verboseDeprecations(false); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable2, 'the message'); expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(1); expect(runnable2.addDeprecationWarning).not.toHaveBeenCalled(); }); it('emits the deprecation for each call when verboseDeprecations is true', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable1 = jasmine.createSpyObj('runnable1', [ 'addDeprecationWarning', 'getFullName' ]); var runnable2 = jasmine.createSpyObj('runnable2', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.verboseDeprecations(true); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable1, 'the message'); deprecator.addDeprecationWarning(runnable2, 'the message'); expect(runnable1.addDeprecationWarning).toHaveBeenCalledTimes(2); expect(runnable2.addDeprecationWarning).toHaveBeenCalled(); }); it('includes a note about verboseDeprecations', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.addDeprecationWarning(runnable, 'the message'); expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1); expect( runnable.addDeprecationWarning.calls.argsFor(0)[0].message ).toContain(verboseDeprecationsNote()); expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).toContain( verboseDeprecationsNote() ); }); it('omits the note about verboseDeprecations when verboseDeprecations is true', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.verboseDeprecations(true); deprecator.addDeprecationWarning(runnable, 'the message'); expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1); expect( runnable.addDeprecationWarning.calls.argsFor(0)[0].message ).not.toContain(verboseDeprecationsNote()); expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).not.toContain( verboseDeprecationsNote() ); }); describe('When the deprecation is an Error', function() { // This form is used by external systems like atom-jasmine3-test-runner // to report their own deprecations through Jasmine. See // . it('passes the error through unchanged', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(); var deprecation, originalStack; try { throw new Error('the deprecation'); } catch (err) { deprecation = err; originalStack = err.stack; } deprecator.addDeprecationWarning(runnable, deprecation); expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1); expect( runnable.addDeprecationWarning.calls.argsFor(0)[0].message ).toEqual('the deprecation'); expect(runnable.addDeprecationWarning.calls.argsFor(0)[0].stack).toBe( originalStack ); expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0].message).toEqual( 'the deprecation' ); expect(console.error.calls.argsFor(0)[0].stack).toEqual(originalStack); }); it('reports the deprecation every time, regardless of config.verboseDeprecations', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); var deprecation; try { throw new Error('the deprecation'); } catch (err) { deprecation = err; } deprecator.addDeprecationWarning(runnable, deprecation); deprecator.addDeprecationWarning(runnable, deprecation); expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(2); expect(console.error).toHaveBeenCalledTimes(2); }); it('omits the note about verboseDeprecations', function() { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); var deprecation; try { throw new Error('the deprecation'); } catch (err) { deprecation = err; } deprecator.addDeprecationWarning(runnable, deprecation); expect(runnable.addDeprecationWarning).toHaveBeenCalledTimes(1); expect( runnable.addDeprecationWarning.calls.argsFor(0)[0].message ).not.toContain(verboseDeprecationsNote()); expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).not.toContain( verboseDeprecationsNote() ); }); }); function verboseDeprecationsNote() { return ( 'Note: This message will be shown only once. Set the ' + 'verboseDeprecations config property to true to see every occurrence.' ); } function testStackTrace(options) { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.addDeprecationWarning(runnable, 'the message', options); expect(runnable.addDeprecationWarning).toHaveBeenCalledWith({ message: jasmine.stringMatching(/^the message/), omitStackTrace: false }); expect(console.error).toHaveBeenCalledTimes(1); expect(console.error.calls.argsFor(0)[0]).toContain('the message'); expect(console.error.calls.argsFor(0)[0]).toContain('DeprecatorSpec.js'); } function testNoStackTrace(options) { var deprecator = new jasmineUnderTest.Deprecator({}); var runnable = jasmine.createSpyObj('runnable', [ 'addDeprecationWarning', 'getFullName' ]); deprecator.addDeprecationWarning(runnable, 'the message', options); expect(runnable.addDeprecationWarning).toHaveBeenCalledWith({ message: jasmine.stringMatching(/^the message/), omitStackTrace: true }); } }); }); jasmine-4.0.0/spec/core/EnvSpec.js000066400000000000000000000456251416413636100167450ustar00rootroot00000000000000// TODO: Fix these unit tests! describe('Env', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); describe('#pending', function() { it('throws the Pending Spec exception', function() { expect(function() { env.pending(); }).toThrow(jasmineUnderTest.Spec.pendingSpecExceptionMessage); }); it('throws the Pending Spec exception with a custom message', function() { expect(function() { env.pending('custom message'); }).toThrow( jasmineUnderTest.Spec.pendingSpecExceptionMessage + 'custom message' ); }); }); describe('#topSuite', function() { it('returns an object that describes the tree of suites and specs', function() { var suite; spyOn(env, 'deprecated'); env.it('a top level spec'); env.describe('a suite', function() { env.it('a spec'); env.describe('a nested suite', function() { env.it('a nested spec'); }); }); suite = env.topSuite(); expect(suite).not.toBeInstanceOf(jasmineUnderTest.Suite); expect(suite.description).toEqual('Jasmine__TopLevel__Suite'); expect(suite.getFullName()).toEqual(''); expect(suite.children.length).toEqual(2); expect(suite.children[0]).not.toBeInstanceOf(jasmineUnderTest.Spec); expect(suite.children[0].description).toEqual('a top level spec'); expect(suite.children[0].getFullName()).toEqual('a top level spec'); expect(suite.children[0].children).toBeFalsy(); expect(suite.children[1]).not.toBeInstanceOf(jasmineUnderTest.Suite); expect(suite.children[1].description).toEqual('a suite'); expect(suite.children[1].getFullName()).toEqual('a suite'); expect(suite.children[1].parentSuite).toBe(suite); expect(suite.children[1].children.length).toEqual(2); expect(suite.children[1].children[0]).not.toBeInstanceOf( jasmineUnderTest.Spec ); expect(suite.children[1].children[0].description).toEqual('a spec'); expect(suite.children[1].children[0].getFullName()).toEqual( 'a suite a spec' ); expect(suite.children[1].children[0].children).toBeFalsy(); expect(suite.children[1].children[1].description).toEqual( 'a nested suite' ); expect(suite.children[1].children[1].getFullName()).toEqual( 'a suite a nested suite' ); expect(suite.children[1].children[1].parentSuite).toBe(suite.children[1]); expect(suite.children[1].children[1].children.length).toEqual(1); expect(suite.children[1].children[1].children[0].description).toEqual( 'a nested spec' ); expect(suite.children[1].children[1].children[0].getFullName()).toEqual( 'a suite a nested suite a nested spec' ); expect(suite.children[1].children[1].children[0].children).toBeFalsy(); }); }); it('accepts its own current configureation', function() { env.configure(env.configuration()); }); it('can configure specs to throw errors on expectation failures', function() { env.configure({ stopSpecOnExpectationFailure: true }); spyOn(jasmineUnderTest, 'Spec').and.callThrough(); env.it('foo', function() {}); expect(jasmineUnderTest.Spec).toHaveBeenCalledWith( jasmine.objectContaining({ throwOnExpectationFailure: true }) ); }); it('can configure suites to throw errors on expectation failures', function() { env.configure({ stopSpecOnExpectationFailure: true }); spyOn(jasmineUnderTest, 'Suite'); env.describe('foo', function() {}); expect(jasmineUnderTest.Suite).toHaveBeenCalledWith( jasmine.objectContaining({ throwOnExpectationFailure: true }) ); }); it('ignores configuration properties that are present but undefined', function() { spyOn(env, 'deprecated'); var initialConfig = { random: true, seed: '123', failSpecWithNoExpectations: true, stopSpecOnExpectationFailure: true, stopOnSpecFailure: true, hideDisabled: true }; env.configure(initialConfig); env.configure({ random: undefined, seed: undefined, failSpecWithNoExpectations: undefined, stopSpecOnExpectationFailure: undefined, stopOnSpecFailure: undefined, hideDisabled: undefined }); expect(env.configuration()).toEqual( jasmine.objectContaining(initialConfig) ); }); it('defaults to multiple failures for specs', function() { spyOn(jasmineUnderTest, 'Spec').and.callThrough(); env.it('bar', function() {}); expect(jasmineUnderTest.Spec).toHaveBeenCalledWith( jasmine.objectContaining({ throwOnExpectationFailure: false }) ); }); it('defaults to multiple failures for suites', function() { spyOn(jasmineUnderTest, 'Suite'); env.describe('foo', function() {}); expect(jasmineUnderTest.Suite).toHaveBeenCalledWith( jasmine.objectContaining({ throwOnExpectationFailure: false }) ); }); function behavesLikeDescribe(methodName) { it('returns a suite metadata object', function() { let innerSuite; let spec; const suite = env.describe('outer suite', function() { innerSuite = env.describe('inner suite', function() { spec = env.it('a spec'); }); }); expect(suite.parentSuite).toEqual( jasmine.objectContaining({ description: 'Jasmine__TopLevel__Suite' }) ); expect(suite.parentSuite.pend).toBeUndefined(); expect(suite.pend).toBeUndefined(); expect(suite.description).toEqual('outer suite'); expect(suite.getFullName()).toEqual('outer suite'); expect(suite.id).toBeInstanceOf(String); expect(suite.id).not.toEqual(''); expect(suite.children.length).toEqual(1); expect(suite.children[0]).toBe(innerSuite); expect(innerSuite.children.length).toEqual(1); expect(innerSuite.children[0]).toBe(spec); expect(innerSuite.getFullName()).toEqual('outer suite inner suite'); expect(innerSuite.parentSuite).toBe(suite); expect(spec.getFullName()).toEqual('outer suite inner suite a spec'); }); } describe('#describe', function() { behavesLikeDescribe('describe'); it('throws an error when given arguments', function() { expect(function() { env.describe('done method', function(done) {}); }).toThrowError('describe does not expect any arguments'); }); it('throws an error when it receives a non-fn argument', function() { // Some versions of PhantomJS return [object DOMWindow] when // Object.prototype.toString.apply is called with `undefined` or `null`. // In a similar fashion, IE8 gives [object Object] for both `undefined` // and `null`. We mostly just want these tests to check that using // anything other than a function throws an error. expect(function() { env.describe('undefined arg', undefined); }).toThrowError( /describe expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); expect(function() { env.describe('null arg', null); }).toThrowError( /describe expects a function argument; received \[object (Null|DOMWindow|Object)\]/ ); expect(function() { env.describe('array arg', []); }).toThrowError( 'describe expects a function argument; received [object Array]' ); expect(function() { env.describe('object arg', {}); }).toThrowError( 'describe expects a function argument; received [object Object]' ); expect(function() { env.describe('fn arg', function() { env.it('has a spec', function() {}); }); }).not.toThrowError( 'describe expects a function argument; received [object Function]' ); }); it('throws an error when it has no children', function() { expect(function() { env.describe('done method', function() {}); }).toThrowError('describe with no children (describe() or it())'); }); }); describe('#fdescribe', function() { behavesLikeDescribe('fdescribe'); }); describe('xdescribe', function() { behavesLikeDescribe('xdescribe'); }); function behavesLikeIt(methodName) { it('returns a spec metadata object', function() { let spec; env.describe('a suite', function() { spec = env[methodName]('a spec', function() {}); }); expect(spec.description) .withContext('description') .toEqual('a spec'); expect(spec.getFullName()) .withContext('getFullName') .toEqual('a suite a spec'); expect(spec.id) .withContext('id') .toBeInstanceOf(String); expect(spec.id) .withContext('id') .not.toEqual(''); expect(spec.pend).toBeFalsy(); }); } describe('#it', function() { behavesLikeIt('it'); it('throws an error when it receives a non-fn argument', function() { expect(function() { env.it('undefined arg', null); }).toThrowError( /it expects a function argument; received \[object (Null|DOMWindow|Object)\]/ ); }); it('does not throw when it is not given a fn argument', function() { expect(function() { env.it('pending spec'); }).not.toThrow(); }); it('accepts an async function', function() { expect(function() { env.it('async', async function() {}); }).not.toThrow(); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.it('huge timeout', function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('#xit', function() { behavesLikeIt('xit'); it('calls spec.exclude with "Temporarily disabled with xit"', function() { var excludeSpy = jasmine.createSpy(); spyOn(env, 'it_').and.returnValue({ exclude: excludeSpy }); env.xit('foo', function() {}); expect(excludeSpy).toHaveBeenCalledWith('Temporarily disabled with xit'); }); it('calls spec.pend with "Temporarily disabled with xit"', function() { var pendSpy = jasmine.createSpy(); var realExclude = jasmineUnderTest.Spec.prototype.exclude; spyOn(env, 'it_').and.returnValue({ exclude: realExclude, pend: pendSpy }); env.xit('foo', function() {}); expect(pendSpy).toHaveBeenCalledWith('Temporarily disabled with xit'); }); it('throws an error when it receives a non-fn argument', function() { expect(function() { env.xit('undefined arg', null); }).toThrowError( /xit expects a function argument; received \[object (Null|DOMWindow|Object)\]/ ); }); it('does not throw when it is not given a fn argument', function() { expect(function() { env.xit('pending spec'); }).not.toThrow(); }); it('accepts an async function', function() { expect(function() { env.xit('async', async function() {}); }).not.toThrow(); }); }); describe('#fit', function() { behavesLikeIt('fit'); it('throws an error when it receives a non-fn argument', function() { expect(function() { env.fit('undefined arg', undefined); }).toThrowError( /fit expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.fit('huge timeout', function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('#beforeEach', function() { it('throws an error when it receives a non-fn argument', function() { expect(function() { env.beforeEach(undefined); }).toThrowError( /beforeEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); }); it('accepts an async function', function() { expect(function() { env.beforeEach(async function() {}); }).not.toThrow(); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.beforeEach(function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('#beforeAll', function() { it('throws an error when it receives a non-fn argument', function() { expect(function() { env.beforeAll(undefined); }).toThrowError( /beforeAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); }); it('accepts an async function', function() { expect(function() { env.beforeAll(async function() {}); }).not.toThrow(); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.beforeAll(function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('#afterEach', function() { it('throws an error when it receives a non-fn argument', function() { expect(function() { env.afterEach(undefined); }).toThrowError( /afterEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); }); it('accepts an async function', function() { expect(function() { env.afterEach(async function() {}); }).not.toThrow(); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.afterEach(function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('#afterAll', function() { it('throws an error when it receives a non-fn argument', function() { expect(function() { env.afterAll(undefined); }).toThrowError( /afterAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/ ); }); it('accepts an async function', function() { expect(function() { env.afterAll(async function() {}); }).not.toThrow(); }); it('throws an error when the timeout value is too large for setTimeout', function() { expect(function() { env.afterAll(function() {}, 2147483648); }).toThrowError('Timeout value cannot be greater than 2147483647'); }); }); describe('when not constructed with suppressLoadErrors: true', function() { it('installs a global error handler on construction', function() { var globalErrors = jasmine.createSpyObj('globalErrors', [ 'install', 'uninstall', 'pushListener', 'popListener' ]); spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors); env.cleanup_(); env = new jasmineUnderTest.Env(); expect(globalErrors.install).toHaveBeenCalled(); }); }); describe('when constructed with suppressLoadErrors: true', function() { it('does not install a global error handler until execute is called', function() { var globalErrors = jasmine.createSpyObj('globalErrors', [ 'install', 'uninstall', 'pushListener', 'popListener' ]); spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors); env.cleanup_(); env = new jasmineUnderTest.Env({ suppressLoadErrors: true }); expect(globalErrors.install).not.toHaveBeenCalled(); env.execute(); expect(globalErrors.install).toHaveBeenCalled(); }); }); it('creates an expectationFactory that uses the current custom equality testers and object formatters', function(done) { function customEqualityTester() {} function customObjectFormatter() {} function prettyPrinter() {} var RealSpec = jasmineUnderTest.Spec, specInstance, expectationFactory; spyOn(jasmineUnderTest, 'MatchersUtil'); spyOn(jasmineUnderTest, 'makePrettyPrinter').and.returnValue(prettyPrinter); spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) { expectationFactory = options.expectationFactory; specInstance = new RealSpec(options); return specInstance; }); env.it('spec', function() { env.addCustomEqualityTester(customEqualityTester); env.addCustomObjectFormatter(customObjectFormatter); expectationFactory('actual', specInstance); }); env.execute(null, function() { expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([ customObjectFormatter ]); expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({ customTesters: [customEqualityTester], pp: prettyPrinter }); done(); }); }); it('creates an asyncExpectationFactory that uses the current custom equality testers and object formatters', function(done) { function customEqualityTester() {} function customObjectFormatter() {} function prettyPrinter() {} var RealSpec = jasmineUnderTest.Spec, specInstance, asyncExpectationFactory; spyOn(jasmineUnderTest, 'MatchersUtil'); spyOn(jasmineUnderTest, 'makePrettyPrinter').and.returnValue(prettyPrinter); spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) { asyncExpectationFactory = options.asyncExpectationFactory; specInstance = new RealSpec(options); return specInstance; }); env.it('spec', function() { env.addCustomEqualityTester(customEqualityTester); env.addCustomObjectFormatter(customObjectFormatter); asyncExpectationFactory('actual', specInstance); }); env.execute(null, function() { expect(jasmineUnderTest.makePrettyPrinter).toHaveBeenCalledWith([ customObjectFormatter ]); expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({ customTesters: [customEqualityTester], pp: prettyPrinter }); done(); }); }); it("does not expose the suite as 'this'", function() { var suiteThis; spyOn(env, 'deprecated'); env.describe('a suite', function() { suiteThis = this; env.it('has a spec'); }); expect(suiteThis).not.toBeInstanceOf(jasmineUnderTest.Suite); }); describe('#execute', function() { it('returns a promise', function() { expect(env.execute()).toBeInstanceOf(Promise); }); it('should reset the topSuite when run twice', function() { spyOn(jasmineUnderTest.Suite.prototype, 'reset'); return env .execute() // 1 .then(function() { return env.execute(); // 2 }) .then(function() { var id; expect( jasmineUnderTest.Suite.prototype.reset ).toHaveBeenCalledOnceWith(); id = jasmineUnderTest.Suite.prototype.reset.calls.thisFor(0).id; expect(id).toBeTruthy(); expect(id).toEqual(env.topSuite().id); }); }); }); }); jasmine-4.0.0/spec/core/ExceptionFormatterSpec.js000066400000000000000000000242711416413636100220310ustar00rootroot00000000000000describe('ExceptionFormatter', function() { describe('#message', function() { it('formats Firefox exception messages', function() { var sampleFirefoxException = { fileName: 'foo.js', lineNumber: '1978', message: 'you got your foo in my bar', name: 'A Classic Mistake' }, exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(sampleFirefoxException); expect(message).toEqual( 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)' ); }); it('formats Webkit exception messages', function() { var sampleWebkitException = { sourceURL: 'foo.js', line: '1978', message: 'you got your foo in my bar', name: 'A Classic Mistake' }, exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(sampleWebkitException); expect(message).toEqual( 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)' ); }); it('formats V8 exception messages', function() { var sampleV8 = { message: 'you got your foo in my bar', name: 'A Classic Mistake' }, exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(sampleV8); expect(message).toEqual('A Classic Mistake: you got your foo in my bar'); }); it('formats unnamed exceptions with message', function() { var unnamedError = { message: 'This is an unnamed error message.' }; var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(unnamedError); expect(message).toEqual('This is an unnamed error message.'); }); it('formats empty exceptions with toString format', function() { var EmptyError = function() {}; EmptyError.prototype.toString = function() { return '[EmptyError]'; }; var emptyError = new EmptyError(); var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(emptyError); expect(message).toEqual('[EmptyError] thrown'); }); it("formats thrown exceptions that aren't errors", function() { var thrown = 'crazy error', exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), message = exceptionFormatter.message(thrown); expect(message).toEqual('crazy error thrown'); }); }); describe('#stack', function() { it('formats stack traces', function() { var error; try { throw new Error('an error'); } catch (e) { error = e; } expect(new jasmineUnderTest.ExceptionFormatter().stack(error)).toMatch( /ExceptionFormatterSpec\.js.*\d+/ ); }); it('filters Jasmine stack frames from V8-style traces but leaves unmatched lines intact', function() { var error = { message: 'nope', stack: 'C:\\__spec__\\core\\UtilSpec.ts:120\n' + " new Error('nope');\n" + ' ^\n' + '\n' + 'Error: nope\n' + ' at fn1 (C:\\__spec__\\core\\UtilSpec.js:115:19)\n' + ' -> C:\\__spec__\\core\\UtilSpec.ts:120:15\n' + ' at fn2 (C:\\__jasmine__\\lib\\jasmine-core\\jasmine.js:7533:40)\n' + ' at fn3 (C:\\__jasmine__\\lib\\jasmine-core\\jasmine.js:7575:25)\n' + ' at fn4 (node:internal/timers:462:21)\n' }; var subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: 'C:\\__jasmine__\\lib\\jasmine-core\\jasmine.js' }); var result = subject.stack(error); expect(result).toEqual( 'C:\\__spec__\\core\\UtilSpec.ts:120\n' + " new Error('nope');\n" + ' ^\n' + 'Error: nope\n' + ' at fn1 (C:\\__spec__\\core\\UtilSpec.js:115:19)\n' + ' -> C:\\__spec__\\core\\UtilSpec.ts:120:15\n' + ' at \n' + ' at fn4 (node:internal/timers:462:21)' ); }); it('filters Jasmine stack frames from V8 style traces', function() { var error = { message: 'nope', stack: 'Error: nope\n' + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + ' at fn3 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)\n' }; var subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' }); var result = subject.stack(error); expect(result).toEqual( 'Error: nope\n' + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at \n' + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)' ); }); it('filters Jasmine stack frames from Webkit style traces', function() { var error = { stack: 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + 'fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + 'fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' }; var subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' }); var result = subject.stack(error); expect(result).toEqual( 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + '\n' + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' ); }); it('filters Jasmine stack frames in this environment', function() { var error, i; try { throw new Error('an error'); } catch (e) { error = e; } var subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: jasmine.util.jasmineFile() }); var result = subject.stack(error); var lines = result.split('\n'); if (lines[0].match(/an error/)) { lines.shift(); } expect(lines[0]).toMatch(/ExceptionFormatterSpec.js/); expect(lines[1]).toMatch(//); // Node has some number of additional frames below Jasmine. for (i = 2; i < lines.length; i++) { expect(lines[i]).not.toMatch(/jasmine.js/); } }); it('handles multiline error messages in this environment', function() { var error, msg = 'an error\nwith two lines'; try { throw new Error(msg); } catch (e) { error = e; } if (error.stack.indexOf(msg) === -1) { pending("Stack traces don't have messages in this environment"); } var subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: jasmine.util.jasmineFile() }); var result = subject.stack(error); var lines = result.split('\n'); expect(lines[0]).toMatch(/an error/); expect(lines[1]).toMatch(/with two lines/); expect(lines[2]).toMatch(/ExceptionFormatterSpec.js/); expect(lines[3]).toMatch(//); }); it('returns null if no Error provided', function() { expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull(); }); it('includes error properties in stack', function() { var error; try { throw new Error('an error'); } catch (e) { error = e; } error.someProperty = 'hello there'; var result = new jasmineUnderTest.ExceptionFormatter().stack(error); expect(result).toMatch(/error properties:.*someProperty.*hello there/); }); describe('When omitMessage is true', function() { it('filters the message from V8-style stack traces', function() { const error = { message: 'nope', stack: 'Error: nope\n' + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + ' at fn3 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)\n' }; const subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' }); const result = subject.stack(error, { omitMessage: true }); expect(result).toEqual( ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at \n' + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)' ); }); it('handles Webkit style traces that do not include a message', function() { const error = { stack: 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + 'fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + 'fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' }; const subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' }); const result = subject.stack(error, { omitMessage: true }); expect(result).toEqual( 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + '\n' + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' ); }); it('ensures that stack traces do not include the message in this environment', function() { let error; try { throw new Error('an error'); } catch (e) { error = e; } const subject = new jasmineUnderTest.ExceptionFormatter({ jasmineFile: jasmine.util.jasmineFile() }); const result = subject.stack(error, { omitMessage: true }); expect(result).not.toContain('an error'); }); }); }); }); jasmine-4.0.0/spec/core/ExceptionsSpec.js000066400000000000000000000027641416413636100203330ustar00rootroot00000000000000describe('Exceptions:', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); it('should handle exceptions thrown, but continue', function(done) { var secondTest = jasmine.createSpy('second test'); env.describe('Suite for handles exceptions', function() { env.it( 'should be a test that fails because it throws an exception', function() { throw new Error(); } ); env.it( 'should be a passing test that runs after exceptions are thrown from a async test', secondTest ); }); var expectations = function() { expect(secondTest).toHaveBeenCalled(); done(); }; env.execute(null, expectations); }); it('should handle exceptions thrown directly in top-level describe blocks and continue', function(done) { var secondDescribe = jasmine .createSpy('second describe') .and.callFake(function() { env.it('has a test', function() {}); }); env.describe('a suite that throws an exception', function() { env.it('is a test that should pass', function() { this.expect(true).toEqual(true); }); throw new Error('top level error'); }); env.describe("a suite that doesn't throw an exception", secondDescribe); var expectations = function() { expect(secondDescribe).toHaveBeenCalled(); done(); }; env.execute(null, expectations); }); }); jasmine-4.0.0/spec/core/ExpectationFilterChainSpec.js000066400000000000000000000105031416413636100225740ustar00rootroot00000000000000describe('ExpectationFilterChain', function() { describe('#addFilter', function() { it('returns a new filter chain with the added filter', function() { var first = jasmine.createSpy('first'), second = jasmine.createSpy('second'), orig = new jasmineUnderTest.ExpectationFilterChain({ modifyFailureMessage: first }), added = orig.addFilter({ selectComparisonFunc: second }); added.modifyFailureMessage(); expect(first).toHaveBeenCalled(); added.selectComparisonFunc(); expect(second).toHaveBeenCalled(); }); it('does not modify the original filter chain', function() { var orig = new jasmineUnderTest.ExpectationFilterChain({}), f = jasmine.createSpy('f'); orig.addFilter({ selectComparisonFunc: f }); orig.selectComparisonFunc(); expect(f).not.toHaveBeenCalled(); }); }); describe('#selectComparisonFunc', function() { describe('When no filters have #selectComparisonFunc', function() { it('returns undefined', function() { var chain = new jasmineUnderTest.ExpectationFilterChain(); chain.addFilter({}); expect(chain.selectComparisonFunc()).toBeUndefined(); }); }); describe('When some filters have #selectComparisonFunc', function() { it('calls the first filter that has #selectComparisonFunc', function() { var first = jasmine.createSpy('first').and.returnValue('first'), second = jasmine.createSpy('second').and.returnValue('second'), chain = new jasmineUnderTest.ExpectationFilterChain() .addFilter({ selectComparisonFunc: first }) .addFilter({ selectComparisonFunc: second }), matcher = {}, result; result = chain.selectComparisonFunc(matcher); expect(first).toHaveBeenCalledWith(matcher); expect(second).not.toHaveBeenCalled(); expect(result).toEqual('first'); }); }); }); describe('#buildFailureMessage', function() { describe('When no filters have #buildFailureMessage', function() { it('returns undefined', function() { var chain = new jasmineUnderTest.ExpectationFilterChain(); chain.addFilter({}); expect(chain.buildFailureMessage()).toBeUndefined(); }); }); describe('When some filters have #buildFailureMessage', function() { it('calls the first filter that has #buildFailureMessage', function() { var first = jasmine.createSpy('first').and.returnValue('first'), second = jasmine.createSpy('second').and.returnValue('second'), chain = new jasmineUnderTest.ExpectationFilterChain() .addFilter({ buildFailureMessage: first }) .addFilter({ buildFailureMessage: second }), matcherResult = { pass: false }, matcherName = 'foo', args = [], matchersUtil = {}, result; result = chain.buildFailureMessage( matcherResult, matcherName, args, matchersUtil ); expect(first).toHaveBeenCalledWith( matcherResult, matcherName, args, matchersUtil ); expect(second).not.toHaveBeenCalled(); expect(result).toEqual('first'); }); }); }); describe('#modifyFailureMessage', function() { describe('When no filters have #modifyFailureMessage', function() { it('returns the original message', function() { var chain = new jasmineUnderTest.ExpectationFilterChain(); chain.addFilter({}); expect(chain.modifyFailureMessage('msg')).toEqual('msg'); }); }); describe('When some filters have #modifyFailureMessage', function() { it('calls the first filter that has #modifyFailureMessage', function() { var first = jasmine.createSpy('first').and.returnValue('first'), second = jasmine.createSpy('second').and.returnValue('second'), chain = new jasmineUnderTest.ExpectationFilterChain() .addFilter({ modifyFailureMessage: first }) .addFilter({ modifyFailureMessage: second }), result; result = chain.modifyFailureMessage('original'); expect(first).toHaveBeenCalledWith('original'); expect(second).not.toHaveBeenCalled(); expect(result).toEqual('first'); }); }); }); }); jasmine-4.0.0/spec/core/ExpectationResultSpec.js000066400000000000000000000074161416413636100216730ustar00rootroot00000000000000describe('buildExpectationResult', function() { it('defaults to passed', function() { var result = jasmineUnderTest.buildExpectationResult({ passed: 'some-value' }); expect(result.passed).toBe('some-value'); }); it('message defaults to Passed for passing specs', function() { var result = jasmineUnderTest.buildExpectationResult({ passed: true, message: 'some-value' }); expect(result.message).toBe('Passed.'); }); it('message returns the message for failing expectations', function() { var result = jasmineUnderTest.buildExpectationResult({ passed: false, message: 'some-value' }); expect(result.message).toBe('some-value'); }); it('delegates message formatting to the provided formatter if there was an Error', function() { var fakeError = { message: 'foo' }, messageFormatter = jasmine .createSpy('exception message formatter') .and.returnValue(fakeError.message); var result = jasmineUnderTest.buildExpectationResult({ passed: false, error: fakeError, messageFormatter: messageFormatter }); expect(messageFormatter).toHaveBeenCalledWith(fakeError); expect(result.message).toEqual('foo'); }); it('delegates stack formatting to the provided formatter if there was an Error', function() { var fakeError = { stack: 'foo' }, stackFormatter = jasmine .createSpy('stack formatter') .and.returnValue(fakeError.stack); var result = jasmineUnderTest.buildExpectationResult({ passed: false, error: fakeError, stackFormatter: stackFormatter }); expect(stackFormatter).toHaveBeenCalledWith(fakeError, { omitMessage: true }); expect(result.stack).toEqual('foo'); }); it('delegates stack formatting to the provided formatter if there was a provided errorForStack', function() { var fakeError = { stack: 'foo' }, stackFormatter = jasmine .createSpy('stack formatter') .and.returnValue(fakeError.stack); var result = jasmineUnderTest.buildExpectationResult({ passed: false, errorForStack: fakeError, stackFormatter: stackFormatter }); expect(stackFormatter).toHaveBeenCalledWith(fakeError, { omitMessage: true }); expect(result.stack).toEqual('foo'); }); it('matcherName returns passed matcherName', function() { var result = jasmineUnderTest.buildExpectationResult({ matcherName: 'some-value' }); expect(result.matcherName).toBe('some-value'); }); it('expected returns passed expected', function() { var result = jasmineUnderTest.buildExpectationResult({ expected: 'some-value' }); expect(result.expected).toBe('some-value'); }); it('actual returns passed actual', function() { var result = jasmineUnderTest.buildExpectationResult({ actual: 'some-value' }); expect(result.actual).toBe('some-value'); }); it('handles nodejs assertions', function() { if (typeof require === 'undefined') { return; } var assert = require('assert'); var error; var value = 8421; var expectedValue = 'JasmineExpectationTestValue'; try { assert.equal(value, expectedValue); } catch (e) { error = e; } expect(error.code).toEqual('ERR_ASSERTION'); expect(error.actual).toEqual(value); expect(error.expected).toEqual(expectedValue); expect(error.operator).toEqual('=='); var result = jasmineUnderTest.buildExpectationResult({ passed: false, matcherName: '', expected: '', actual: '', error: error }); expect(result.code).toEqual('ERR_ASSERTION'); expect(result.actual).toEqual(value); expect(result.expected).toEqual(expectedValue); expect(result.matcherName).toEqual('assert =='); }); }); jasmine-4.0.0/spec/core/ExpectationSpec.js000066400000000000000000000467251416413636100205020ustar00rootroot00000000000000describe('Expectation', function() { it('makes custom matchers available to this expectation', function() { var matchers = { toFoo: function() {}, toBar: function() {} }, expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers }); expect(expectation.toFoo).toBeDefined(); expect(expectation.toBar).toBeDefined(); }); it('.addCoreMatchers makes matchers available to any expectation', function() { var coreMatchers = { toQuux: function() {} }, expectation; jasmineUnderTest.Expectation.addCoreMatchers(coreMatchers); expectation = jasmineUnderTest.Expectation.factory({}); expect(expectation.toQuux).toBeDefined(); }); it("wraps matchers's compare functions, passing in matcher dependencies", function() { var fakeCompare = function() { return { pass: true }; }, matcherFactory = jasmine .createSpy('matcher') .and.returnValue({ compare: fakeCompare }), matchers = { toFoo: matcherFactory }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ matchersUtil: matchersUtil, customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(matcherFactory).toHaveBeenCalledWith(matchersUtil); }); it("wraps matchers's compare functions, passing the actual and expected", function() { var fakeCompare = jasmine .createSpy('fake-compare') .and.returnValue({ pass: true }), matchers = { toFoo: function() { return { compare: fakeCompare }; } }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ matchersUtil: matchersUtil, customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(fakeCompare).toHaveBeenCalledWith('an actual', 'hello'); }); it('reports a passing result to the spec when the comparison passes', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true }; } }; } }, matchersUtil = { buildFailureMessage: jasmine.createSpy('buildFailureMessage') }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, matchersUtil: matchersUtil, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, message: '', error: undefined, expected: 'hello', actual: 'an actual', errorForStack: undefined }); }); it('reports a failing result to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false }; } }; } }, matchersUtil = { buildFailureMessage: function() { return ''; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, matchersUtil: matchersUtil, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: '', error: undefined, errorForStack: undefined }); }); it('reports a failing result and a custom fail message to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: 'I am a custom message' }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ actual: 'an actual', customMatchers: matchers, addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: undefined }); }); it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: function() { return 'I am a custom message'; } }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: undefined, errorForStack: undefined }); }); it('reports a passing result to the spec when the comparison fails for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, message: '', error: undefined, expected: 'hello', actual: actual, errorForStack: undefined }); }); it('reports a failing result to the spec when the comparison passes for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true }; } }; } }, matchersUtil = { buildFailureMessage: function() { return 'default message'; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', matchersUtil: matchersUtil, addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: 'default message', error: undefined, errorForStack: undefined }); }); it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true, message: 'I am a custom message' }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: 'I am a custom message', error: undefined, errorForStack: undefined }); }); it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true }; }, negativeCompare: function() { return { pass: true }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(true, { matcherName: 'toFoo', passed: true, expected: 'hello', actual: actual, message: '', error: undefined, errorForStack: undefined }); }); it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true }; }, negativeCompare: function() { return { pass: false, message: "I'm a custom message" }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = 'an actual', expectation; expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: actual, message: "I'm a custom message", error: undefined, errorForStack: undefined }); }); it('reports a custom error message to the spec', function() { var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: 'I am a custom message', error: customError }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ actual: 'an actual', customMatchers: matchers, addExpectationResult: addExpectationResult }); expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: customError, errorForStack: undefined }); }); it("reports a custom message to the spec when a 'not' comparison fails", function() { var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { return { compare: function() { return { pass: true, message: 'I am a custom message', error: customError }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ actual: 'an actual', customMatchers: matchers, addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: customError, errorForStack: undefined }); }); it("reports a custom message func to the spec when a 'not' comparison fails", function() { var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { return { compare: function() { return { pass: true, message: function() { return 'I am a custom message'; }, error: customError }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation; expectation = jasmineUnderTest.Expectation.factory({ actual: 'an actual', customMatchers: matchers, addExpectationResult: addExpectationResult }).not; expectation.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith(false, { matcherName: 'toFoo', passed: false, expected: 'hello', actual: 'an actual', message: 'I am a custom message', error: customError, errorForStack: undefined }); }); describe('#withContext', function() { it('prepends the context to the generated failure message', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false }; } }; } }, matchersUtil = { buildFailureMessage: function() { return 'failure message'; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, matchersUtil: matchersUtil, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.withContext('Some context').toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: failure message' }) ); }); it('prepends the context to a custom failure message', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: 'msg' }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.withContext('Some context').toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: msg' }) ); }); it('indents a multiline failure message', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: 'a\nmultiline\nmessage' }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }), actualMessage; expectation.withContext('Some context').toFoo('hello'); actualMessage = addExpectationResult.calls.argsFor(0)[1].message; expect(actualMessage).toEqual( 'Some context:\n a\n multiline\n message' ); }); it('prepends the context to a custom failure message from a function', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: false, message: function() { return 'msg'; } }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.withContext('Some context').toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: msg' }) ); }); it('works with #not', function() { var matchers = { toFoo: function() { return { compare: function() { return { pass: true }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), pp = jasmineUnderTest.makePrettyPrinter(), expectation = jasmineUnderTest.Expectation.factory({ customMatchers: matchers, matchersUtil: new jasmineUnderTest.MatchersUtil({ pp: pp }), actual: 'an actual', addExpectationResult: addExpectationResult }); expectation.withContext('Some context').not.toFoo(); expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: "Some context: Expected 'an actual' not to foo." }) ); }); it('works with #not and a custom message', function() { var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { return { compare: function() { return { pass: true, message: function() { return 'I am a custom message'; }, error: customError }; } }; } }, addExpectationResult = jasmine.createSpy('addExpectationResult'), expectation = jasmineUnderTest.Expectation.factory({ actual: 'an actual', customMatchers: matchers, addExpectationResult: addExpectationResult }); expectation.withContext('Some context').not.toFoo('hello'); expect(addExpectationResult).toHaveBeenCalledWith( false, jasmine.objectContaining({ message: 'Some context: I am a custom message' }) ); }); }); }); jasmine-4.0.0/spec/core/GlobalErrorsSpec.js000066400000000000000000000314051416413636100206010ustar00rootroot00000000000000describe('GlobalErrors', function() { it('calls the added handler on error', function() { var fakeGlobal = { onerror: null }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); fakeGlobal.onerror('foo'); expect(handler).toHaveBeenCalledWith('foo'); }); it('enables external interception of error by overriding global.onerror', function() { var fakeGlobal = { onerror: null }, handler = jasmine.createSpy('errorHandler'), hijackHandler = jasmine.createSpy('hijackErrorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); fakeGlobal.onerror = hijackHandler; fakeGlobal.onerror('foo'); expect(hijackHandler).toHaveBeenCalledWith('foo'); expect(handler).not.toHaveBeenCalled(); }); it('calls the global error handler with all parameters', function() { var fakeGlobal = { onerror: null }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal), fooError = new Error('foo'); errors.install(); errors.pushListener(handler); fakeGlobal.onerror(fooError.message, 'foo.js', 1, 1, fooError); expect(handler).toHaveBeenCalledWith( fooError.message, 'foo.js', 1, 1, fooError ); }); it('only calls the most recent handler', function() { var fakeGlobal = { onerror: null }, handler1 = jasmine.createSpy('errorHandler1'), handler2 = jasmine.createSpy('errorHandler2'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler1); errors.pushListener(handler2); fakeGlobal.onerror('foo'); expect(handler1).not.toHaveBeenCalled(); expect(handler2).toHaveBeenCalledWith('foo'); }); it('calls previous handlers when one is removed', function() { var fakeGlobal = { onerror: null }, handler1 = jasmine.createSpy('errorHandler1'), handler2 = jasmine.createSpy('errorHandler2'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler1); errors.pushListener(handler2); errors.popListener(handler2); fakeGlobal.onerror('foo'); expect(handler1).toHaveBeenCalledWith('foo'); expect(handler2).not.toHaveBeenCalled(); }); it('throws when no listener is passed to #popListener', function() { var errors = new jasmineUnderTest.GlobalErrors({}); expect(function() { errors.popListener(); }).toThrowError('popListener expects a listener'); }); it('uninstalls itself, putting back a previous callback', function() { var originalCallback = jasmine.createSpy('error'), fakeGlobal = { onerror: originalCallback }, errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); expect(fakeGlobal.onerror).toBe(originalCallback); errors.install(); expect(fakeGlobal.onerror).not.toBe(originalCallback); errors.uninstall(); expect(fakeGlobal.onerror).toBe(originalCallback); }); it('rethrows the original error when there is no handler', function() { var fakeGlobal = {}, errors = new jasmineUnderTest.GlobalErrors(fakeGlobal), originalError = new Error('nope'); errors.install(); try { fakeGlobal.onerror(originalError); } catch (e) { expect(e).toBe(originalError); } errors.uninstall(); }); it('reports uncaught exceptions in node.js', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), removeListener: jasmine.createSpy('process.removeListener'), listeners: jasmine .createSpy('process.listeners') .and.returnValue(['foo']), removeAllListeners: jasmine.createSpy('process.removeAllListeners') } }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); expect(fakeGlobal.process.on).toHaveBeenCalledWith( 'uncaughtException', jasmine.any(Function) ); expect(fakeGlobal.process.listeners).toHaveBeenCalledWith( 'uncaughtException' ); expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith( 'uncaughtException' ); errors.pushListener(handler); var addedListener = fakeGlobal.process.on.calls.argsFor(0)[1]; addedListener(new Error('bar')); expect(handler).toHaveBeenCalledWith(new Error('bar')); expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe( 'Uncaught exception: Error: bar' ); errors.uninstall(); expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith( 'uncaughtException', addedListener ); expect(fakeGlobal.process.on).toHaveBeenCalledWith( 'uncaughtException', 'foo' ); }); describe('Reporting unhandled promise rejections in node.js', function() { it('reports rejections with `Error` reasons', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), removeListener: jasmine.createSpy('process.removeListener'), listeners: jasmine .createSpy('process.listeners') .and.returnValue(['foo']), removeAllListeners: jasmine.createSpy('process.removeAllListeners') } }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); expect(fakeGlobal.process.on).toHaveBeenCalledWith( 'unhandledRejection', jasmine.any(Function) ); expect(fakeGlobal.process.listeners).toHaveBeenCalledWith( 'unhandledRejection' ); expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith( 'unhandledRejection' ); errors.pushListener(handler); var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; addedListener(new Error('bar')); expect(handler).toHaveBeenCalledWith(new Error('bar')); expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe( 'Unhandled promise rejection: Error: bar' ); errors.uninstall(); expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith( 'unhandledRejection', addedListener ); expect(fakeGlobal.process.on).toHaveBeenCalledWith( 'unhandledRejection', 'foo' ); }); it('reports rejections with non-`Error` reasons', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), removeListener: function() {}, listeners: function() { return []; }, removeAllListeners: function() {} } }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual( 'unhandledRejection' ); var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; addedListener(17); expect(handler).toHaveBeenCalledWith( new Error( 'Unhandled promise rejection: 17\n' + '(Tip: to get a useful stack trace, use ' + 'Promise.reject(new Error(...)) instead of Promise.reject(...).)' ) ); }); it('reports rejections with no reason provided', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), removeListener: function() {}, listeners: function() { return []; }, removeAllListeners: function() {} } }, handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual( 'unhandledRejection' ); var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; addedListener(undefined); expect(handler).toHaveBeenCalledWith( new Error( 'Unhandled promise rejection with no error or message\n' + '(Tip: to get a useful stack trace, use ' + 'Promise.reject(new Error(...)) instead of Promise.reject().)' ) ); }); }); describe('Reporting unhandled promise rejections in the browser', function() { it('subscribes and unsubscribes from the unhandledrejection event', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ 'addEventListener', 'removeEventListener', 'onerror' ]), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); expect(fakeGlobal.addEventListener).toHaveBeenCalledWith( 'unhandledrejection', jasmine.any(Function) ); var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; errors.uninstall(); expect(fakeGlobal.removeEventListener).toHaveBeenCalledWith( 'unhandledrejection', addedListener ); }); it('reports rejections whose reason is a string', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ 'addEventListener', 'removeEventListener', 'onerror' ]), handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; addedListener({ reason: 'nope' }); expect(handler).toHaveBeenCalledWith('Unhandled promise rejection: nope'); }); it('reports rejections whose reason is an Error', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ 'addEventListener', 'removeEventListener', 'onerror' ]), handler = jasmine.createSpy('errorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; var reason; try { // Throwing ensures that we get a stack property in all browsers throw new Error('bar'); } catch (e) { reason = e; } addedListener({ reason: reason }); expect(handler).toHaveBeenCalledWith( jasmine.objectContaining({ jasmineMessage: 'Unhandled promise rejection: Error: bar', message: reason.message, stack: reason.stack }) ); }); describe('Enabling external interception of reported rejections by overriding global.onerror', function() { it('overriding global.onerror intercepts rejections whose reason is a string', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ 'addEventListener' ]), handler = jasmine.createSpy('errorHandler'), hijackHandler = jasmine.createSpy('hijackErrorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); fakeGlobal.onerror = hijackHandler; var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; addedListener({ reason: 'nope' }); expect(hijackHandler).toHaveBeenCalledWith( 'Unhandled promise rejection: nope' ); expect(handler).not.toHaveBeenCalled(); }); it('overriding global.onerror intercepts rejections whose reason is an Error', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ 'addEventListener' ]), handler = jasmine.createSpy('errorHandler'), hijackHandler = jasmine.createSpy('hijackErrorHandler'), errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors.install(); errors.pushListener(handler); fakeGlobal.onerror = hijackHandler; var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; var reason; try { // Throwing ensures that we get a stack property in all browsers throw new Error('bar'); } catch (e) { reason = e; } addedListener({ reason: reason }); expect(hijackHandler).toHaveBeenCalledWith( jasmine.objectContaining({ jasmineMessage: 'Unhandled promise rejection: Error: bar', message: reason.message, stack: reason.stack }) ); expect(handler).not.toHaveBeenCalled(); }); }); }); }); jasmine-4.0.0/spec/core/JsApiReporterSpec.js000066400000000000000000000121441416413636100207340ustar00rootroot00000000000000describe('JsApiReporter', function() { it('knows when a full environment is started', function() { var reporter = new jasmineUnderTest.JsApiReporter({}); expect(reporter.started).toBe(false); expect(reporter.finished).toBe(false); reporter.jasmineStarted(); expect(reporter.started).toBe(true); expect(reporter.finished).toBe(false); }); it('knows when a full environment is done', function() { var reporter = new jasmineUnderTest.JsApiReporter({}); expect(reporter.started).toBe(false); expect(reporter.finished).toBe(false); reporter.jasmineStarted(); reporter.jasmineDone({}); expect(reporter.finished).toBe(true); }); it("defaults to 'loaded' status", function() { var reporter = new jasmineUnderTest.JsApiReporter({}); expect(reporter.status()).toEqual('loaded'); }); it("reports 'started' when Jasmine has started", function() { var reporter = new jasmineUnderTest.JsApiReporter({}); reporter.jasmineStarted(); expect(reporter.status()).toEqual('started'); }); it("reports 'done' when Jasmine is done", function() { var reporter = new jasmineUnderTest.JsApiReporter({}); reporter.jasmineDone({}); expect(reporter.status()).toEqual('done'); }); it('tracks a suite', function() { var reporter = new jasmineUnderTest.JsApiReporter({}); reporter.suiteStarted({ id: 123, description: 'A suite' }); var suites = reporter.suites(); expect(suites).toEqual({ 123: { id: 123, description: 'A suite' } }); reporter.suiteDone({ id: 123, description: 'A suite', status: 'passed' }); expect(suites).toEqual({ 123: { id: 123, description: 'A suite', status: 'passed' } }); }); describe('#specResults', function() { var reporter, specResult1, specResult2; beforeEach(function() { reporter = new jasmineUnderTest.JsApiReporter({}); specResult1 = { id: 1, description: 'A spec' }; specResult2 = { id: 2, description: 'Another spec' }; reporter.specDone(specResult1); reporter.specDone(specResult2); }); it('should return a slice of results', function() { expect(reporter.specResults(0, 1)).toEqual([specResult1]); expect(reporter.specResults(1, 1)).toEqual([specResult2]); }); describe('when the results do not exist', function() { it('should return a slice of shorter length', function() { expect(reporter.specResults(0, 3)).toEqual([specResult1, specResult2]); expect(reporter.specResults(2, 3)).toEqual([]); }); }); }); describe('#suiteResults', function() { var reporter, suiteStarted1, suiteResult1, suiteResult2; beforeEach(function() { reporter = new jasmineUnderTest.JsApiReporter({}); suiteStarted1 = { id: 1 }; suiteResult1 = { id: 1, status: 'failed', failedExpectations: [{ message: 'My After All Exception' }] }; suiteResult2 = { id: 2, status: 'passed' }; reporter.suiteStarted(suiteStarted1); reporter.suiteDone(suiteResult1); reporter.suiteDone(suiteResult2); }); it('should not include suite starts', function() { expect(reporter.suiteResults(0, 3).length).toEqual(2); }); it('should return a slice of results', function() { expect(reporter.suiteResults(0, 1)).toEqual([suiteResult1]); expect(reporter.suiteResults(1, 1)).toEqual([suiteResult2]); }); it('returns nothing for out of bounds indices', function() { expect(reporter.suiteResults(0, 3)).toEqual([suiteResult1, suiteResult2]); expect(reporter.suiteResults(2, 3)).toEqual([]); }); }); describe('#executionTime', function() { it('should start the timer when jasmine starts', function() { var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), reporter = new jasmineUnderTest.JsApiReporter({ timer: timerSpy }); reporter.jasmineStarted(); expect(timerSpy.start).toHaveBeenCalled(); }); it('should return the time it took the specs to run, in ms', function() { var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), reporter = new jasmineUnderTest.JsApiReporter({ timer: timerSpy }); timerSpy.elapsed.and.returnValue(1000); reporter.jasmineDone(); expect(reporter.executionTime()).toEqual(1000); }); describe("when the specs haven't finished being run", function() { it('should return undefined', function() { var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']), reporter = new jasmineUnderTest.JsApiReporter({ timer: timerSpy }); expect(reporter.executionTime()).toBeUndefined(); }); }); }); describe('#runDetails', function() { it('should have details about the run', function() { var reporter = new jasmineUnderTest.JsApiReporter({}); reporter.jasmineDone({ some: { run: 'details' } }); expect(reporter.runDetails).toEqual({ some: { run: 'details' } }); }); }); }); jasmine-4.0.0/spec/core/MockDateSpec.js000066400000000000000000000122261416413636100176730ustar00rootroot00000000000000describe('FakeDate', function() { it('does not fail if no global date is found', function() { var fakeGlobal = {}, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); expect(function() { mockDate.install(); mockDate.tick(0); mockDate.uninstall(); }).not.toThrow(); }); it('replaces the global Date when it is installed', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() {} }; }), fakeGlobal = { Date: globalDate }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); expect(fakeGlobal.Date).toEqual(globalDate); mockDate.install(); expect(fakeGlobal.Date).not.toEqual(globalDate); }); it('replaces the global Date on uninstall', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() {} }; }), fakeGlobal = { Date: globalDate }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); mockDate.uninstall(); expect(fakeGlobal.Date).toEqual(globalDate); }); it('takes the current time as the base when installing without parameters', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() { return 1000; } }; }), fakeGlobal = { Date: globalDate }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); globalDate.calls.reset(); new fakeGlobal.Date(); expect(globalDate).toHaveBeenCalledWith(1000); }); it('can accept a date as time base when installing', function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal), baseDate = new Date(); spyOn(baseDate, 'getTime').and.returnValue(123); mockDate.install(baseDate); expect(new fakeGlobal.Date().getTime()).toEqual(123); }); it('makes real dates', function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); expect(new fakeGlobal.Date()).toEqual(jasmine.any(Date)); expect(new fakeGlobal.Date() instanceof fakeGlobal.Date).toBe(true); }); it('fakes current time when using Date.now()', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() { return 1000; } }; }), fakeGlobal = { Date: globalDate }; globalDate.now = function() {}; var mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); expect(fakeGlobal.Date.now()).toEqual(1000); }); it('makes time passes using tick', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() { return 1000; } }; }), fakeGlobal = { Date: globalDate }; globalDate.now = function() {}; var mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); mockDate.tick(100); expect(fakeGlobal.Date.now()).toEqual(1100); mockDate.tick(1000); expect(fakeGlobal.Date.now()).toEqual(2100); }); it('allows to increase 0 milliseconds using tick', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { getTime: function() { return 1000; } }; }), fakeGlobal = { Date: globalDate }; globalDate.now = function() {}; var mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); mockDate.tick(0); expect(fakeGlobal.Date.now()).toEqual(1000); mockDate.tick(); expect(fakeGlobal.Date.now()).toEqual(1000); }); it('allows creation of a Date in a different time than the mocked time', function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); var otherDate = new fakeGlobal.Date(2013, 9, 23, 0, 0, 1, 0); expect(otherDate.getTime()).toEqual( new Date(2013, 9, 23, 0, 0, 1, 0).getTime() ); }); it("allows creation of a Date that isn't fully specified", function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); var otherDate = new fakeGlobal.Date(2013, 9, 23); expect(otherDate.getTime()).toEqual(new Date(2013, 9, 23).getTime()); }); it('allows creation of a Date with millis', function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal), now = new Date(2014, 3, 15).getTime(); mockDate.install(); var otherDate = new fakeGlobal.Date(now); expect(otherDate.getTime()).toEqual(now); }); it('copies all Date properties to the mocked date', function() { var fakeGlobal = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(fakeGlobal); mockDate.install(); expect(fakeGlobal.Date.UTC(2013, 9, 23)).toEqual(Date.UTC(2013, 9, 23)); }); }); jasmine-4.0.0/spec/core/PrettyPrintSpec.js000066400000000000000000000424451416413636100205160ustar00rootroot00000000000000describe('PrettyPrinter', function() { it('should wrap strings in single quotes', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp('some string')).toEqual("'some string'"); expect(pp("som' string")).toEqual("'som' string'"); }); it('should stringify primitives properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(true)).toEqual('true'); expect(pp(false)).toEqual('false'); expect(pp(null)).toEqual('null'); expect(pp(jasmine.undefined)).toEqual('undefined'); expect(pp(3)).toEqual('3'); expect(pp(-3.14)).toEqual('-3.14'); expect(pp(-0)).toEqual('-0'); }); describe('stringify sets', function() { it('should stringify sets properly', function() { var set = new Set(); set.add(1); set.add(2); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(set)).toEqual('Set( 1, 2 )'); }); it('should truncate sets with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() { var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; var set = new Set(); set.add('a'); set.add('b'); set.add('c'); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(set)).toEqual("Set( 'a', 'b', ... )"); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize; } }); }); describe('stringify maps', function() { it('should stringify maps properly', function() { var map = new Map(); map.set(1, 2); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(map)).toEqual('Map( [ 1, 2 ] )'); }); it('should truncate maps with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() { var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; var map = new Map(); map.set('a', 1); map.set('b', 2); map.set('c', 3); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(map)).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )"); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize; } }); }); describe('stringify arrays', function() { it('should stringify arrays properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp([1, 2])).toEqual('[ 1, 2 ]'); expect(pp([1, 'foo', {}, jasmine.undefined, null])).toEqual( "[ 1, 'foo', Object({ }), undefined, null ]" ); }); it('should truncate arrays that are longer than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() { var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; var array = [1, 2, 3]; var pp = jasmineUnderTest.makePrettyPrinter(); try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; expect(pp(array)).toEqual('[ 1, 2, ... ]'); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength; } }); it('should stringify arrays with properties properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var arr = [1, 2]; arr.foo = 'bar'; arr.baz = {}; expect(pp(arr)).toEqual("[ 1, 2, foo: 'bar', baz: Object({ }) ]"); }); it('should stringify empty arrays with properties properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var empty = []; empty.foo = 'bar'; empty.baz = {}; expect(pp(empty)).toEqual("[ foo: 'bar', baz: Object({ }) ]"); }); it('should stringify long arrays with properties properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; var long = [1, 2, 3]; long.foo = 'bar'; long.baz = {}; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; expect(pp(long)).toEqual( "[ 1, 2, ..., foo: 'bar', baz: Object({ }) ]" ); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength; } }); it('should indicate circular array references', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var array1 = [1, 2]; var array2 = [array1]; array1.push(array2); expect(pp(array1)).toEqual('[ 1, 2, [ ] ]'); }); it('should not indicate circular references incorrectly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var array = [[1]]; expect(pp(array)).toEqual('[ [ 1 ] ]'); }); }); it('should stringify objects properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp({ foo: 'bar' })).toEqual("Object({ foo: 'bar' })"); expect( pp({ foo: 'bar', baz: 3, nullValue: null, undefinedValue: jasmine.undefined }) ).toEqual( "Object({ foo: 'bar', baz: 3, nullValue: null, undefinedValue: undefined })" ); expect(pp({ foo: function() {}, bar: [1, 2, 3] })).toEqual( 'Object({ foo: Function, bar: [ 1, 2, 3 ] })' ); }); it('should stringify objects that almost look like DOM nodes', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp({ nodeType: 1 })).toEqual('Object({ nodeType: 1 })'); }); it('should truncate objects with too many keys', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; var long = { a: 1, b: 2, c: 3 }; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; expect(pp(long)).toEqual('Object({ a: 1, b: 2, ... })'); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength; } }); function withMaxChars(maxChars, fn) { var originalMaxChars = jasmineUnderTest.MAX_PRETTY_PRINT_CHARS; try { jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = maxChars; fn(); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = originalMaxChars; } } it('should truncate outputs that are too long', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var big = [{ a: 1, b: 'a long string' }, {}]; withMaxChars(34, function() { expect(pp(big)).toEqual("[ Object({ a: 1, b: 'a long st ..."); }); }); it('should not serialize more objects after hitting MAX_PRETTY_PRINT_CHARS', function() { var a = { jasmineToString: function() { return 'object a'; } }, b = { jasmineToString: function() { return 'object b'; } }, c = { jasmineToString: jasmine .createSpy('c jasmineToString') .and.returnValue('') }, d = { jasmineToString: jasmine .createSpy('d jasmineToString') .and.returnValue('') }, pp = jasmineUnderTest.makePrettyPrinter(); withMaxChars(30, function() { pp([{ a: a, b: b, c: c }, d]); expect(c.jasmineToString).not.toHaveBeenCalled(); expect(d.jasmineToString).not.toHaveBeenCalled(); }); }); it("should print 'null' as the constructor of an object with its own constructor property", function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp({ constructor: function() {} })).toContain('null({'); expect(pp({ constructor: 'foo' })).toContain('null({'); }); it('should not include inherited properties when stringifying an object', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var SomeClass = function SomeClass() {}; SomeClass.prototype.foo = 'inherited foo'; var instance = new SomeClass(); instance.bar = 'my own bar'; expect(pp(instance)).toEqual("SomeClass({ bar: 'my own bar' })"); }); it('should not recurse objects and arrays more deeply than jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var originalMaxDepth = jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH; var nestedObject = { level1: { level2: { level3: { level4: 'leaf' } } } }; var nestedArray = [1, [2, [3, [4, 'leaf']]]]; try { jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH = 2; expect(pp(nestedObject)).toEqual( 'Object({ level1: Object({ level2: Object }) })' ); expect(pp(nestedArray)).toEqual('[ 1, [ 2, Array ] ]'); jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH = 3; expect(pp(nestedObject)).toEqual( 'Object({ level1: Object({ level2: Object({ level3: Object }) }) })' ); expect(pp(nestedArray)).toEqual('[ 1, [ 2, [ 3, Array ] ] ]'); jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH = 4; expect(pp(nestedObject)).toEqual( "Object({ level1: Object({ level2: Object({ level3: Object({ level4: 'leaf' }) }) }) })" ); expect(pp(nestedArray)).toEqual("[ 1, [ 2, [ 3, [ 4, 'leaf' ] ] ] ]"); } finally { jasmineUnderTest.MAX_PRETTY_PRINT_DEPTH = originalMaxDepth; } }); it('should stringify immutable circular objects', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var frozenObject = { foo: { bar: 'baz' } }; frozenObject.circular = frozenObject; frozenObject = Object.freeze(frozenObject); expect(pp(frozenObject)).toEqual( "Object({ foo: Object({ bar: 'baz' }), circular: })" ); }); it('should stringify RegExp objects properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(/x|y|z/)).toEqual('/x|y|z/'); }); it('should indicate circular object references', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var sampleValue = { foo: 'hello' }; sampleValue.nested = sampleValue; expect(pp(sampleValue)).toEqual( "Object({ foo: 'hello', nested: })" ); }); it('should indicate getters on objects as such', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var sampleValue = { id: 1, get calculatedValue() { throw new Error("don't call me!"); } }; expect(pp(sampleValue)).toEqual( 'Object({ id: 1, calculatedValue: })' ); }); it('should not do HTML escaping of strings', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp('some html string &', false)).toEqual( "'some html string &'" ); }); it('should abbreviate the global (usually window) object', function() { var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(jasmine.getGlobal())).toEqual(''); }); it('should stringify Date objects properly', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var now = new Date(); expect(pp(now)).toEqual('Date(' + now.toString() + ')'); }); describe('with a spy object', function() { var env, pp; beforeEach(function() { env = new jasmineUnderTest.Env(); pp = jasmineUnderTest.makePrettyPrinter(); }); afterEach(function() { env.cleanup_(); }); it('should stringify spy objects properly', function() { var TestObject = { someFunction: function() {} }; var spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return []; }, createSpy: function(name, originalFn) { return jasmineUnderTest.Spy(name, originalFn); } }); spyRegistry.spyOn(TestObject, 'someFunction'); expect(pp(TestObject.someFunction)).toEqual('spy on someFunction'); expect(pp(env.createSpy('something'))).toEqual('spy on something'); }); it('should stringify spyOn toString properly', function() { var TestObject = { someFunction: function() {} }, env = new jasmineUnderTest.Env(), pp = jasmineUnderTest.makePrettyPrinter(); var spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return []; }, createSpy: function(name, originalFn) { return jasmineUnderTest.Spy(name, originalFn); } }); spyRegistry.spyOn(TestObject, 'toString'); var testSpyObj = env.createSpyObj('TheClassName', ['toString']); expect(pp(testSpyObj)).toEqual('spy on TheClassName.toString'); }); }); it('should stringify objects that implement jasmineToString', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var obj = { jasmineToString: function() { return 'strung'; } }; expect(pp(obj)).toEqual('strung'); }); it('should pass itself to jasmineToString', function() { var pp = jasmineUnderTest.makePrettyPrinter([]); var obj = { jasmineToString: jasmine.createSpy('jasmineToString').and.returnValue('') }; pp(obj); expect(obj.jasmineToString).toHaveBeenCalledWith(pp); }); it('should stringify objects that implement custom toString', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var obj = { toString: function() { return 'my toString'; } }; expect(pp(obj)).toEqual('my toString'); // Simulate object from another global context (e.g. an iframe or Web Worker) that does not actually have a custom // toString despite obj.toString !== Object.prototype.toString var objFromOtherContext = { foo: 'bar', toString: function() { return Object.prototype.toString.call(this); } }; expect(pp(objFromOtherContext)).toEqual( "Object({ foo: 'bar', toString: Function })" ); }); it("should stringify objects have have a toString that isn't a function", function() { var pp = jasmineUnderTest.makePrettyPrinter(); var obj = { toString: 'foo' }; expect(pp(obj)).toEqual("Object({ toString: 'foo' })"); }); it('should stringify objects from anonymous constructors with custom toString', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var MyAnonymousConstructor = (function() { return function() {}; })(); MyAnonymousConstructor.toString = function() { return ''; }; var a = new MyAnonymousConstructor(); expect(pp(a)).toEqual('({ })'); }); it('should handle objects with null prototype', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var obj = Object.create(null); obj.foo = 'bar'; expect(pp(obj)).toEqual("null({ foo: 'bar' })"); }); it('should gracefully handle objects with invalid toString implementations', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var obj = { foo: { toString: function() { // Invalid: toString returning a number return 3; } }, bar: { toString: function() { // Really invalid: a nested bad toString(). return { toString: function() { return new Date(); } }; } }, // Valid: an actual number baz: 3, // Valid: an actual Error object qux: new Error('bar'), // baddy: { toString: function() { throw new Error('I am a bad toString'); } } }; expect(pp(obj)).toEqual( 'Object({ foo: [object Number], bar: [object Object], baz: 3, qux: Error: bar, baddy: has-invalid-toString-method })' ); }); describe('Custom object formatters', function() { it('should use the first custom object formatter that does not return undefined', function() { var customObjectFormatters = [ function(obj) { return undefined; }, function(obj) { return '2nd: ' + obj.foo; }, function(obj) { return '3rd: ' + obj.foo; } ], pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters), obj = { foo: 'bar' }; expect(pp(obj)).toEqual('2nd: bar'); }); it('should fall back to built in logic if all custom object formatters return undefined', function() { var customObjectFormatters = [ function(obj) { return undefined; } ], pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters), obj = { foo: 'bar' }; expect(pp(obj)).toEqual("Object({ foo: 'bar' })"); }); }); describe('#customFormat_', function() { it('should use the first custom object formatter that does not return undefined', function() { var customObjectFormatters = [ function(obj) { return undefined; }, function(obj) { return '2nd: ' + obj.foo; }, function(obj) { return '3rd: ' + obj.foo; } ], pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters), obj = { foo: 'bar' }; expect(pp.customFormat_(obj)).toEqual('2nd: bar'); }); it('should return undefined if all custom object formatters return undefined', function() { var customObjectFormatters = [ function(obj) { return undefined; } ], pp = jasmineUnderTest.makePrettyPrinter(customObjectFormatters), obj = { foo: 'bar' }; expect(pp.customFormat_(obj)).toBeUndefined(); }); }); }); jasmine-4.0.0/spec/core/QueueRunnerSpec.js000066400000000000000000000717601416413636100204720ustar00rootroot00000000000000describe('QueueRunner', function() { it("runs all the functions it's passed", function() { var calls = [], queueableFn1 = { fn: jasmine.createSpy('fn1') }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2] }); queueableFn1.fn.and.callFake(function() { calls.push('fn1'); }); queueableFn2.fn.and.callFake(function() { calls.push('fn2'); }); queueRunner.execute(); expect(calls).toEqual(['fn1', 'fn2']); }); it("calls each function with a consistent 'this'-- an empty object", function() { var queueableFn1 = { fn: jasmine.createSpy('fn1') }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, queueableFn3 = { fn: function(done) { asyncContext = this; done(); } }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2, queueableFn3] }), asyncContext; queueRunner.execute(); var context = queueableFn1.fn.calls.first().object; expect(context).toEqual(new jasmineUnderTest.UserContext()); expect(queueableFn2.fn.calls.first().object).toBe(context); expect(asyncContext).toBe(context); }); describe('with an asynchronous function', function() { beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it('supports asynchronous functions, only advancing to next function after a done() callback', function() { //TODO: it would be nice if spy arity could match the fake, so we could do something like: //createSpy('asyncfn').and.callFake(function(done) {}); var onComplete = jasmine.createSpy('onComplete'), beforeCallback = jasmine.createSpy('beforeCallback'), fnCallback = jasmine.createSpy('fnCallback'), afterCallback = jasmine.createSpy('afterCallback'), queueableFn1 = { fn: function(done) { beforeCallback(); setTimeout(done, 100); } }, queueableFn2 = { fn: function(done) { fnCallback(); setTimeout(done, 100); } }, queueableFn3 = { fn: function(done) { afterCallback(); setTimeout(done, 100); } }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2, queueableFn3], onComplete: onComplete }); queueRunner.execute(); expect(beforeCallback).toHaveBeenCalled(); expect(fnCallback).not.toHaveBeenCalled(); expect(afterCallback).not.toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(fnCallback).toHaveBeenCalled(); expect(afterCallback).not.toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(afterCallback).toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(onComplete).toHaveBeenCalled(); }); it('explicitly fails an async function with a provided fail function and moves to the next function', function() { var queueableFn1 = { fn: function(done) { setTimeout(function() { done.fail('foo'); }, 100); } }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, failFn = jasmine.createSpy('fail'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], fail: failFn }); queueRunner.execute(); expect(failFn).not.toHaveBeenCalled(); expect(queueableFn2.fn).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(failFn).toHaveBeenCalledWith('foo'); expect(queueableFn2.fn).toHaveBeenCalled(); }); describe('When next is called with an argument', function() { it('explicitly fails and moves to the next function', function() { var err = 'anything except undefined', queueableFn1 = { fn: function(done) { setTimeout(function() { done(err); }, 100); } }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, failFn = jasmine.createSpy('fail'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], fail: failFn }); queueRunner.execute(); expect(failFn).not.toHaveBeenCalled(); expect(queueableFn2.fn).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(failFn).toHaveBeenCalledWith(err); expect(queueableFn2.fn).toHaveBeenCalled(); }); }); it('does not cause an explicit fail if execution is being stopped', function() { var err = new jasmineUnderTest.StopExecutionError('foo'), queueableFn1 = { fn: function(done) { setTimeout(function() { done(err); }, 100); } }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, failFn = jasmine.createSpy('fail'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], fail: failFn }); queueRunner.execute(); expect(failFn).not.toHaveBeenCalled(); expect(queueableFn2.fn).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(failFn).not.toHaveBeenCalled(); expect(queueableFn2.fn).toHaveBeenCalled(); }); it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() { var timeout = 3, beforeFn = { fn: function(done) {}, type: 'before', timeout: timeout }, queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' }, onComplete = jasmine.createSpy('onComplete'), onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [beforeFn, queueableFn], onComplete: onComplete, onException: onException }); queueRunner.execute(); expect(queueableFn.fn).not.toHaveBeenCalled(); jasmine.clock().tick(timeout); expect(onException).toHaveBeenCalledWith(jasmine.any(Error)); expect(queueableFn.fn).toHaveBeenCalled(); expect(onComplete).toHaveBeenCalled(); }); it('does not call onMultipleDone if an asynchrnous function completes after timing out', function() { var timeout = 3, queueableFn = { fn: function(done) { queueableFnDone = done; }, type: 'queueable', timeout: timeout }, onComplete = jasmine.createSpy('onComplete'), onMultipleDone = jasmine.createSpy('onMultipleDone'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onComplete: onComplete, onMultipleDone: onMultipleDone }), queueableFnDone; queueRunner.execute(); jasmine.clock().tick(timeout); queueableFnDone(); expect(onComplete).toHaveBeenCalled(); expect(onMultipleDone).not.toHaveBeenCalled(); }); it('by default does not set a timeout for asynchronous functions', function() { var beforeFn = { fn: function(done) {} }, queueableFn = { fn: jasmine.createSpy('fn') }, onComplete = jasmine.createSpy('onComplete'), onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [beforeFn, queueableFn], onComplete: onComplete, onException: onException }); queueRunner.execute(); expect(queueableFn.fn).not.toHaveBeenCalled(); jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL); expect(onException).not.toHaveBeenCalled(); expect(queueableFn.fn).not.toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); }); it('clears the timeout when an async function throws an exception, to prevent additional exception reporting', function() { var queueableFn = { fn: function(done) { throw new Error('error!'); } }, onComplete = jasmine.createSpy('onComplete'), onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onComplete: onComplete, onException: onException }); queueRunner.execute(); expect(onComplete).toHaveBeenCalled(); expect(onException).toHaveBeenCalled(); jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL); expect(onException.calls.count()).toEqual(1); }); it('clears the timeout when the done callback is called', function() { var queueableFn = { fn: function(done) { done(); } }, onComplete = jasmine.createSpy('onComplete'), onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onComplete: onComplete, onException: onException }); queueRunner.execute(); jasmine.clock().tick(1); expect(onComplete).toHaveBeenCalled(); jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL); expect(onException).not.toHaveBeenCalled(); }); it('only moves to the next spec the first time you call done', function() { var queueableFn = { fn: function(done) { done(); done(); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFn') }, onMultipleDone = jasmine.createSpy('onMultipleDone'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn], onMultipleDone: onMultipleDone }); queueRunner.execute(); jasmine.clock().tick(1); expect(nextQueueableFn.fn.calls.count()).toEqual(1); expect(onMultipleDone).toHaveBeenCalled(); }); it('does not move to the next spec if done is called after an exception has ended the spec', function() { var queueableFn = { fn: function(done) { setTimeout(done, 1); throw new Error('error!'); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFn') }, deprecated = jasmine.createSpy('deprecated'), queueRunner = new jasmineUnderTest.QueueRunner({ deprecated: deprecated, queueableFns: [queueableFn, nextQueueableFn] }); queueRunner.execute(); jasmine.clock().tick(1); expect(nextQueueableFn.fn.calls.count()).toEqual(1); // Don't issue a deprecation. The error already tells the user that // something went wrong. expect(deprecated).not.toHaveBeenCalled(); }); it('should return a null when you call done', function() { // Some promises want handlers to return anything but undefined to help catch "forgotten returns". var doneReturn, queueableFn = { fn: function(done) { doneReturn = done(); } }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn] }); queueRunner.execute(); expect(doneReturn).toBe(null); }); it('continues running functions when an exception is thrown in async code without timing out', function() { var queueableFn = { fn: function(done) { throwAsync(); }, timeout: 1 }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, onException = jasmine.createSpy('onException'), globalErrors = { pushListener: jasmine.createSpy('pushListener'), popListener: jasmine.createSpy('popListener') }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn], onException: onException, globalErrors: globalErrors }), throwAsync = function() { globalErrors.pushListener.calls .mostRecent() .args[0](new Error('foo')); jasmine.clock().tick(2); }; nextQueueableFn.fn.and.callFake(function() { // should remove the same function that was added expect(globalErrors.popListener).toHaveBeenCalledWith( globalErrors.pushListener.calls.argsFor(1)[0] ); }); queueRunner.execute(); function errorWithMessage(message) { return { asymmetricMatch: function(other) { return new RegExp(message).test(other.message); }, toString: function() { return ''; } }; } expect(onException).not.toHaveBeenCalledWith( errorWithMessage(/DEFAULT_TIMEOUT_INTERVAL/) ); expect(onException).toHaveBeenCalledWith(errorWithMessage(/^foo$/)); expect(nextQueueableFn.fn).toHaveBeenCalled(); }); it('handles exceptions thrown while waiting for the stack to clear', function() { var queueableFn = { fn: function(done) { done(); } }, errorListeners = [], globalErrors = { pushListener: function(f) { errorListeners.push(f); }, popListener: function() { errorListeners.pop(); } }, clearStack = jasmine.createSpy('clearStack'), onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], globalErrors: globalErrors, clearStack: clearStack, onException: onException }), error = new Error('nope'); queueRunner.execute(); jasmine.clock().tick(); expect(clearStack).toHaveBeenCalled(); expect(errorListeners.length).toEqual(1); errorListeners[0](error); clearStack.calls.argsFor(0)[0](); expect(onException).toHaveBeenCalledWith(error); }); }); describe('with a function that returns a promise', function() { function StubPromise() {} StubPromise.prototype.then = function(resolve, reject) { this.resolveHandler = resolve; this.rejectHandler = reject; }; beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it('runs the function asynchronously, advancing once the promise is settled', function() { var onComplete = jasmine.createSpy('onComplete'), fnCallback = jasmine.createSpy('fnCallback'), p1 = new StubPromise(), p2 = new StubPromise(), queueableFn1 = { fn: function() { setTimeout(function() { p1.resolveHandler(); }, 100); return p1; } }, queueableFn2 = { fn: function() { fnCallback(); setTimeout(function() { p2.resolveHandler(); }, 100); return p2; } }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], onComplete: onComplete }); queueRunner.execute(); expect(fnCallback).not.toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(fnCallback).toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(onComplete).toHaveBeenCalled(); }); it('handles a rejected promise like an unhandled exception', function() { var promise = new StubPromise(), queueableFn1 = { fn: function() { setTimeout(function() { promise.rejectHandler('foo'); }, 100); return promise; } }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, onExceptionCallback = jasmine.createSpy('on exception callback'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], onException: onExceptionCallback }); queueRunner.execute(); expect(onExceptionCallback).not.toHaveBeenCalled(); expect(queueableFn2.fn).not.toHaveBeenCalled(); jasmine.clock().tick(100); expect(onExceptionCallback).toHaveBeenCalledWith('foo'); expect(queueableFn2.fn).toHaveBeenCalled(); }); it('issues an error if the function also takes a parameter', function() { var queueableFn = { fn: function(done) { return new StubPromise(); } }, onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onException: onException }); queueRunner.execute(); expect(onException).toHaveBeenCalledWith( 'An asynchronous ' + 'before/it/after function took a done callback but also returned a ' + 'promise. ' + 'Either remove the done callback (recommended) or change the function ' + 'to not return a promise.' ); }); it('issues a more specific error if the function is `async`', function() { eval('var fn = async function(done){};'); var onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [{ fn: fn }], onException: onException }); queueRunner.execute(); expect(onException).toHaveBeenCalledWith( 'An asynchronous ' + 'before/it/after function was defined with the async keyword but ' + 'also took a done callback. Either remove the done callback ' + '(recommended) or remove the async keyword.' ); }); }); it('passes the error instance to exception handlers in HTML browsers', function() { var error = new Error('fake error'), onExceptionCallback = jasmine.createSpy('on exception callback'), queueRunner = new jasmineUnderTest.QueueRunner({ onException: onExceptionCallback }); queueRunner.execute(); queueRunner.handleFinalError(error.message, 'fake.js', 1, 1, error); expect(onExceptionCallback).toHaveBeenCalledWith(error); }); it('passes the first argument to exception handlers for compatibility', function() { var error = new Error('fake error'), onExceptionCallback = jasmine.createSpy('on exception callback'), queueRunner = new jasmineUnderTest.QueueRunner({ onException: onExceptionCallback }); queueRunner.execute(); queueRunner.handleFinalError(error.message); expect(onExceptionCallback).toHaveBeenCalledWith(error.message); }); it('calls exception handlers when an exception is thrown in a fn', function() { var queueableFn = { type: 'queueable', fn: function() { throw new Error('fake error'); } }, onExceptionCallback = jasmine.createSpy('on exception callback'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onException: onExceptionCallback }); queueRunner.execute(); expect(onExceptionCallback).toHaveBeenCalledWith(jasmine.any(Error)); }); it('continues running the functions even after an exception is thrown in an async spec', function() { var queueableFn = { fn: function(done) { throw new Error('error'); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn] }); queueRunner.execute(); expect(nextQueueableFn.fn).toHaveBeenCalled(); }); describe('When configured with a skip policy', function() { it('instantiates the skip policy', function() { const SkipPolicy = jasmine.createSpy('SkipPolicy ctor'); const queueableFns = [{ fn: () => {} }, { fn: () => {} }]; new jasmineUnderTest.QueueRunner({ queueableFns, SkipPolicy }); expect(SkipPolicy).toHaveBeenCalledWith(queueableFns); }); it('uses the skip policy to determine which fn to run next', function() { const queueableFns = [ { fn: jasmine.createSpy('fn0') }, { fn: jasmine.createSpy('fn1') }, { fn: jasmine.createSpy('fn2').and.throwError(new Error('nope')) }, { fn: jasmine.createSpy('fn3') } ]; const skipPolicy = jasmine.createSpyObj('skipPolicy', [ 'skipTo', 'fnErrored' ]); skipPolicy.skipTo.and.callFake(function(lastRanIx) { return lastRanIx === 0 ? 2 : lastRanIx + 1; }); const queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns, SkipPolicy: function() { return skipPolicy; } }); queueRunner.execute(); expect(skipPolicy.skipTo).toHaveBeenCalledWith(0); expect(skipPolicy.skipTo).toHaveBeenCalledWith(2); expect(skipPolicy.fnErrored).toHaveBeenCalledWith(2); expect(queueableFns[0].fn).toHaveBeenCalled(); expect(queueableFns[1].fn).not.toHaveBeenCalled(); expect(queueableFns[2].fn).toHaveBeenCalled(); expect(queueableFns[3].fn).toHaveBeenCalled(); }); it('throws if the skip policy returns the current fn', function() { const skipPolicy = { skipTo: i => i }; const queueableFns = [{ fn: () => {} }]; const queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns, SkipPolicy: function() { return skipPolicy; } }); expect(function() { queueRunner.execute(); }).toThrowError("Can't skip to the same queueable fn that just finished"); }); }); describe('When configured to complete on first error', function() { it('skips to cleanup functions on the first exception', function() { var queueableFn = { fn: function() { throw new Error('error'); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, onComplete = jasmine.createSpy('onComplete'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn, cleanupFn], onComplete: onComplete, SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled(); expect(onComplete).toHaveBeenCalledWith( jasmine.any(jasmineUnderTest.StopExecutionError) ); }); it('does not skip when a cleanup function throws', function() { var queueableFn = { fn: function() {} }, cleanupFn1 = { fn: function() { throw new Error('error'); }, type: 'afterEach' }, cleanupFn2 = { fn: jasmine.createSpy('cleanupFn2'), type: 'afterEach' }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, cleanupFn1, cleanupFn2], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); expect(cleanupFn2.fn).toHaveBeenCalled(); }); describe('with an asynchronous function', function() { beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it('skips to cleanup functions once the fn completes after an unhandled exception', function() { var errorListeners = [], queueableFn = { fn: function(done) { queueableFnDone = done; } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, queueRunner = new jasmineUnderTest.QueueRunner({ globalErrors: { pushListener: function(f) { errorListeners.push(f); }, popListener: function() { errorListeners.pop(); } }, queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }), queueableFnDone; queueRunner.execute(); errorListeners[errorListeners.length - 1](new Error('error')); expect(cleanupFn.fn).not.toHaveBeenCalled(); queueableFnDone(); expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled(); }); it('skips to cleanup functions when next.fail is called', function() { var queueableFn = { fn: function(done) { done.fail('nope'); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); jasmine.clock().tick(); expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled(); }); it('skips to cleanup functions when next is called with an Error', function() { var queueableFn = { fn: function(done) { done(new Error('nope')); } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); jasmine.clock().tick(); expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled(); }); }); }); it('calls a provided complete callback when done', function() { var queueableFn = { fn: jasmine.createSpy('fn') }, completeCallback = jasmine.createSpy('completeCallback'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], onComplete: completeCallback }); queueRunner.execute(); expect(completeCallback).toHaveBeenCalled(); }); describe('clearing the stack', function() { beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it('calls a provided stack clearing function when done', function() { var asyncFn = { fn: function(done) { done(); } }, afterFn = { fn: jasmine.createSpy('afterFn') }, completeCallback = jasmine.createSpy('completeCallback'), clearStack = jasmine.createSpy('clearStack'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [asyncFn, afterFn], clearStack: clearStack, onComplete: completeCallback }); clearStack.and.callFake(function(fn) { fn(); }); queueRunner.execute(); jasmine.clock().tick(); expect(afterFn.fn).toHaveBeenCalled(); expect(clearStack).toHaveBeenCalled(); clearStack.calls.argsFor(0)[0](); expect(completeCallback).toHaveBeenCalled(); }); }); describe('when user context has not been defined', function() { beforeEach(function() { var fn; this.fn = fn = jasmine.createSpy('fn1'); this.queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [{ fn: fn }] }); }); it('runs the functions on the scope of a UserContext', function() { var context; this.fn.and.callFake(function() { context = this; }); this.queueRunner.execute(); expect(context.constructor).toBe(jasmineUnderTest.UserContext); }); }); describe('when user context has been defined', function() { beforeEach(function() { var fn, context; this.fn = fn = jasmine.createSpy('fn1'); this.context = context = new jasmineUnderTest.UserContext(); this.queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [{ fn: fn }], userContext: context }); }); it('runs the functions on the scope of a UserContext', function() { var context; this.fn.and.callFake(function() { context = this; }); this.queueRunner.execute(); expect(context).toBe(this.context); }); }); }); jasmine-4.0.0/spec/core/ReportDispatcherSpec.js000066400000000000000000000133461416413636100214720ustar00rootroot00000000000000describe('ReportDispatcher', function() { it('builds an interface of requested methods', function() { var dispatcher = new jasmineUnderTest.ReportDispatcher([ 'foo', 'bar', 'baz' ]); expect(dispatcher.foo).toBeDefined(); expect(dispatcher.bar).toBeDefined(); expect(dispatcher.baz).toBeDefined(); }); it('dispatches requested methods to added reporters', function() { var queueRunnerFactory = jasmine.createSpy('queueRunner'), dispatcher = new jasmineUnderTest.ReportDispatcher( ['foo', 'bar'], queueRunnerFactory ), reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']), anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']), completeCallback = jasmine.createSpy('complete'); dispatcher.addReporter(reporter); dispatcher.addReporter(anotherReporter); dispatcher.foo(123, 456, completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) } ], isReporter: true }) ); var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter.foo).toHaveBeenCalledWith(123, 456); expect(reporter.foo.calls.mostRecent().object).toBe(reporter); fns[1].fn(); expect(anotherReporter.foo).toHaveBeenCalledWith(123, 456); expect(anotherReporter.foo.calls.mostRecent().object).toBe(anotherReporter); queueRunnerFactory.calls.reset(); dispatcher.bar('a', 'b', completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) } ], isReporter: true }) ); fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter.bar).toHaveBeenCalledWith('a', 'b'); fns[1].fn(); expect(anotherReporter.bar).toHaveBeenCalledWith('a', 'b'); }); it("does not dispatch to a reporter if the reporter doesn't accept the method", function() { var queueRunnerFactory = jasmine.createSpy('queueRunner'), dispatcher = new jasmineUnderTest.ReportDispatcher( ['foo'], queueRunnerFactory ), reporter = jasmine.createSpyObj('reporter', ['baz']); dispatcher.addReporter(reporter); dispatcher.foo(123, 456); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [] }) ); }); it("allows providing a fallback reporter in case there's no other reporter", function() { var queueRunnerFactory = jasmine.createSpy('queueRunner'), dispatcher = new jasmineUnderTest.ReportDispatcher( ['foo', 'bar'], queueRunnerFactory ), reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']), completeCallback = jasmine.createSpy('complete'); dispatcher.provideFallbackReporter(reporter); dispatcher.foo(123, 456, completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [{ fn: jasmine.any(Function) }], isReporter: true }) ); var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter.foo).toHaveBeenCalledWith(123, 456); }); it('does not call fallback reporting methods when another reporter is provided', function() { var queueRunnerFactory = jasmine.createSpy('queueRunner'), dispatcher = new jasmineUnderTest.ReportDispatcher( ['foo', 'bar'], queueRunnerFactory ), reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']), fallbackReporter = jasmine.createSpyObj('otherReporter', ['foo', 'bar']), completeCallback = jasmine.createSpy('complete'); dispatcher.provideFallbackReporter(fallbackReporter); dispatcher.addReporter(reporter); dispatcher.foo(123, 456, completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [{ fn: jasmine.any(Function) }], isReporter: true }) ); var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter.foo).toHaveBeenCalledWith(123, 456); expect(fallbackReporter.foo).not.toHaveBeenCalledWith(123, 456); }); it('allows registered reporters to be cleared', function() { var queueRunnerFactory = jasmine.createSpy('queueRunner'), dispatcher = new jasmineUnderTest.ReportDispatcher( ['foo', 'bar'], queueRunnerFactory ), reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']), reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']), completeCallback = jasmine.createSpy('complete'); dispatcher.addReporter(reporter1); dispatcher.foo(123, completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [{ fn: jasmine.any(Function) }], isReporter: true }) ); var fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter1.foo).toHaveBeenCalledWith(123); dispatcher.clearReporters(); dispatcher.addReporter(reporter2); dispatcher.bar(456, completeCallback); expect(queueRunnerFactory).toHaveBeenCalledWith( jasmine.objectContaining({ queueableFns: [{ fn: jasmine.any(Function) }], isReporter: true }) ); fns = queueRunnerFactory.calls.mostRecent().args[0].queueableFns; fns[0].fn(); expect(reporter1.bar).not.toHaveBeenCalled(); expect(reporter2.bar).toHaveBeenCalledWith(456); }); }); jasmine-4.0.0/spec/core/SkipAfterBeforeAllErrorPolicySpec.js000066400000000000000000000051251416413636100240420ustar00rootroot00000000000000describe('SkipAfterBeforeAllErrorPolicy', function() { describe('#skipTo', function() { describe('When nothing has errored', function() { it('does not skip anything', function() { const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( arrayOfArbitraryFns(4) ); expect(policy.skipTo(0)).toEqual(1); expect(policy.skipTo(1)).toEqual(2); expect(policy.skipTo(2)).toEqual(3); expect(policy.skipTo(3)).toEqual(4); }); }); describe('When anything but a beforeAll has errored', function() { it('does not skip anything', function() { const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( arrayOfArbitraryFns(4) ); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); policy.fnErrored(1); expect(policy.skipTo(1)).toEqual(2); policy.fnErrored(2); expect(policy.skipTo(2)).toEqual(3); policy.fnErrored(3); expect(policy.skipTo(3)).toEqual(4); }); }); describe('When a beforeAll has errored', function() { it('skips subsequent functions other than afterAll', function() { const suite = {}; const fns = [ { type: 'beforeAll', fn: () => {}, suite }, { fn: () => {} }, { fn: () => {} }, { type: 'afterAll', fn: () => {} }, { type: 'afterAll', fn: () => {} } ]; const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(3); expect(policy.skipTo(3)).toEqual(4); }); }); }); describe('#fnErrored', function() { describe('When the fn is a beforeAll', function() { it("sets the suite's hadBeforeAllFailure property to true", function() { const suite = {}; const fns = [{ type: 'beforeAll', fn: () => {}, suite }]; const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); policy.fnErrored(0); expect(suite.hadBeforeAllFailure).toBeTrue(); }); }); describe('When the fn is not a beforeAll', function() { it('does not try to access the suite, which is probably not there', function() { const fns = [{ fn: () => {} /* no suite */ }]; const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); expect(() => policy.fnErrored(0)).not.toThrow(); }); }); }); }); function arrayOfArbitraryFns(n) { const result = []; for (let i = 0; i < n; i++) { result.push({ fn: () => {} }); } return result; } jasmine-4.0.0/spec/core/SpecSpec.js000066400000000000000000000507741416413636100171100ustar00rootroot00000000000000describe('Spec', function() { it('#isPendingSpecException returns true for a pending spec exception', function() { var e = new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage); expect(jasmineUnderTest.Spec.isPendingSpecException(e)).toBe(true); }); it('#isPendingSpecException returns true for a pending spec exception (even when FF bug is present)', function() { var fakeError = { toString: function() { return 'Error: ' + jasmineUnderTest.Spec.pendingSpecExceptionMessage; } }; expect(jasmineUnderTest.Spec.isPendingSpecException(fakeError)).toBe(true); }); it('#isPendingSpecException returns true for a pending spec exception with a custom message', function() { expect( jasmineUnderTest.Spec.isPendingSpecException( jasmineUnderTest.Spec.pendingSpecExceptionMessage + 'foo' ) ).toBe(true); }); it('#isPendingSpecException returns false for not a pending spec exception', function() { var e = new Error('foo'); expect(jasmineUnderTest.Spec.isPendingSpecException(e)).toBe(false); }); it("#isPendingSpecException returns false for thrown values that don't have toString", function() { expect(jasmineUnderTest.Spec.isPendingSpecException(void 0)).toBe(false); }); it('delegates execution to a QueueRunner', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), spec = new jasmineUnderTest.Spec({ description: 'my test', id: 'some-id', queueableFn: { fn: function() {} }, queueRunnerFactory: fakeQueueRunner }); spec.execute(); expect(fakeQueueRunner).toHaveBeenCalled(); }); it('should call the start callback on execution', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), startCallback = jasmine.createSpy('startCallback'), spec = new jasmineUnderTest.Spec({ id: 123, description: 'foo bar', queueableFn: { fn: function() {} }, onStart: startCallback, queueRunnerFactory: fakeQueueRunner }); spec.execute(); fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); expect(startCallback.calls.first().object).toEqual(spec); }); it('should call the start callback on execution but before any befores are called', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), beforesWereCalled = false, startCallback = jasmine .createSpy('start-callback') .and.callFake(function() { expect(beforesWereCalled).toBe(false); }), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, beforeFns: function() { return [ function() { beforesWereCalled = true; } ]; }, onStart: startCallback, queueRunnerFactory: fakeQueueRunner }); spec.execute(); fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); }); it('provides all before fns and after fns to be run', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), before = jasmine.createSpy('before'), after = jasmine.createSpy('after'), queueableFn = { fn: jasmine.createSpy('test body').and.callFake(function() { expect(before).toHaveBeenCalled(); expect(after).not.toHaveBeenCalled(); }) }, spec = new jasmineUnderTest.Spec({ queueableFn: queueableFn, beforeAndAfterFns: function() { return { befores: [before], afters: [after] }; }, queueRunnerFactory: fakeQueueRunner }); spec.execute(); var options = fakeQueueRunner.calls.mostRecent().args[0]; expect(options.queueableFns).toEqual([ { fn: jasmine.any(Function) }, before, queueableFn, after, { fn: jasmine.any(Function), type: 'specCleanup' } ]); }); it("tells the queue runner that it's a leaf node", function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, beforeAndAfterFns: function() { return { befores: [], afters: [] }; }, queueRunnerFactory: fakeQueueRunner }); spec.execute(); expect(fakeQueueRunner).toHaveBeenCalledWith( jasmine.objectContaining({ isLeaf: true }) ); }); it('is marked pending if created without a function body', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), startCallback = jasmine.createSpy('startCallback'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ onStart: startCallback, queueableFn: { fn: null }, resultCallback: resultCallback, queueRunnerFactory: fakeQueueRunner }); expect(spec.status()).toBe('pending'); }); it('can be excluded at execution time by a parent', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), startCallback = jasmine.createSpy('startCallback'), specBody = jasmine.createSpy('specBody'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ onStart: startCallback, queueableFn: { fn: specBody }, resultCallback: resultCallback, queueRunnerFactory: fakeQueueRunner }); spec.execute('cally-back', true); expect(fakeQueueRunner).toHaveBeenCalledWith( jasmine.objectContaining({ onComplete: jasmine.any(Function), queueableFns: [ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function), type: 'specCleanup' } ] }) ); expect(specBody).not.toHaveBeenCalled(); var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback).toHaveBeenCalled(); expect(spec.result.status).toBe('excluded'); }); it('can be marked pending, but still calls callbacks when executed', function() { var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), startCallback = jasmine.createSpy('startCallback'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ onStart: startCallback, resultCallback: resultCallback, description: 'with a spec', getSpecName: function() { return 'a suite with a spec'; }, queueRunnerFactory: fakeQueueRunner, queueableFn: { fn: null } }); spec.pend(); expect(spec.status()).toBe('pending'); spec.execute(); expect(fakeQueueRunner).toHaveBeenCalled(); var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); args.queueableFns[1].fn('things'); expect(resultCallback).toHaveBeenCalledWith( { id: spec.id, status: 'pending', description: 'with a spec', fullName: 'a suite with a spec', failedExpectations: [], passedExpectations: [], deprecationWarnings: [], pendingReason: '', duration: jasmine.any(Number), properties: null, debugLogs: null }, 'things' ); }); it('should call the done callback on execution complete', function() { var done = jasmine.createSpy('done callback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, catchExceptions: function() { return false; }, resultCallback: function() {}, queueRunnerFactory: function(attrs) { attrs.onComplete(); } }); spec.execute(done); expect(done).toHaveBeenCalled(); }); it('should call the done callback with an error if the spec is failed', function() { var done = jasmine.createSpy('done callback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, catchExceptions: function() { return false; }, resultCallback: function() {}, queueRunnerFactory: function(attrs) { spec.result.status = 'failed'; attrs.onComplete(); } }); spec.execute(done); expect(done).toHaveBeenCalledWith( jasmine.any(jasmineUnderTest.StopExecutionError) ); }); it('should report the duration of the test', function() { var timer = jasmine.createSpyObj('timer', { start: null, elapsed: 77000 }), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') }, catchExceptions: function() { return false; }, resultCallback: function(result) { duration = result.duration; }, queueRunnerFactory: function(config) { config.queueableFns.forEach(function(qf) { qf.fn(); }); config.onComplete(); }, timer: timer }), duration = undefined; spec.execute(function() {}); expect(duration).toBe(77000); }); it('should report properties set during the test', function() { var done = jasmine.createSpy('done callback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') }, catchExceptions: function() { return false; }, resultCallback: function() {}, queueRunnerFactory: function(attrs) { attrs.onComplete(); } }); spec.setSpecProperty('a', 4); spec.execute(done); expect(spec.result.properties).toEqual({ a: 4 }); }); it('#status returns passing by default', function() { var spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') } }); expect(spec.status()).toBe('passed'); }); it('#status returns passed if all expectations in the spec have passed', function() { var spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') } }); spec.addExpectationResult(true); expect(spec.status()).toBe('passed'); }); it('#status returns failed if any expectations in the spec have failed', function() { var spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') } }); spec.addExpectationResult(true); spec.addExpectationResult(false); expect(spec.status()).toBe('failed'); }); it('keeps track of passed and failed expectations', function() { var fakeQueueRunner = jasmine.createSpy('queueRunner'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') }, expectationResultFactory: function(data) { return data; }, queueRunnerFactory: fakeQueueRunner, resultCallback: resultCallback }); spec.addExpectationResult(true, 'expectation1'); spec.addExpectationResult(false, 'expectation2'); spec.execute(); const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns; fns[fns.length - 1].fn(); expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([ 'expectation1' ]); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([ 'expectation2' ]); }); it("throws an ExpectationFailed error upon receiving a failed expectation when 'throwOnExpectationFailure' is set", function() { var fakeQueueRunner = jasmine.createSpy('queueRunner'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, expectationResultFactory: function(data) { return data; }, queueRunnerFactory: fakeQueueRunner, resultCallback: resultCallback, throwOnExpectationFailure: true }); spec.addExpectationResult(true, 'passed'); expect(function() { spec.addExpectationResult(false, 'failed'); }).toThrowError(jasmineUnderTest.errors.ExpectationFailed); spec.execute(); const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns; fns[fns.length - 1].fn(); expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([ 'passed' ]); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([ 'failed' ]); }); it('does not throw an ExpectationFailed error when handling an error', function() { var resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, expectationResultFactory: function(data) { return data; }, queueRunnerFactory: function(attrs) { attrs.onComplete(); }, resultCallback: resultCallback, throwOnExpectationFailure: true }); spec.onException('failing exception'); }); it('can return its full name', function() { var specNameSpy = jasmine .createSpy('specNameSpy') .and.returnValue('expected val'); var spec = new jasmineUnderTest.Spec({ getSpecName: specNameSpy, queueableFn: { fn: null } }); expect(spec.getFullName()).toBe('expected val'); expect(specNameSpy.calls.mostRecent().args[0].id).toEqual(spec.id); }); describe('when a spec is marked pending during execution', function() { it('should mark the spec as pending', function() { var fakeQueueRunner = function(opts) { opts.onException( new Error(jasmineUnderTest.Spec.pendingSpecExceptionMessage) ); }, spec = new jasmineUnderTest.Spec({ description: 'my test', id: 'some-id', queueableFn: { fn: function() {} }, queueRunnerFactory: fakeQueueRunner }); spec.execute(); expect(spec.status()).toEqual('pending'); expect(spec.result.pendingReason).toEqual(''); }); it('should set the pendingReason', function() { var fakeQueueRunner = function(opts) { opts.onException( new Error( jasmineUnderTest.Spec.pendingSpecExceptionMessage + 'custom message' ) ); }, spec = new jasmineUnderTest.Spec({ description: 'my test', id: 'some-id', queueableFn: { fn: function() {} }, queueRunnerFactory: fakeQueueRunner }); spec.execute(); expect(spec.status()).toEqual('pending'); expect(spec.result.pendingReason).toEqual('custom message'); }); }); it('should log a failure when handling an exception', function() { var fakeQueueRunner = jasmine.createSpy('queueRunner'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, expectationResultFactory: function(data) { return data; }, queueRunnerFactory: fakeQueueRunner, resultCallback: resultCallback }); spec.onException('foo'); spec.execute(); var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([ { error: 'foo', matcherName: '', passed: false, expected: '', actual: '' } ]); }); it('should not log an additional failure when handling an ExpectationFailed error', function() { var fakeQueueRunner = jasmine.createSpy('queueRunner'), resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, expectationResultFactory: function(data) { return data; }, queueRunnerFactory: fakeQueueRunner, resultCallback: resultCallback }); spec.onException(new jasmineUnderTest.errors.ExpectationFailed()); spec.execute(); var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]); }); it('treats multiple done calls as late errors', function() { var queueRunnerFactory = jasmine.createSpy('queueRunnerFactory'), onLateError = jasmine.createSpy('onLateError'), spec = new jasmineUnderTest.Spec({ onLateError: onLateError, queueableFn: { fn: function() {} }, queueRunnerFactory: queueRunnerFactory, getSpecName: function() { return 'a spec'; } }); spec.execute(); expect(queueRunnerFactory).toHaveBeenCalled(); queueRunnerFactory.calls.argsFor(0)[0].onMultipleDone(); expect(onLateError).toHaveBeenCalledTimes(1); expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); expect(onLateError.calls.argsFor(0)[0].message).toEqual( 'An asynchronous spec, beforeEach, or afterEach function called its ' + "'done' callback more than once.\n(in spec: a spec)" ); }); describe('#trace', function() { it('adds the messages to the result', function() { var timer = jasmine.createSpyObj('timer', ['start', 'elapsed']), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, queueRunnerFactory: function() {}, timer: timer }), t1 = 123, t2 = 456; spec.execute(); expect(spec.result.debugLogs).toBeNull(); timer.elapsed.and.returnValue(t1); spec.debugLog('msg 1'); expect(spec.result.debugLogs).toEqual([ { message: 'msg 1', timestamp: t1 } ]); timer.elapsed.and.returnValue(t2); spec.debugLog('msg 2'); expect(spec.result.debugLogs).toEqual([ { message: 'msg 1', timestamp: t1 }, { message: 'msg 2', timestamp: t2 } ]); }); describe('When the spec passes', function() { it('omits the messages from the reported result', function() { var resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, resultCallback: resultCallback, queueRunnerFactory: function(config) { spec.debugLog('msg'); for (const fn of config.queueableFns) { fn.fn(); } config.onComplete(false); } }); spec.execute(function() {}); expect(resultCallback).toHaveBeenCalledWith( jasmine.objectContaining({ debugLogs: null }), undefined ); }); it('removes the messages to save memory', function() { var resultCallback = jasmine.createSpy('resultCallback'), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, resultCallback: resultCallback, queueRunnerFactory: function(config) { spec.debugLog('msg'); for (const fn of config.queueableFns) { fn.fn(); } config.onComplete(false); } }); spec.execute(function() {}); expect(resultCallback).toHaveBeenCalled(); expect(spec.result.debugLogs).toBeNull(); }); }); describe('When the spec fails', function() { it('includes the messages in the reported result', function() { var resultCallback = jasmine.createSpy('resultCallback'), timer = jasmine.createSpyObj('timer', ['start', 'elapsed']), spec = new jasmineUnderTest.Spec({ queueableFn: { fn: function() {} }, resultCallback: resultCallback, queueRunnerFactory: function(config) { spec.debugLog('msg'); spec.onException(new Error('nope')); for (const fn of config.queueableFns) { fn.fn(); } config.onComplete(true); }, timer: timer }), timestamp = 12345; timer.elapsed.and.returnValue(timestamp); spec.execute(function() {}); expect(resultCallback).toHaveBeenCalledWith( jasmine.objectContaining({ debugLogs: [{ message: 'msg', timestamp: timestamp }] }), undefined ); }); }); }); }); jasmine-4.0.0/spec/core/SpyRegistrySpec.js000066400000000000000000000476151416413636100205220ustar00rootroot00000000000000describe('SpyRegistry', function() { function createSpy(name, originalFn) { return jasmineUnderTest.Spy(name, originalFn); } describe('#spyOn', function() { it('checks for the existence of the object', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }); expect(function() { spyRegistry.spyOn(void 0, 'pants'); }).toThrowError(/could not find an object/); }); it('checks that a method name was passed', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; expect(function() { spyRegistry.spyOn(subject); }).toThrowError(/No method name supplied/); }); it('checks that the object is not `null`', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(); expect(function() { spyRegistry.spyOn(null, 'pants'); }).toThrowError(/could not find an object/); }); it('checks that the method name is not `null`', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; expect(function() { spyRegistry.spyOn(subject, null); }).toThrowError(/No method name supplied/); }); it('checks for the existence of the method', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; expect(function() { spyRegistry.spyOn(subject, 'pants'); }).toThrowError(/method does not exist/); }); it('checks if it has already been spied upon', function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), subject = { spiedFunc: function() {} }; spyRegistry.spyOn(subject, 'spiedFunc'); expect(function() { spyRegistry.spyOn(subject, 'spiedFunc'); }).toThrowError(/has already been spied upon/); }); it('checks if it can be spied upon', function() { var scope = {}; function myFunc() { return 1; } Object.defineProperty(scope, 'myFunc', { get: function() { return myFunc; } }); var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; } }), subject = { spiedFunc: scope.myFunc }; expect(function() { spyRegistry.spyOn(scope, 'myFunc'); }).toThrowError(/is not declared writable or has no setter/); expect(function() { spyRegistry.spyOn(subject, 'spiedFunc'); }).not.toThrowError(/is not declared writable or has no setter/); }); it('overrides the method on the object and returns the spy', function() { var originalFunctionWasCalled = false, spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }), subject = { spiedFunc: function() { originalFunctionWasCalled = true; } }; var spy = spyRegistry.spyOn(subject, 'spiedFunc'); expect(subject.spiedFunc).toEqual(spy); subject.spiedFunc(); expect(originalFunctionWasCalled).toBe(false); }); }); describe('#spyOnProperty', function() { it('checks for the existence of the object', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(); expect(function() { spyRegistry.spyOnProperty(void 0, 'pants'); }).toThrowError(/could not find an object/); }); it('checks that a property name was passed', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; expect(function() { spyRegistry.spyOnProperty(subject); }).toThrowError(/No property name supplied/); }); it('checks for the existence of the method', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; expect(function() { spyRegistry.spyOnProperty(subject, 'pants'); }).toThrowError(/property does not exist/); }); it('checks for the existence of access type', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(), subject = {}; Object.defineProperty(subject, 'pants', { get: function() { return 1; }, configurable: true }); expect(function() { spyRegistry.spyOnProperty(subject, 'pants', 'set'); }).toThrowError(/does not have access type/); }); it('checks if it can be spied upon', function() { var subject = {}; Object.defineProperty(subject, 'myProp', { get: function() {} }); Object.defineProperty(subject, 'spiedProp', { get: function() {}, configurable: true }); var spyRegistry = new jasmineUnderTest.SpyRegistry(); expect(function() { spyRegistry.spyOnProperty(subject, 'myProp'); }).toThrowError(/is not declared configurable/); expect(function() { spyRegistry.spyOnProperty(subject, 'spiedProp'); }).not.toThrowError(/is not declared configurable/); }); it('overrides the property getter on the object and returns the spy', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }), subject = {}, returnValue = 1; Object.defineProperty(subject, 'spiedProperty', { get: function() { return returnValue; }, configurable: true }); expect(subject.spiedProperty).toEqual(returnValue); var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty'); var getter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty') .get; expect(getter).toEqual(spy); expect(subject.spiedProperty).toBeUndefined(); }); it('overrides the property setter on the object and returns the spy', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }), subject = {}, returnValue = 1; Object.defineProperty(subject, 'spiedProperty', { get: function() { return returnValue; }, set: function() {}, configurable: true }); var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty', 'set'); var setter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty') .set; expect(subject.spiedProperty).toEqual(returnValue); expect(setter).toEqual(spy); }); describe('when the property is already spied upon', function() { it('throws an error if respy is not allowed', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }), subject = {}; Object.defineProperty(subject, 'spiedProp', { get: function() { return 1; }, configurable: true }); spyRegistry.spyOnProperty(subject, 'spiedProp'); expect(function() { spyRegistry.spyOnProperty(subject, 'spiedProp'); }).toThrowError(/spiedProp#get has already been spied upon/); }); it('returns the original spy if respy is allowed', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: createSpy }), subject = {}; spyRegistry.allowRespy(true); Object.defineProperty(subject, 'spiedProp', { get: function() { return 1; }, configurable: true }); var originalSpy = spyRegistry.spyOnProperty(subject, 'spiedProp'); expect(spyRegistry.spyOnProperty(subject, 'spiedProp')).toBe( originalSpy ); }); }); }); describe('#spyOnAllFunctions', function() { it('checks for the existence of the object', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry(); expect(function() { spyRegistry.spyOnAllFunctions(void 0); }).toThrowError(/spyOnAllFunctions could not find an object to spy upon/); }); it('overrides all writable and configurable functions of the object and its parents', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var createNoop = function() { return function() { /**/ }; }; var noop1 = createNoop(); var noop2 = createNoop(); var noop3 = createNoop(); var noop4 = createNoop(); var noop5 = createNoop(); var parent = { parentSpied1: noop1 }; var subject = Object.create(parent); Object.defineProperty(subject, 'spied1', { value: noop1, writable: true, configurable: true, enumerable: true }); Object.defineProperty(subject, 'spied2', { value: noop2, writable: true, configurable: true, enumerable: true }); var _spied3 = noop3; Object.defineProperty(subject, 'spied3', { configurable: true, set: function(val) { _spied3 = val; }, get: function() { return _spied3; }, enumerable: true }); subject.spied4 = noop4; Object.defineProperty(subject, 'notSpied2', { value: noop2, writable: false, configurable: true, enumerable: true }); Object.defineProperty(subject, 'notSpied3', { value: noop3, writable: true, configurable: false, enumerable: true }); Object.defineProperty(subject, 'notSpied4', { configurable: false, set: function(val) { /**/ }, get: function() { return noop4; }, enumerable: true }); Object.defineProperty(subject, 'notSpied5', { value: noop5, writable: true, configurable: true, enumerable: false }); subject.notSpied6 = 6; var spiedObject = spyRegistry.spyOnAllFunctions(subject); expect(subject.parentSpied1).toBe('I am a spy'); expect(subject.notSpied2).toBe(noop2); expect(subject.notSpied3).toBe(noop3); expect(subject.notSpied4).toBe(noop4); expect(subject.notSpied5).toBe(noop5); expect(subject.notSpied6).toBe(6); expect(subject.spied1).toBe('I am a spy'); expect(subject.spied2).toBe('I am a spy'); expect(subject.spied3).toBe('I am a spy'); expect(subject.spied4).toBe('I am a spy'); expect(spiedObject).toBe(subject); }); it('overrides prototype methods on the object', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var noop1 = function() {}; var noop2 = function() {}; var MyClass = function() { this.spied1 = noop1; }; MyClass.prototype.spied2 = noop2; var subject = new MyClass(); spyRegistry.spyOnAllFunctions(subject); expect(subject.spied1).toBe('I am a spy'); expect(subject.spied2).toBe('I am a spy'); expect(MyClass.prototype.spied2).toBe(noop2); }); it('does not override non-enumerable properties (like Object.prototype methods)', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = { spied1: function() {} }; spyRegistry.spyOnAllFunctions(subject); expect(subject.spied1).toBe('I am a spy'); expect(subject.toString).not.toBe('I am a spy'); expect(subject.hasOwnProperty).not.toBe('I am a spy'); }); describe('when includeNonEnumerable is true', function() { it('does not override Object.prototype methods', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = { spied1: function() {} }; spyRegistry.spyOnAllFunctions(subject, true); expect(subject.spied1).toBe('I am a spy'); expect(subject.toString).not.toBe('I am a spy'); expect(subject.hasOwnProperty).not.toBe('I am a spy'); }); it('overrides non-enumerable properties', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = { spied1: function() {}, spied2: function() {} }; Object.defineProperty(subject, 'spied2', { enumerable: false, writable: true, configurable: true }); spyRegistry.spyOnAllFunctions(subject, true); expect(subject.spied1).toBe('I am a spy'); expect(subject.spied2).toBe('I am a spy'); }); it('should not spy on non-enumerable functions named constructor', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = { constructor: function() {} }; Object.defineProperty(subject, 'constructor', { enumerable: false, writable: true, configurable: true }); spyRegistry.spyOnAllFunctions(subject, true); expect(subject.constructor).not.toBe('I am a spy'); }); it('should spy on enumerable functions named constructor', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = { constructor: function() {} }; spyRegistry.spyOnAllFunctions(subject, true); expect(subject.constructor).toBe('I am a spy'); }); it('should not throw an exception if we try and access strict mode restricted properties', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subject = function() {}; var fn = function() { spyRegistry.spyOnAllFunctions(subject, true); }; expect(fn).not.toThrow(); }); it('should not spy on properties which are more permissable further up the prototype chain', function() { var spyRegistry = new jasmineUnderTest.SpyRegistry({ createSpy: function() { return 'I am a spy'; } }); var subjectParent = Object.defineProperty({}, 'sharedProp', { value: function() {}, writable: true, configurable: true }); var subject = Object.create(subjectParent); Object.defineProperty(subject, 'sharedProp', { value: function() {} }); var fn = function() { spyRegistry.spyOnAllFunctions(subject, true); }; expect(fn).not.toThrow(); expect(subject).not.toBe('I am a spy'); }); }); }); describe('#clearSpies', function() { it('restores the original functions on the spied-upon objects', function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalFunction = function() {}, subject = { spiedFunc: originalFunction }; spyRegistry.spyOn(subject, 'spiedFunc'); spyRegistry.clearSpies(); expect(subject.spiedFunc).toBe(originalFunction); }); it('restores the original functions, even when that spy has been replace and re-spied upon', function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalFunction = function() {}, subject = { spiedFunc: originalFunction }; spyRegistry.spyOn(subject, 'spiedFunc'); // replace the original spy with some other function subject.spiedFunc = function() {}; // spy on the function in that location again spyRegistry.spyOn(subject, 'spiedFunc'); spyRegistry.clearSpies(); expect(subject.spiedFunc).toBe(originalFunction); }); it("does not add a property that the spied-upon object didn't originally have", function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalFunction = function() {}, subjectParent = { spiedFunc: originalFunction }; var subject = Object.create(subjectParent); expect(subject.hasOwnProperty('spiedFunc')).toBe(false); spyRegistry.spyOn(subject, 'spiedFunc'); spyRegistry.clearSpies(); expect(subject.hasOwnProperty('spiedFunc')).toBe(false); expect(subject.spiedFunc).toBe(originalFunction); }); it("restores the original function when it's inherited and cannot be deleted", function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalFunction = function() {}, subjectParent = { spiedFunc: originalFunction }; var subject = Object.create(subjectParent); spyRegistry.spyOn(subject, 'spiedFunc'); // simulate a spy that cannot be deleted Object.defineProperty(subject, 'spiedFunc', { configurable: false }); spyRegistry.clearSpies(); expect(jasmineUnderTest.isSpy(subject.spiedFunc)).toBe(false); }); it('restores window.onerror by overwriting, not deleting', function() { function FakeWindow() {} FakeWindow.prototype.onerror = function() {}; var spies = [], global = new FakeWindow(), spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy, global: global }); spyRegistry.spyOn(global, 'onerror'); spyRegistry.clearSpies(); expect(global.onerror).toBe(FakeWindow.prototype.onerror); expect(global.hasOwnProperty('onerror')).toBe(true); }); }); describe('spying on properties', function() { it('restores the original properties on the spied-upon objects', function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalReturn = 1, subject = {}; Object.defineProperty(subject, 'spiedProp', { get: function() { return originalReturn; }, configurable: true }); spyRegistry.spyOnProperty(subject, 'spiedProp'); spyRegistry.clearSpies(); expect(subject.spiedProp).toBe(originalReturn); }); it("does not add a property that the spied-upon object didn't originally have", function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy }), originalReturn = 1, subjectParent = {}; Object.defineProperty(subjectParent, 'spiedProp', { get: function() { return originalReturn; }, configurable: true }); var subject = Object.create(subjectParent); expect(subject.hasOwnProperty('spiedProp')).toBe(false); spyRegistry.spyOnProperty(subject, 'spiedProp'); spyRegistry.clearSpies(); expect(subject.hasOwnProperty('spiedProp')).toBe(false); expect(subject.spiedProp).toBe(originalReturn); }); }); }); jasmine-4.0.0/spec/core/SpySpec.js000066400000000000000000000225471416413636100167660ustar00rootroot00000000000000describe('Spies', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); describe('createSpy', function() { var TestClass; beforeEach(function() { TestClass = function() {}; TestClass.prototype.someFunction = function() {}; TestClass.prototype.someFunction.bob = 'test'; }); it('preserves the properties of the spied function', function() { var spy = env.createSpy( TestClass.prototype, TestClass.prototype.someFunction ); expect(spy.bob).toEqual('test'); }); it('should allow you to omit the name argument and only pass the originalFn argument', function() { var fn = function test() {}; var spy = env.createSpy(fn); expect(spy.and.identity).toEqual('test'); }); it('warns the user that we intend to overwrite an existing property', function() { TestClass.prototype.someFunction.and = 'turkey'; expect(function() { env.createSpy(TestClass.prototype, TestClass.prototype.someFunction); }).toThrowError( "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon" ); }); it('adds a spyStrategy and callTracker to the spy', function() { var spy = env.createSpy( TestClass.prototype, TestClass.prototype.someFunction ); expect(spy.and).toEqual(jasmine.any(jasmineUnderTest.SpyStrategy)); expect(spy.calls).toEqual(jasmine.any(jasmineUnderTest.CallTracker)); }); it('tracks the argument of calls', function() { var spy = env.createSpy( TestClass.prototype, TestClass.prototype.someFunction ); var trackSpy = spyOn(spy.calls, 'track'); spy('arg'); expect(trackSpy.calls.mostRecent().args[0].args).toEqual(['arg']); }); it('tracks the context of calls', function() { var spy = env.createSpy( TestClass.prototype, TestClass.prototype.someFunction ); var trackSpy = spyOn(spy.calls, 'track'); var contextObject = { spyMethod: spy }; contextObject.spyMethod(); expect(trackSpy.calls.mostRecent().args[0].object).toEqual(contextObject); }); it('tracks the return value of calls', function() { var spy = env.createSpy( TestClass.prototype, TestClass.prototype.someFunction ); var trackSpy = spyOn(spy.calls, 'track'); spy.and.returnValue('return value'); spy(); expect(trackSpy.calls.mostRecent().args[0].returnValue).toEqual( 'return value' ); }); it('preserves arity of original function', function() { var functions = [ function nullary() {}, function unary(arg) {}, function binary(arg1, arg2) {}, function ternary(arg1, arg2, arg3) {}, function quaternary(arg1, arg2, arg3, arg4) {}, function quinary(arg1, arg2, arg3, arg4, arg5) {}, function senary(arg1, arg2, arg3, arg4, arg5, arg6) {} ]; for (var arity = 0; arity < functions.length; arity++) { var someFunction = functions[arity], spy = env.createSpy(someFunction.name, someFunction); expect(spy.length).toEqual(arity); } }); }); describe('createSpyObj', function() { it('should create an object with spy methods and corresponding return values when you call jasmine.createSpyObj() with an object', function() { var spyObj = env.createSpyObj('BaseName', { method1: 42, method2: 'special sauce' }); expect(spyObj.method1()).toEqual(42); expect(spyObj.method1.and.identity).toEqual('BaseName.method1'); expect(spyObj.method2()).toEqual('special sauce'); expect(spyObj.method2.and.identity).toEqual('BaseName.method2'); }); it('should create an object with a bunch of spy methods when you call jasmine.createSpyObj()', function() { var spyObj = env.createSpyObj('BaseName', ['method1', 'method2']); expect(spyObj).toEqual({ method1: jasmine.any(Function), method2: jasmine.any(Function) }); expect(spyObj.method1.and.identity).toEqual('BaseName.method1'); expect(spyObj.method2.and.identity).toEqual('BaseName.method2'); }); it('should allow you to omit the baseName', function() { var spyObj = env.createSpyObj(['method1', 'method2']); expect(spyObj).toEqual({ method1: jasmine.any(Function), method2: jasmine.any(Function) }); expect(spyObj.method1.and.identity).toEqual('unknown.method1'); expect(spyObj.method2.and.identity).toEqual('unknown.method2'); }); it('should throw if you do not pass an array or object argument', function() { expect(function() { env.createSpyObj('BaseName'); }).toThrow( 'createSpyObj requires a non-empty array or object of method names to create spies for' ); }); it('should throw if you pass an empty array argument', function() { expect(function() { env.createSpyObj('BaseName', []); }).toThrow( 'createSpyObj requires a non-empty array or object of method names to create spies for' ); }); it('should throw if you pass an empty object argument', function() { expect(function() { env.createSpyObj('BaseName', {}); }).toThrow( 'createSpyObj requires a non-empty array or object of method names to create spies for' ); }); it('creates an object with spy properties if a second list is passed', function() { var spyObj = env.createSpyObj('base', ['method1'], ['prop1']); expect(spyObj).toEqual({ method1: jasmine.any(Function), prop1: undefined }); var descriptor = Object.getOwnPropertyDescriptor(spyObj, 'prop1'); expect(descriptor.get.and.identity).toEqual('base.prop1.get'); expect(descriptor.set.and.identity).toEqual('base.prop1.set'); }); it('creates an object with property names and return values if second object is passed', function() { var spyObj = env.createSpyObj('base', ['method1'], { prop1: 'foo', prop2: 37 }); expect(spyObj).toEqual({ method1: jasmine.any(Function), prop1: 'foo', prop2: 37 }); expect(spyObj.prop1).toEqual('foo'); expect(spyObj.prop2).toEqual(37); spyObj.prop2 = 4; expect(spyObj.prop2).toEqual(37); expect( Object.getOwnPropertyDescriptor(spyObj, 'prop2').set.calls.count() ).toBe(1); }); it('allows base name to be omitted when assigning methods and properties', function() { var spyObj = env.createSpyObj({ m: 3 }, { p: 4 }); expect(spyObj.m()).toEqual(3); expect(spyObj.p).toEqual(4); expect( Object.getOwnPropertyDescriptor(spyObj, 'p').get.and.identity ).toEqual('unknown.p.get'); }); }); it('can use different strategies for different arguments', function() { var spy = env.createSpy('foo'); spy.and.returnValue(42); spy.withArgs('baz', 'grault').and.returnValue(-1); spy.withArgs('thud').and.returnValue('bob'); expect(spy('foo')).toEqual(42); expect(spy('baz', 'grault')).toEqual(-1); expect(spy('thud')).toEqual('bob'); expect(spy('baz', 'grault', 'waldo')).toEqual(42); }); it('uses asymmetric equality testers when selecting a strategy', function() { var spy = env.createSpy('foo'); spy.and.returnValue(42); spy.withArgs(jasmineUnderTest.any(String)).and.returnValue(-1); expect(spy('foo')).toEqual(-1); expect(spy({})).toEqual(42); }); it('uses the provided matchersUtil selecting a strategy', function() { const matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [ function(a, b) { if ((a === 'bar' && b === 'baz') || (a === 'baz' && b === 'bar')) { return true; } } ] }); const spy = new jasmineUnderTest.Spy('aSpy', matchersUtil); spy.and.returnValue('default strategy return value'); spy.withArgs('bar').and.returnValue('custom strategy return value'); expect(spy('foo')).toEqual('default strategy return value'); expect(spy('baz')).toEqual('custom strategy return value'); }); it('can reconfigure an argument-specific strategy', function() { var spy = env.createSpy('foo'); spy.withArgs('foo').and.returnValue(42); spy.withArgs('foo').and.returnValue(17); expect(spy('foo')).toEqual(17); }); describe('any promise-based strategy', function() { it('works with global Promise library', function(done) { var spy = env.createSpy('foo').and.resolveTo(42); spy() .then(function(result) { expect(result).toEqual(42); done(); }) .catch(done.fail); }); }); describe('when withArgs is used without a base strategy', function() { it('uses the matching strategy', function() { var spy = env.createSpy('foo'); spy.withArgs('baz').and.returnValue(-1); expect(spy('baz')).toEqual(-1); }); it("throws if the args don't match", function() { var spy = env.createSpy('foo'); spy.withArgs('bar').and.returnValue(-1); expect(function() { spy('baz', { qux: 42 }); }).toThrowError( "Spy 'foo' received a call with arguments [ 'baz', Object({ qux: 42 }) ] but all configured strategies specify other arguments." ); }); }); }); jasmine-4.0.0/spec/core/SpyStrategySpec.js000066400000000000000000000237161416413636100205100ustar00rootroot00000000000000describe('SpyStrategy', function() { it('defaults its name to unknown', function() { var spyStrategy = new jasmineUnderTest.SpyStrategy(); expect(spyStrategy.identity).toEqual('unknown'); }); it('takes a name', function() { var spyStrategy = new jasmineUnderTest.SpyStrategy({ name: 'foo' }); expect(spyStrategy.identity).toEqual('foo'); }); it('stubs an original function, if provided', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.exec(); expect(originalFn).not.toHaveBeenCalled(); }); it("allows an original function to be called, passed through the params and returns it's value", function() { var originalFn = jasmine.createSpy('original').and.returnValue(42), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }), returnValue; spyStrategy.callThrough(); returnValue = spyStrategy.exec(null, ['foo']); expect(originalFn).toHaveBeenCalled(); expect(originalFn.calls.mostRecent().args).toEqual(['foo']); expect(returnValue).toEqual(42); }); it('can return a specified value when executed', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }), returnValue; spyStrategy.returnValue(17); returnValue = spyStrategy.exec(); expect(originalFn).not.toHaveBeenCalled(); expect(returnValue).toEqual(17); }); it('can return specified values in order specified when executed', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.returnValues('value1', 'value2', 'value3'); expect(spyStrategy.exec()).toEqual('value1'); expect(spyStrategy.exec()).toEqual('value2'); expect(spyStrategy.exec()).toBe('value3'); expect(spyStrategy.exec()).toBeUndefined(); expect(originalFn).not.toHaveBeenCalled(); }); it('allows an exception to be thrown when executed', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.throwError(new TypeError('bar')); expect(function() { spyStrategy.exec(); }).toThrowError(TypeError, 'bar'); expect(originalFn).not.toHaveBeenCalled(); }); it('allows a string to be thrown, wrapping it into an exception when executed', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.throwError('bar'); expect(function() { spyStrategy.exec(); }).toThrowError(Error, 'bar'); expect(originalFn).not.toHaveBeenCalled(); }); it('allows a non-Error to be thrown when executed', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.throwError({ code: 'ESRCH' }); expect(function() { spyStrategy.exec(); }).toThrow(jasmine.objectContaining({ code: 'ESRCH' })); expect(originalFn).not.toHaveBeenCalled(); }); it('allows a fake function to be called instead', function() { var originalFn = jasmine.createSpy('original'), fakeFn = jasmine.createSpy('fake').and.returnValue(67), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }), returnValue; spyStrategy.callFake(fakeFn); returnValue = spyStrategy.exec(); expect(originalFn).not.toHaveBeenCalled(); expect(returnValue).toEqual(67); }); it('allows a fake async function to be called instead', function(done) { var originalFn = jasmine.createSpy('original'), fakeFn = jasmine .createSpy('fake') .and.callFake(eval('async () => { return 67; }')), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.callFake(fakeFn); spyStrategy .exec() .then(function(returnValue) { expect(originalFn).not.toHaveBeenCalled(); expect(fakeFn).toHaveBeenCalled(); expect(returnValue).toEqual(67); done(); }) .catch(function(err) { done.fail(err); }); }); describe('#resolveTo', function() { it('allows a resolved promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.resolveTo(37); spyStrategy .exec() .then(function(returnValue) { expect(returnValue).toEqual(37); done(); }) .catch(done.fail); }); it('allows an empty resolved promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.resolveTo(); spyStrategy .exec() .then(function(returnValue) { expect(returnValue).toBe(); done(); }) .catch(done.fail); }); }); describe('#rejectWith', function() { it('allows a rejected promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.rejectWith(new Error('oops')); spyStrategy .exec() .then(done.fail) .catch(function(error) { expect(error).toEqual(new Error('oops')); done(); }) .catch(done.fail); }); it('allows an empty rejected promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.rejectWith(); spyStrategy .exec() .then(done.fail) .catch(function(error) { expect(error).toBe(); done(); }) .catch(done.fail); }); it('allows a non-Error to be rejected', function(done) { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyStrategy.rejectWith('oops'); spyStrategy .exec() .then(done.fail) .catch(function(error) { expect(error).toEqual('oops'); done(); }) .catch(done.fail); }); }); it('allows a custom strategy to be used', function() { var plan = jasmine .createSpy('custom strategy') .and.returnValue('custom strategy result'), customStrategy = jasmine .createSpy('custom strategy') .and.returnValue(plan), originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn, customStrategies: { doSomething: customStrategy } }); spyStrategy.doSomething(1, 2, 3); expect(customStrategy).toHaveBeenCalledWith(1, 2, 3); expect(spyStrategy.exec(null, ['some', 'args'])).toEqual( 'custom strategy result' ); expect(plan).toHaveBeenCalledWith('some', 'args'); }); it("throws an error if a custom strategy doesn't return a function", function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn, customStrategies: { doSomething: function() { return 'not a function'; } } }); expect(function() { spyStrategy.doSomething(1, 2, 3); }).toThrowError('Spy strategy must return a function'); }); it('does not allow custom strategies to overwrite existing methods', function() { var spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: function() {}, customStrategies: { exec: function() {} } }); expect(spyStrategy.exec).toBe(jasmineUnderTest.SpyStrategy.prototype.exec); }); it('throws an error when a non-function is passed to callFake strategy', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); spyOn(jasmineUnderTest, 'isFunction_').and.returnValue(false); spyOn(jasmineUnderTest, 'isAsyncFunction_').and.returnValue(false); expect(function() { spyStrategy.callFake(function() {}); }).toThrowError(/^Argument passed to callFake should be a function, got/); expect(function() { spyStrategy.callFake(function() {}); }).toThrowError(/^Argument passed to callFake should be a function, got/); }); it('allows generator functions to be passed to callFake strategy', function() { var generator = function*() { yield 'ok'; }, spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: function() {} }); spyStrategy.callFake(generator); expect(spyStrategy.exec().next().value).toEqual('ok'); }); it('allows a return to plan stubbing after another strategy', function() { var originalFn = jasmine.createSpy('original'), fakeFn = jasmine.createSpy('fake').and.returnValue(67), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }), returnValue; spyStrategy.callFake(fakeFn); returnValue = spyStrategy.exec(); expect(originalFn).not.toHaveBeenCalled(); expect(returnValue).toEqual(67); spyStrategy.stub(); returnValue = spyStrategy.exec(); expect(returnValue).toEqual(void 0); }); it('returns the spy after changing the strategy', function() { var spy = {}, spyFn = jasmine.createSpy('spyFn').and.returnValue(spy), spyStrategy = new jasmineUnderTest.SpyStrategy({ getSpy: spyFn }); expect(spyStrategy.callThrough()).toBe(spy); expect(spyStrategy.returnValue()).toBe(spy); expect(spyStrategy.throwError()).toBe(spy); expect(spyStrategy.callFake(function() {})).toBe(spy); expect(spyStrategy.stub()).toBe(spy); }); }); jasmine-4.0.0/spec/core/StackTraceSpec.js000066400000000000000000000224441416413636100202330ustar00rootroot00000000000000describe('StackTrace', function() { it('understands Chrome/Edge style traces', function() { var error = { message: 'nope', stack: 'Error: nope\n' + ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toEqual('Error: nope'); expect(result.style).toEqual('v8'); expect(result.frames).toEqual([ { raw: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', func: 'UserContext.', file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 }, { raw: ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)', func: 'QueueRunner.run', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 4320 } ]); }); it('understands Chrome/Edge style traces with multiline messages', function() { var error = { message: 'line 1\nline 2', stack: 'Error: line 1\nline 2\n' + ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toEqual('Error: line 1\nline 2'); var rawFrames = result.frames.map(function(f) { return f.raw; }); expect(rawFrames).toEqual([ ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' ]); }); it('understands Node style traces', function() { var error = { message: 'nope', stack: 'Error\n' + ' at /somewhere/jasmine/lib/jasmine-core/jasmine.js:4255:9\n' + ' at QueueRunner.complete [as onComplete] (/somewhere/jasmine/lib/jasmine-core/jasmine.js:579:9)\n' + ' at Immediate. (/somewhere/jasmine/lib/jasmine-core/jasmine.js:4314:12)\n' + ' at runCallback (timers.js:672:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toEqual('Error'); expect(result.style).toEqual('v8'); expect(result.frames).toEqual([ { raw: ' at /somewhere/jasmine/lib/jasmine-core/jasmine.js:4255:9', func: undefined, file: '/somewhere/jasmine/lib/jasmine-core/jasmine.js', line: 4255 }, { raw: ' at QueueRunner.complete [as onComplete] (/somewhere/jasmine/lib/jasmine-core/jasmine.js:579:9)', func: 'QueueRunner.complete [as onComplete]', file: '/somewhere/jasmine/lib/jasmine-core/jasmine.js', line: 579 }, { raw: ' at Immediate. (/somewhere/jasmine/lib/jasmine-core/jasmine.js:4314:12)', func: 'Immediate.', file: '/somewhere/jasmine/lib/jasmine-core/jasmine.js', line: 4314 }, { raw: ' at runCallback (timers.js:672:20)', func: 'runCallback', file: 'timers.js', line: 672 } ]); }); it('understands Safari <=14/Firefox/Phantom-OS X style traces', function() { var error = { message: 'nope', stack: 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + 'run@http://localhost:8888/__jasmine__/jasmine.js:4320:27' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toBeFalsy(); expect(result.style).toEqual('webkit'); expect(result.frames).toEqual([ { raw: 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28', func: undefined, file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 }, { raw: 'run@http://localhost:8888/__jasmine__/jasmine.js:4320:27', func: 'run', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 4320 } ]); }); it('understands Safari 15 style traces', function() { var error = { message: 'nope', stack: '@http://localhost:8888/__spec__/core/FooSpec.js:164:24\n' + 'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44\n' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toBeFalsy(); expect(result.style).toEqual('webkit'); expect(result.frames).toEqual([ { raw: '@http://localhost:8888/__spec__/core/FooSpec.js:164:24', func: undefined, file: 'http://localhost:8888/__spec__/core/FooSpec.js', line: 164 }, { raw: 'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44', func: 'attempt', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 8074 } ]); }); it('does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces', function() { var error = { message: 'nope', stack: 'randomcharsnotincludingwhitespace' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.style).toBeNull(); expect(result.frames).toEqual([{ raw: error.stack }]); }); it('understands Phantom-Linux style traces', function() { var error = { message: 'nope', stack: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toBeFalsy(); expect(result.style).toEqual('v8'); expect(result.frames).toEqual([ { raw: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', func: 'UserContext.', file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 }, { raw: ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)', func: 'QueueRunner.run', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 4320 } ]); }); it('ignores blank lines', function() { var error = { message: 'nope', stack: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.frames).toEqual([ { raw: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', func: 'UserContext.', file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 } ]); }); it("omits properties except 'raw' for frames that are not understood", function() { var error = { message: 'nope', stack: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' but this is quite unexpected\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.style).toEqual('v8'); expect(result.frames).toEqual([ { raw: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', func: 'UserContext.', file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 }, { raw: ' but this is quite unexpected' }, { raw: ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)', func: 'QueueRunner.run', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 4320 } ]); }); it('consideres different types of errors', function() { var error = { message: 'nope', stack: 'TypeError: nope\n' + ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result = new jasmineUnderTest.StackTrace(error); expect(result.message).toEqual('TypeError: nope'); expect(result.frames).toEqual([ { raw: ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)', func: 'UserContext.', file: 'http://localhost:8888/__spec__/core/UtilSpec.js', line: 115 }, { raw: ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)', func: 'QueueRunner.run', file: 'http://localhost:8888/__jasmine__/jasmine.js', line: 4320 } ]); var no_error = { message: 'nope', stack: 'Type Error: nope\n' + ' at UserContext. (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)' }; var result_no_error = new jasmineUnderTest.StackTrace(no_error); expect(result_no_error.message).not.toEqual(jasmine.anything()); }); }); jasmine-4.0.0/spec/core/SuiteSpec.js000066400000000000000000000226571416413636100173060ustar00rootroot00000000000000describe('Suite', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); it('keeps its id', function() { var suite = new jasmineUnderTest.Suite({ env: env, id: 456, description: 'I am a suite' }); expect(suite.id).toEqual(456); }); it('returns blank full name for top level suite', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' }); expect(suite.getFullName()).toEqual(''); }); it('returns its full name when it has parent suites', function() { var parentSuite = new jasmineUnderTest.Suite({ env: env, description: 'I am a parent suite', parentSuite: jasmine.createSpy('pretend top level suite') }), suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite', parentSuite: parentSuite }); expect(suite.getFullName()).toEqual('I am a parent suite I am a suite'); }); it('adds beforeEach functions in order of needed execution', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' }), outerBefore = { fn: 'outerBeforeEach' }, innerBefore = { fn: 'insideBeforeEach' }; suite.beforeEach(outerBefore); suite.beforeEach(innerBefore); expect(suite.beforeFns).toEqual([ { fn: innerBefore.fn, suite }, { fn: outerBefore.fn, suite } ]); }); it('adds beforeAll functions in order of needed execution', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' }), outerBefore = { fn: 'outerBeforeAll' }, innerBefore = { fn: 'insideBeforeAll' }; suite.beforeAll(outerBefore); suite.beforeAll(innerBefore); function sameInstance(expected) { return { asymmetricMatch: function(actual) { return actual === expected; }, jasmineToString: function() { return ``; } }; } expect(suite.beforeAllFns).toEqual([ { fn: outerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) }, { fn: innerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) } ]); }); it('adds afterEach functions in order of needed execution', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' }), outerAfter = { fn: 'outerAfterEach' }, innerAfter = { fn: 'insideAfterEach' }; suite.afterEach(outerAfter); suite.afterEach(innerAfter); expect(suite.afterFns).toEqual([ { fn: innerAfter.fn, suite, type: 'afterEach' }, { fn: outerAfter.fn, suite, type: 'afterEach' } ]); }); it('adds afterAll functions in order of needed execution', function() { const suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' }), outerAfter = { fn: 'outerAfterAll' }, innerAfter = { fn: 'insideAfterAl' }; suite.afterAll(outerAfter); suite.afterAll(innerAfter); expect(suite.afterAllFns).toEqual([ { fn: innerAfter.fn, type: 'afterAll' }, { fn: outerAfter.fn, type: 'afterAll' } ]); }); it('has a status of failed if any expectations have failed', function() { var suite = new jasmineUnderTest.Suite({ expectationResultFactory: function() { return 'hi'; } }); suite.addExpectationResult(false); expect(suite.status()).toBe('failed'); }); it('retrieves a result with updated status', function() { var suite = new jasmineUnderTest.Suite({}); expect(suite.getResult().status).toBe('passed'); }); it('retrieves a result with pending status', function() { var suite = new jasmineUnderTest.Suite({}); suite.pend(); expect(suite.getResult().status).toBe('pending'); }); it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() { var suite = new jasmineUnderTest.Suite({ expectationResultFactory: function(data) { return data; }, throwOnExpectationFailure: true }); expect(function() { suite.addExpectationResult(false, 'failed'); }).toThrowError(jasmineUnderTest.errors.ExpectationFailed); expect(suite.status()).toBe('failed'); expect(suite.result.failedExpectations).toEqual(['failed']); }); it('does not add an additional failure when an expectation fails', function() { var suite = new jasmineUnderTest.Suite({}); suite.onException(new jasmineUnderTest.errors.ExpectationFailed()); expect(suite.getResult().failedExpectations).toEqual([]); }); it('calls timer to compute duration', function() { var suite = new jasmineUnderTest.Suite({ env: env, id: 456, description: 'I am a suite', timer: jasmine.createSpyObj('timer', { start: null, elapsed: 77000 }) }); suite.startTimer(); suite.endTimer(); expect(suite.getResult().duration).toEqual(77000); }); describe('#sharedUserContext', function() { beforeEach(function() { this.suite = new jasmineUnderTest.Suite({}); }); it('returns a UserContext', function() { expect(this.suite.sharedUserContext().constructor).toBe( jasmineUnderTest.UserContext ); }); }); describe('attr.autoCleanClosures', function() { function arrangeSuite(attrs) { var suite = new jasmineUnderTest.Suite(attrs); suite.beforeAll(function() {}); suite.beforeEach(function() {}); suite.afterEach(function() {}); suite.afterAll(function() {}); return suite; } it('should clean closures when "attr.autoCleanClosures" is missing', function() { var suite = arrangeSuite({}); suite.cleanupBeforeAfter(); expect(suite.beforeAllFns[0].fn).toBe(null); expect(suite.beforeFns[0].fn).toBe(null); expect(suite.afterFns[0].fn).toBe(null); expect(suite.afterAllFns[0].fn).toBe(null); }); it('should clean closures when "attr.autoCleanClosures" is true', function() { var suite = arrangeSuite({ autoCleanClosures: true }); suite.cleanupBeforeAfter(); expect(suite.beforeAllFns[0].fn).toBe(null); expect(suite.beforeFns[0].fn).toBe(null); expect(suite.afterFns[0].fn).toBe(null); expect(suite.afterAllFns[0].fn).toBe(null); }); it('should NOT clean closures when "attr.autoCleanClosures" is false', function() { var suite = arrangeSuite({ autoCleanClosures: false }); suite.cleanupBeforeAfter(); expect(suite.beforeAllFns[0].fn).not.toBe(null); expect(suite.beforeFns[0].fn).not.toBe(null); expect(suite.afterFns[0].fn).not.toBe(null); expect(suite.afterAllFns[0].fn).not.toBe(null); }); }); describe('#reset', function() { it('should reset the "pending" status', function() { var suite = new jasmineUnderTest.Suite({}); suite.pend(); suite.reset(); expect(suite.getResult().status).toBe('passed'); }); it('should not reset the "pending" status when the suite was excluded', function() { var suite = new jasmineUnderTest.Suite({}); suite.exclude(); suite.reset(); expect(suite.getResult().status).toBe('pending'); }); it('should also reset the children', function() { var suite = new jasmineUnderTest.Suite({}); var child1 = jasmine.createSpyObj(['reset']); var child2 = jasmine.createSpyObj(['reset']); suite.addChild(child1); suite.addChild(child2); suite.reset(); expect(child1.reset).toHaveBeenCalled(); expect(child2.reset).toHaveBeenCalled(); }); it('should reset the failedExpectations', function() { var suite = new jasmineUnderTest.Suite({ expectationResultFactory: function(error) { return error; } }); suite.onException(new Error()); suite.reset(); var result = suite.getResult(); expect(result.status).toBe('passed'); expect(result.failedExpectations).toHaveSize(0); }); }); describe('#onMultipleDone', function() { it('reports a special error when it is the top suite', function() { const onLateError = jasmine.createSpy('onLateError'); const suite = new jasmineUnderTest.Suite({ onLateError, parentSuite: null }); suite.onMultipleDone(); expect(onLateError).toHaveBeenCalledTimes(1); expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); expect(onLateError.calls.argsFor(0)[0].message).toEqual( 'A top-level beforeAll or afterAll function called its ' + "'done' callback more than once." ); }); it('reports an error including the suite name when it is a normal suite', function() { const onLateError = jasmine.createSpy('onLateError'); var suite = new jasmineUnderTest.Suite({ onLateError, description: 'the suite', parentSuite: { description: 'the parent suite', parentSuite: {} } }); suite.onMultipleDone(); expect(onLateError).toHaveBeenCalledTimes(1); expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); expect(onLateError.calls.argsFor(0)[0].message).toEqual( "An asynchronous beforeAll or afterAll function called its 'done' " + 'callback more than once.\n(in suite: the parent suite the suite)' ); }); }); }); jasmine-4.0.0/spec/core/TimerSpec.js000066400000000000000000000016331416413636100172640ustar00rootroot00000000000000describe('Timer', function() { it('reports the time elapsed', function() { var fakeNow = jasmine.createSpy('fake Date.now'), timer = new jasmineUnderTest.Timer({ now: fakeNow }); fakeNow.and.returnValue(100); timer.start(); fakeNow.and.returnValue(200); expect(timer.elapsed()).toEqual(100); }); describe('when date is stubbed, perhaps by other testing helpers', function() { var origDate = Date; beforeEach(function() { // eslint-disable-next-line no-implicit-globals Date = jasmine.createSpy('date spy'); }); afterEach(function() { // eslint-disable-next-line no-implicit-globals Date = origDate; }); it('does not throw even though Date was taken away', function() { var timer = new jasmineUnderTest.Timer(); expect(timer.start).not.toThrow(); expect(timer.elapsed()).toEqual(jasmine.any(Number)); }); }); }); jasmine-4.0.0/spec/core/TreeProcessorSpec.js000066400000000000000000000721421416413636100210060ustar00rootroot00000000000000describe('TreeProcessor', function() { var nodeNumber = 0, leafNumber = 0; function Node(attrs) { attrs = attrs || {}; this.id = 'node' + nodeNumber++; this.children = attrs.children || []; this.canBeReentered = function() { return !attrs.noReenter; }; this.markedPending = attrs.markedPending || false; this.sharedUserContext = function() { return attrs.userContext || {}; }; this.getResult = jasmine.createSpy(this.id + '#execute'); this.beforeAllFns = attrs.beforeAllFns || []; this.afterAllFns = attrs.afterAllFns || []; this.cleanupBeforeAfter = function() {}; } function Leaf(attrs) { attrs = attrs || {}; this.id = 'leaf' + leafNumber++; this.markedPending = attrs.markedPending || false; this.execute = jasmine.createSpy(this.id + '#execute'); } it('processes a single leaf', function() { var leaf = new Leaf(), processor = new jasmineUnderTest.TreeProcessor({ tree: leaf, runnableIds: [leaf.id] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[leaf.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); }); it('processes a single pending leaf', function() { var leaf = new Leaf({ markedPending: true }), processor = new jasmineUnderTest.TreeProcessor({ tree: leaf, runnableIds: [leaf.id] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[leaf.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); }); it('processes a single non-specified leaf', function() { var leaf = new Leaf(), processor = new jasmineUnderTest.TreeProcessor({ tree: leaf, runnableIds: [] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[leaf.id]).toEqual({ excluded: true, willExecute: false, segments: jasmine.any(Array) }); }); it('processes a single excluded leaf', function() { var leaf = new Leaf(), processor = new jasmineUnderTest.TreeProcessor({ tree: leaf, runnableIds: [leaf.id], excludeNode: function(node) { return true; } }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[leaf.id]).toEqual({ excluded: true, willExecute: false, segments: jasmine.any(Array) }); }); it('processes a tree with a single leaf with the root specified', function() { var leaf = new Leaf(), parent = new Node({ children: [leaf] }), processor = new jasmineUnderTest.TreeProcessor({ tree: parent, runnableIds: [parent.id] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[parent.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); expect(result[leaf.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); }); it('processes a tree with a single pending leaf, with the root specified', function() { var leaf = new Leaf({ markedPending: true }), parent = new Node({ children: [leaf] }), processor = new jasmineUnderTest.TreeProcessor({ tree: parent, runnableIds: [parent.id] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[parent.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); expect(result[leaf.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); }); it('processes a complicated tree with the root specified', function() { var pendingLeaf = new Leaf({ markedPending: true }), executableLeaf = new Leaf({ markedPending: false }), parent = new Node({ children: [pendingLeaf, executableLeaf] }), childless = new Node(), childOfPending = new Leaf({ markedPending: true }), pendingNode = new Node({ markedPending: true, children: [childOfPending] }), parentOfPendings = new Node({ markedPending: false, children: [childless, pendingNode] }), root = new Node({ children: [parent, parentOfPendings] }), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [root.id] }), result = processor.processTree(); expect(result.valid).toBe(true); expect(result[root.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); expect(result[parentOfPendings.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); expect(result[childless.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); expect(result[pendingLeaf.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); expect(result[executableLeaf.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); expect(result[parent.id]).toEqual({ excluded: false, willExecute: true, segments: jasmine.any(Array) }); expect(result[pendingNode.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); expect(result[childOfPending.id]).toEqual({ excluded: false, willExecute: false, segments: jasmine.any(Array) }); }); it('marks the run order invalid if it would re-enter a node that does not allow re-entry', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), reentered = new Node({ noReenter: true, children: [leaf1, leaf2] }), root = new Node({ children: [reentered, leaf3] }), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf3.id, leaf2.id] }), result = processor.processTree(); expect(result).toEqual({ valid: false }); }); it('marks the run order valid if a node being re-entered allows re-entry', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), reentered = new Node({ children: [leaf1, leaf2] }), root = new Node({ children: [reentered, leaf3] }), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf3.id, leaf2.id] }), result = processor.processTree(); expect(result.valid).toBe(true); }); it("marks the run order valid if a node which can't be re-entered is only entered once", function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), noReentry = new Node({ noReenter: true }), root = new Node({ children: [noReentry] }), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf2.id, leaf1.id, leaf3.id] }), result = processor.processTree(); expect(result.valid).toBe(true); }); it("marks the run order valid if a node which can't be re-entered is run directly", function() { var noReentry = new Node({ noReenter: true }), root = new Node({ children: [noReentry] }), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [root.id] }), result = processor.processTree(); expect(result.valid).toBe(true); }); it('runs a single leaf', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], userContext: { root: 'context' } }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: node, runnableIds: [leaf.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'); processor.execute(treeComplete); expect(queueRunner).toHaveBeenCalledWith({ onComplete: treeComplete, onException: jasmine.any(Function), userContext: { root: 'context' }, queueableFns: [{ fn: jasmine.any(Function) }], onMultipleDone: null }); queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo'); expect(leaf.execute).toHaveBeenCalledWith('foo', false, false); }); it('runs a node with no children', function() { var node = new Node({ userContext: { node: 'context' } }), root = new Node({ children: [node], userContext: { root: 'context' } }), nodeStart = jasmine.createSpy('nodeStart'), nodeComplete = jasmine.createSpy('nodeComplete'), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], nodeStart: nodeStart, nodeComplete: nodeComplete, queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); expect(queueRunner).toHaveBeenCalledWith({ onComplete: treeComplete, onException: jasmine.any(Function), userContext: { root: 'context' }, queueableFns: [{ fn: jasmine.any(Function) }], onMultipleDone: null }); queueRunner.calls.mostRecent().args[0].queueableFns[0].fn(nodeDone); expect(queueRunner).toHaveBeenCalledWith({ onComplete: jasmine.any(Function), onMultipleDone: null, queueableFns: [{ fn: jasmine.any(Function) }], userContext: { node: 'context' }, onException: jasmine.any(Function), onMultipleDone: null }); queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo'); expect(nodeStart).toHaveBeenCalledWith(node, 'foo'); node.getResult.and.returnValue({ my: 'result' }); queueRunner.calls.mostRecent().args[0].onComplete(); expect(nodeComplete).toHaveBeenCalledWith( node, { my: 'result' }, jasmine.any(Function) ); }); it('runs a node with children', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), node = new Node({ children: [leaf1, leaf2] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(3); queueableFns[1].fn('foo'); expect(leaf1.execute).toHaveBeenCalledWith('foo', false, false); queueableFns[2].fn('bar'); expect(leaf2.execute).toHaveBeenCalledWith('bar', false, false); }); it('cascades errors up the tree', function() { var leaf = new Leaf(), node = new Node({ children: [leaf] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), nodeComplete = jasmine.createSpy('nodeComplete'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], nodeComplete: nodeComplete, queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(2); queueableFns[1].fn('foo'); expect(leaf.execute).toHaveBeenCalledWith('foo', false, false); queueRunner.calls.mostRecent().args[0].onComplete('things'); expect(nodeComplete).toHaveBeenCalled(); nodeComplete.calls.mostRecent().args[2](); expect(nodeDone).toHaveBeenCalledWith('things'); }); it('runs an excluded node with leaf', function() { var leaf1 = new Leaf(), node = new Node({ children: [leaf1] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), nodeStart = jasmine.createSpy('nodeStart'), nodeComplete = jasmine.createSpy('nodeComplete'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [], queueRunnerFactory: queueRunner, nodeStart: nodeStart, nodeComplete: nodeComplete }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(2); queueableFns[0].fn('bar'); expect(nodeStart).toHaveBeenCalledWith(node, 'bar'); queueableFns[1].fn('foo'); expect(leaf1.execute).toHaveBeenCalledWith('foo', true, false); node.getResult.and.returnValue({ im: 'disabled' }); queueRunner.calls.mostRecent().args[0].onComplete(); expect(nodeComplete).toHaveBeenCalledWith( node, { im: 'disabled' }, jasmine.any(Function) ); }); it('should execute node with correct arguments when failSpecWithNoExpectations option is set', function() { var leaf = new Leaf(), node = new Node({ children: [leaf] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), nodeStart = jasmine.createSpy('nodeStart'), nodeComplete = jasmine.createSpy('nodeComplete'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [], queueRunnerFactory: queueRunner, nodeStart: nodeStart, nodeComplete: nodeComplete, failSpecWithNoExpectations: true }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(2); queueableFns[1].fn('foo'); expect(leaf.execute).toHaveBeenCalledWith('foo', true, true); }); it('runs beforeAlls for a node with children', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], beforeAllFns: [ { fn: 'beforeAll1', timeout: 1 }, { fn: 'beforeAll2', timeout: 2 } ] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: 'beforeAll1', timeout: 1 }, { fn: 'beforeAll2', timeout: 2 }, { fn: jasmine.any(Function) } ]); }); it('runs afterAlls for a node with children', function() { var leaf = new Leaf(), afterAllFns = [{ fn: 'afterAll1' }, { fn: 'afterAll2' }], node = new Node({ children: [leaf], afterAllFns }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) }, afterAllFns[0], afterAllFns[1] ]); }); it('does not run beforeAlls or afterAlls for a node with no children', function() { var node = new Node({ beforeAllFns: [{ fn: 'before' }], afterAllFns: [{ fn: 'after' }] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns).toEqual([{ fn: jasmine.any(Function) }]); }); it('does not run beforeAlls or afterAlls for a node with only pending children', function() { var leaf = new Leaf({ markedPending: true }), node = new Node({ children: [leaf], beforeAllFns: [{ fn: 'before' }], afterAllFns: [{ fn: 'after' }], markedPending: false }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'), nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(nodeDone); queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) } ]); }); it('runs leaves in the order specified', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), root = new Node({ children: [leaf1, leaf2] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf2.id, leaf1.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(); expect(leaf1.execute).not.toHaveBeenCalled(); expect(leaf2.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(leaf1.execute).toHaveBeenCalled(); }); it('runs specified leaves before non-specified leaves within a parent node', function() { var specified = new Leaf(), nonSpecified = new Leaf(), root = new Node({ children: [nonSpecified, specified] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [specified.id], queueRunnerFactory: queueRunner }), treeComplete = jasmine.createSpy('treeComplete'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(); expect(nonSpecified.execute).not.toHaveBeenCalled(); expect(specified.execute).toHaveBeenCalledWith(undefined, false, false); queueableFns[1].fn(); expect(nonSpecified.execute).toHaveBeenCalledWith(undefined, true, false); }); it('runs nodes and leaves with a specified order', function() { var specifiedLeaf = new Leaf(), childLeaf = new Leaf(), specifiedNode = new Node({ children: [childLeaf] }), root = new Node({ children: [specifiedLeaf, specifiedNode] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [specifiedNode.id, specifiedLeaf.id], queueRunnerFactory: queueRunner }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; queueableFns[0].fn(); expect(specifiedLeaf.execute).not.toHaveBeenCalled(); var nodeQueueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; nodeQueueableFns[1].fn(); expect(childLeaf.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(specifiedLeaf.execute).toHaveBeenCalled(); }); it('runs a node multiple times if the order specified leaves and re-enters it', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), leaf4 = new Leaf(), leaf5 = new Leaf(), reentered = new Node({ children: [leaf1, leaf2, leaf3] }), root = new Node({ children: [reentered, leaf4, leaf5] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf4.id, leaf2.id, leaf5.id, leaf3.id], queueRunnerFactory: queueRunner }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(5); queueableFns[0].fn(); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf1.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(leaf4.execute).toHaveBeenCalled(); queueableFns[2].fn(); expect(queueRunner.calls.count()).toBe(3); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf2.execute).toHaveBeenCalled(); queueableFns[3].fn(); expect(leaf5.execute).toHaveBeenCalled(); queueableFns[4].fn(); expect(queueRunner.calls.count()).toBe(4); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf3.execute).toHaveBeenCalled(); }); it('runs a parent of a node with segments correctly', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), leaf4 = new Leaf(), leaf5 = new Leaf(), parent = new Node({ children: [leaf1, leaf2, leaf3] }), grandparent = new Node({ children: [parent] }), root = new Node({ children: [grandparent, leaf4, leaf5] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf4.id, leaf2.id, leaf5.id, leaf3.id], queueRunnerFactory: queueRunner }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(5); queueableFns[0].fn(); expect(queueRunner.calls.count()).toBe(2); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(queueRunner.calls.count()).toBe(3); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf1.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(leaf4.execute).toHaveBeenCalled(); queueableFns[2].fn(); expect(queueRunner.calls.count()).toBe(4); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(queueRunner.calls.count()).toBe(5); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf2.execute).toHaveBeenCalled(); queueableFns[3].fn(); expect(leaf5.execute).toHaveBeenCalled(); queueableFns[4].fn(); expect(queueRunner.calls.count()).toBe(6); expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(2); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(queueRunner.calls.count()).toBe(7); queueRunner.calls.mostRecent().args[0].queueableFns[1].fn(); expect(leaf3.execute).toHaveBeenCalled(); }); it('runs nodes in the order they were declared', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), parent = new Node({ children: [leaf2, leaf3] }), root = new Node({ children: [leaf1, parent] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [root.id], queueRunnerFactory: queueRunner }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(2); queueableFns[0].fn(); expect(leaf1.execute).toHaveBeenCalled(); queueableFns[1].fn(); var childFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(childFns.length).toBe(3); childFns[1].fn(); expect(leaf2.execute).toHaveBeenCalled(); childFns[2].fn(); expect(leaf3.execute).toHaveBeenCalled(); }); it('runs large segments of nodes in the order they were declared', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), leaf4 = new Leaf(), leaf5 = new Leaf(), leaf6 = new Leaf(), leaf7 = new Leaf(), leaf8 = new Leaf(), leaf9 = new Leaf(), leaf10 = new Leaf(), leaf11 = new Leaf(), root = new Node({ children: [ leaf1, leaf2, leaf3, leaf4, leaf5, leaf6, leaf7, leaf8, leaf9, leaf10, leaf11 ] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [root.id], queueRunnerFactory: queueRunner }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(11); queueableFns[0].fn(); expect(leaf1.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(leaf2.execute).toHaveBeenCalled(); queueableFns[2].fn(); expect(leaf3.execute).toHaveBeenCalled(); queueableFns[3].fn(); expect(leaf4.execute).toHaveBeenCalled(); queueableFns[4].fn(); expect(leaf5.execute).toHaveBeenCalled(); queueableFns[5].fn(); expect(leaf6.execute).toHaveBeenCalled(); queueableFns[6].fn(); expect(leaf7.execute).toHaveBeenCalled(); queueableFns[7].fn(); expect(leaf8.execute).toHaveBeenCalled(); queueableFns[8].fn(); expect(leaf9.execute).toHaveBeenCalled(); queueableFns[9].fn(); expect(leaf10.execute).toHaveBeenCalled(); queueableFns[10].fn(); expect(leaf11.execute).toHaveBeenCalled(); }); it('runs nodes in a custom order when orderChildren is overridden', function() { var leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), leaf4 = new Leaf(), leaf5 = new Leaf(), leaf6 = new Leaf(), leaf7 = new Leaf(), leaf8 = new Leaf(), leaf9 = new Leaf(), leaf10 = new Leaf(), leaf11 = new Leaf(), root = new Node({ children: [ leaf1, leaf2, leaf3, leaf4, leaf5, leaf6, leaf7, leaf8, leaf9, leaf10, leaf11 ] }), queueRunner = jasmine.createSpy('queueRunner'), processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [root.id], queueRunnerFactory: queueRunner, orderChildren: function(node) { var children = node.children.slice(); return children.reverse(); } }); processor.execute(); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; expect(queueableFns.length).toBe(11); queueableFns[0].fn(); expect(leaf11.execute).toHaveBeenCalled(); queueableFns[1].fn(); expect(leaf10.execute).toHaveBeenCalled(); queueableFns[2].fn(); expect(leaf9.execute).toHaveBeenCalled(); queueableFns[3].fn(); expect(leaf8.execute).toHaveBeenCalled(); queueableFns[4].fn(); expect(leaf7.execute).toHaveBeenCalled(); queueableFns[5].fn(); expect(leaf6.execute).toHaveBeenCalled(); queueableFns[6].fn(); expect(leaf5.execute).toHaveBeenCalled(); queueableFns[7].fn(); expect(leaf4.execute).toHaveBeenCalled(); queueableFns[8].fn(); expect(leaf3.execute).toHaveBeenCalled(); queueableFns[9].fn(); expect(leaf2.execute).toHaveBeenCalled(); queueableFns[10].fn(); expect(leaf1.execute).toHaveBeenCalled(); }); }); jasmine-4.0.0/spec/core/UserContextSpec.js000066400000000000000000000030641416413636100204670ustar00rootroot00000000000000describe('UserContext', function() { it('Behaves just like an plain object', function() { var context = new jasmineUnderTest.UserContext(), properties = []; for (var prop in context) { if (obj.hasOwnProperty(prop)) { properties.push(prop); } } expect(properties).toEqual([]); }); describe('.fromExisting', function() { describe('when using an already built context as model', function() { beforeEach(function() { this.context = new jasmineUnderTest.UserContext(); this.context.key = 'value'; this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context); }); it('returns a cloned object', function() { expect(this.cloned).toEqual(this.context); }); it('does not return the same object', function() { expect(this.cloned).not.toBe(this.context); }); }); describe('when using a regular object as parameter', function() { beforeEach(function() { this.context = {}; this.value = 'value'; this.context.key = this.value; this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context); }); it('returns an object with the same attributes', function() { expect(this.cloned.key).toEqual(this.value); }); it('does not return the same object', function() { expect(this.cloned).not.toBe(this.context); }); it('returns an UserContext', function() { expect(this.cloned.constructor).toBe(jasmineUnderTest.UserContext); }); }); }); }); jasmine-4.0.0/spec/core/UtilSpec.js000066400000000000000000000151331416413636100171210ustar00rootroot00000000000000describe('jasmineUnderTest.util', function() { describe('isArray_', function() { it('should return true if the argument is an array', function() { expect(jasmineUnderTest.isArray_([])).toBe(true); expect(jasmineUnderTest.isArray_(['a'])).toBe(true); }); it('should return false if the argument is not an array', function() { expect(jasmineUnderTest.isArray_(undefined)).toBe(false); expect(jasmineUnderTest.isArray_({})).toBe(false); expect(jasmineUnderTest.isArray_(function() {})).toBe(false); expect(jasmineUnderTest.isArray_('foo')).toBe(false); expect(jasmineUnderTest.isArray_(5)).toBe(false); expect(jasmineUnderTest.isArray_(null)).toBe(false); }); }); describe('isObject_', function() { it('should return true if the argument is an object', function() { expect(jasmineUnderTest.isObject_({})).toBe(true); expect(jasmineUnderTest.isObject_({ an: 'object' })).toBe(true); }); it('should return false if the argument is not an object', function() { expect(jasmineUnderTest.isObject_(undefined)).toBe(false); expect(jasmineUnderTest.isObject_([])).toBe(false); expect(jasmineUnderTest.isObject_(function() {})).toBe(false); expect(jasmineUnderTest.isObject_('foo')).toBe(false); expect(jasmineUnderTest.isObject_(5)).toBe(false); expect(jasmineUnderTest.isObject_(null)).toBe(false); }); }); describe('promise utils', function() { var mockNativePromise, mockPromiseLikeObject; var mockPromiseLike = function() { this.then = function() {}; }; beforeEach(function() { mockNativePromise = new Promise(function(res, rej) {}); mockPromiseLikeObject = new mockPromiseLike(); }); describe('isPromise', function() { it('should return true when passed a native promise', function() { expect(jasmineUnderTest.isPromise(mockNativePromise)).toBe(true); }); it('should return false for promise like objects', function() { expect(jasmineUnderTest.isPromise(mockPromiseLikeObject)).toBe(false); }); it('should return false for strings', function() { expect(jasmineUnderTest.isPromise('hello')).toBe(false); }); it('should return false for numbers', function() { expect(jasmineUnderTest.isPromise(3)).toBe(false); }); it('should return false for null', function() { expect(jasmineUnderTest.isPromise(null)).toBe(false); }); it('should return false for undefined', function() { expect(jasmineUnderTest.isPromise(undefined)).toBe(false); }); it('should return false for arrays', function() { expect(jasmineUnderTest.isPromise([])).toBe(false); }); it('should return false for objects', function() { expect(jasmineUnderTest.isPromise({})).toBe(false); }); it('should return false for boolean values', function() { expect(jasmineUnderTest.isPromise(true)).toBe(false); }); }); describe('isPromiseLike', function() { it('should return true when passed a native promise', function() { expect(jasmineUnderTest.isPromiseLike(mockNativePromise)).toBe(true); }); it('should return true for promise like objects', function() { expect(jasmineUnderTest.isPromiseLike(mockPromiseLikeObject)).toBe( true ); }); it('should return false if then is not a function', function() { expect( jasmineUnderTest.isPromiseLike({ then: { its: 'Not a function :O' } }) ).toBe(false); }); it('should return false for strings', function() { expect(jasmineUnderTest.isPromiseLike('hello')).toBe(false); }); it('should return false for numbers', function() { expect(jasmineUnderTest.isPromiseLike(3)).toBe(false); }); it('should return false for null', function() { expect(jasmineUnderTest.isPromiseLike(null)).toBe(false); }); it('should return false for undefined', function() { expect(jasmineUnderTest.isPromiseLike(undefined)).toBe(false); }); it('should return false for arrays', function() { expect(jasmineUnderTest.isPromiseLike([])).toBe(false); }); it('should return false for objects', function() { expect(jasmineUnderTest.isPromiseLike({})).toBe(false); }); it('should return false for boolean values', function() { expect(jasmineUnderTest.isPromiseLike(true)).toBe(false); }); }); }); describe('isUndefined', function() { it('reports if a variable is defined', function() { var a; expect(jasmineUnderTest.util.isUndefined(a)).toBe(true); expect(jasmineUnderTest.util.isUndefined(undefined)).toBe(true); var undefined = 'diz be undefined yo'; expect(jasmineUnderTest.util.isUndefined(undefined)).toBe(false); }); }); describe('getPropertyDescriptor', function() { it('get property descriptor from object', function() { var obj = { prop: 1 }, actual = jasmineUnderTest.util.getPropertyDescriptor(obj, 'prop'), expected = Object.getOwnPropertyDescriptor(obj, 'prop'); expect(actual).toEqual(expected); }); it('get property descriptor from object property', function() { var proto = { prop: 1 }, actual = jasmineUnderTest.util.getPropertyDescriptor(proto, 'prop'), expected = Object.getOwnPropertyDescriptor(proto, 'prop'); expect(actual).toEqual(expected); }); }); describe('objectDifference', function() { it('given two objects A and B, returns the properties in A not present in B', function() { var a = { foo: 3, bar: 4, baz: 5 }; var b = { bar: 6, quux: 7 }; expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({ foo: 3, baz: 5 }); }); it('only looks at own properties of both objects', function() { function Foo() {} Foo.prototype.x = 1; Foo.prototype.y = 2; var a = new Foo(); a.x = 1; var b = new Foo(); b.y = 2; expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({ x: 1 }); expect(jasmineUnderTest.util.objectDifference(b, a)).toEqual({ y: 2 }); }); }); describe('jasmineFile', function() { it('returns the file containing jasmine.util', function() { // Chrome sometimes reports foo.js as foo.js/, so tolerate // a trailing slash if present. expect(jasmineUnderTest.util.jasmineFile()).toMatch(/util.js\/?$/); expect(jasmine.util.jasmineFile()).toMatch(/jasmine.js\/?$/); }); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/000077500000000000000000000000001416413636100211225ustar00rootroot00000000000000jasmine-4.0.0/spec/core/asymmetric_equality/AnySpec.js000066400000000000000000000043031416413636100230220ustar00rootroot00000000000000describe('Any', function() { it('matches a string', function() { var any = new jasmineUnderTest.Any(String); expect(any.asymmetricMatch('foo')).toBe(true); }); it('matches a number', function() { var any = new jasmineUnderTest.Any(Number); expect(any.asymmetricMatch(1)).toBe(true); }); it('matches a function', function() { var any = new jasmineUnderTest.Any(Function); expect(any.asymmetricMatch(function() {})).toBe(true); }); it('matches an Object', function() { var any = new jasmineUnderTest.Any(Object); expect(any.asymmetricMatch({})).toBe(true); }); it('matches a Boolean', function() { var any = new jasmineUnderTest.Any(Boolean); expect(any.asymmetricMatch(true)).toBe(true); }); it('matches a Map', function() { var any = new jasmineUnderTest.Any(Map); expect(any.asymmetricMatch(new Map())).toBe(true); }); it('matches a Set', function() { var any = new jasmineUnderTest.Any(Set); expect(any.asymmetricMatch(new Set())).toBe(true); }); it('matches a TypedArray', function() { var any = new jasmineUnderTest.Any(Uint32Array); expect(any.asymmetricMatch(new Uint32Array([]))).toBe(true); }); it('matches a Symbol', function() { var any = new jasmineUnderTest.Any(Symbol); expect(any.asymmetricMatch(Symbol())).toBe(true); }); it('matches another constructed object', function() { var Thing = function() {}, any = new jasmineUnderTest.Any(Thing); expect(any.asymmetricMatch(new Thing())).toBe(true); }); it('does not treat null as an Object', function() { var any = new jasmineUnderTest.Any(Object); expect(any.asymmetricMatch(null)).toBe(false); }); it("jasmineToString's itself", function() { var any = new jasmineUnderTest.Any(Number); expect(any.jasmineToString()).toEqual(''); expect(any.jasmineToString()).toEqual(''); }); describe('when called without an argument', function() { it('tells the user to pass a constructor or use jasmine.anything()', function() { expect(function() { new jasmineUnderTest.Any(); }).toThrowError(TypeError, /constructor.*anything/); }); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/AnythingSpec.js000066400000000000000000000034751416413636100240650ustar00rootroot00000000000000describe('Anything', function() { it('matches a string', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch('foo')).toBe(true); }); it('matches a number', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(42)).toBe(true); }); it('matches an object', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch({ foo: 'bar' })).toBe(true); }); it('matches an array', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch([1, 2, 3])).toBe(true); }); it('matches a Map', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(new Map())).toBe(true); }); it('matches a Set', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(new Set())).toBe(true); }); it('matches a TypedArray', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(new Uint32Array([]))).toBe(true); }); it('matches a Symbol', function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(Symbol())).toBe(true); }); it("doesn't match undefined", function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch()).toBe(false); expect(anything.asymmetricMatch(undefined)).toBe(false); }); it("doesn't match null", function() { var anything = new jasmineUnderTest.Anything(); expect(anything.asymmetricMatch(null)).toBe(false); }); it("jasmineToString's itself", function() { var anything = new jasmineUnderTest.Anything(); expect(anything.jasmineToString()).toEqual(''); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/ArrayContainingSpec.js000066400000000000000000000046701416413636100253720ustar00rootroot00000000000000describe('ArrayContaining', function() { it('matches any actual to an empty array', function() { var containing = new jasmineUnderTest.ArrayContaining([]); expect(containing.asymmetricMatch('foo')).toBe(true); }); it('does not work when not passed an array', function() { var containing = new jasmineUnderTest.ArrayContaining('foo'); expect(function() { containing.asymmetricMatch([]); }).toThrowError(/not 'foo'/); }); it('matches when the item is in the actual', function() { var containing = new jasmineUnderTest.ArrayContaining(['foo']); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(['foo'], matchersUtil)).toBe(true); }); it('matches when additional items are in the actual', function() { var containing = new jasmineUnderTest.ArrayContaining(['foo']); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(['foo', 'bar'], matchersUtil)).toBe(true); }); it('does not match when the item is not in the actual', function() { var containing = new jasmineUnderTest.ArrayContaining(['foo']); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(['bar'], matchersUtil)).toBe(false); }); it('does not match when the actual is not an array', function() { var containing = new jasmineUnderTest.ArrayContaining(['foo']); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch('foo', matchersUtil)).toBe(false); }); it('jasmineToStrings itself', function() { var sample = [], matcher = new jasmineUnderTest.ArrayContaining(sample), pp = jasmine.createSpy('pp').and.returnValue('sample'); expect(matcher.jasmineToString(pp)).toEqual( '' ); expect(pp).toHaveBeenCalledWith(sample); }); it('uses custom equality testers', function() { var tester = function(a, b) { // All "foo*" strings match each other. if ( typeof a == 'string' && typeof b == 'string' && a.substr(0, 3) == 'foo' && b.substr(0, 3) == 'foo' ) { return true; } }; var containing = new jasmineUnderTest.ArrayContaining(['fooVal']); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); expect(containing.asymmetricMatch(['fooBar'], matchersUtil)).toBe(true); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/ArrayWithExactContentsSpec.js000066400000000000000000000041611416413636100267120ustar00rootroot00000000000000describe('ArrayWithExactContents', function() { it('matches an array with the same items in a different order', function() { var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matcher.asymmetricMatch([2, 'a', /a/], matchersUtil)).toBe(true); }); it('does not work when not passed an array', function() { var matcher = new jasmineUnderTest.ArrayWithExactContents('foo'); expect(function() { matcher.asymmetricMatch([]); }).toThrowError(/not 'foo'/); }); it('does not match when an item is missing', function() { var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matcher.asymmetricMatch(['a', 2], matchersUtil)).toBe(false); expect(matcher.asymmetricMatch(['a', 2, undefined], matchersUtil)).toBe( false ); }); it('does not match when there is an extra item', function() { var matcher = new jasmineUnderTest.ArrayWithExactContents(['a']); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matcher.asymmetricMatch(['a', 2], matchersUtil)).toBe(false); }); it('jasmineToStrings itself', function() { var sample = [], matcher = new jasmineUnderTest.ArrayWithExactContents(sample), pp = jasmine.createSpy('pp').and.returnValue('sample'); expect(matcher.jasmineToString(pp)).toEqual( '' ); expect(pp).toHaveBeenCalledWith(sample); }); it('uses custom equality testers', function() { var tester = function(a, b) { // All "foo*" strings match each other. if ( typeof a == 'string' && typeof b == 'string' && a.substr(0, 3) == 'foo' && b.substr(0, 3) == 'foo' ) { return true; } }; var matcher = new jasmineUnderTest.ArrayWithExactContents(['fooVal']); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); expect(matcher.asymmetricMatch(['fooBar'], matchersUtil)).toBe(true); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/EmptySpec.js000066400000000000000000000027061416413636100233760ustar00rootroot00000000000000describe('Empty', function() { it('matches an empty object', function() { var empty = new jasmineUnderTest.Empty(); expect(empty.asymmetricMatch({})).toBe(true); expect(empty.asymmetricMatch({ undefined: false })).toBe(false); }); it('matches an empty array', function() { var empty = new jasmineUnderTest.Empty(); expect(empty.asymmetricMatch([])).toBe(true); expect(empty.asymmetricMatch([1, 12, 3])).toBe(false); }); it('matches an empty string', function() { var empty = new jasmineUnderTest.Empty(); expect(empty.asymmetricMatch('')).toBe(true); expect(empty.asymmetricMatch('')).toBe(true); expect(empty.asymmetricMatch('12312')).toBe(false); }); it('matches an empty map', function() { var empty = new jasmineUnderTest.Empty(); var fullMap = new Map(); fullMap.set('thing', 2); expect(empty.asymmetricMatch(new Map())).toBe(true); expect(empty.asymmetricMatch(fullMap)).toBe(false); }); it('matches an empty set', function() { var empty = new jasmineUnderTest.Empty(); var fullSet = new Set(); fullSet.add(3); expect(empty.asymmetricMatch(new Set())).toBe(true); expect(empty.asymmetricMatch(fullSet)).toBe(false); }); it('matches an empty typed array', function() { var empty = new jasmineUnderTest.Empty(); expect(empty.asymmetricMatch(new Int16Array())).toBe(true); expect(empty.asymmetricMatch(new Int16Array([1, 2]))).toBe(false); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/FalsySpec.js000066400000000000000000000022611416413636100233520ustar00rootroot00000000000000describe('Falsy', function() { it('is true for an empty string', function() { var falsy = new jasmineUnderTest.Falsy(); expect(falsy.asymmetricMatch('')).toBe(true); expect(falsy.asymmetricMatch('')).toBe(true); expect(falsy.asymmetricMatch('asdasdad')).toBe(false); }); it('is false for a number that is 0', function() { var falsy = new jasmineUnderTest.Falsy(Number); expect(falsy.asymmetricMatch(1)).toBe(false); expect(falsy.asymmetricMatch(0)).toBe(true); expect(falsy.asymmetricMatch(-23)).toBe(false); expect(falsy.asymmetricMatch(-3.1)).toBe(false); }); it('is true for a null or undefined', function() { var falsy = new jasmineUnderTest.Falsy(Function); expect(falsy.asymmetricMatch(null)).toBe(true); expect(falsy.asymmetricMatch(undefined)).toBe(true); }); it('is true for NaN', function() { var falsy = new jasmineUnderTest.Falsy(Object); expect(falsy.asymmetricMatch(NaN)).toBe(true); }); it('is true for a false Boolean', function() { var falsy = new jasmineUnderTest.Falsy(Boolean); expect(falsy.asymmetricMatch(false)).toBe(true); expect(falsy.asymmetricMatch(true)).toBe(false); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/MapContainingSpec.js000066400000000000000000000127231416413636100250270ustar00rootroot00000000000000describe('MapContaining', function() { it('matches any actual map to an empty map', function() { var actualMap = new Map([['foo', 'bar']]); var containing = new jasmineUnderTest.MapContaining(new Map()); expect(containing.asymmetricMatch(actualMap)).toBe(true); }); it('matches when all the key/value pairs in sample have matches in actual', function() { var actualMap = new Map([ ['foo', [1, 2, 3]], [{ foo: 'bar' }, 'baz'], ['other', 'any'] ]); var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true); }); it('does not match when a key is not in actual', function() { var actualMap = new Map([ ['foo', [1, 2, 3]], [{ foo: 'not a bar' }, 'baz'] ]); var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false); }); it('does not match when a value is not in actual', function() { var actualMap = new Map([['foo', [1, 2, 3]], [{ foo: 'bar' }, 'baz']]); var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false); }); it('matches when all the key/value pairs in sample have asymmetric matches in actual', function() { var actualMap = new Map([ ['foo1', 'not a bar'], ['foo2', 'bar'], ['baz', [1, 2, 3, 4]] ]); var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([2, 3])] ]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true); }); it('does not match when a key in sample has no asymmetric matches in actual', function() { var actualMap = new Map([['a-foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([2, 3])] ]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false); }); it('does not match when a value in sample has no asymmetric matches in actual', function() { var actualMap = new Map([['foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([4, 5])] ]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false); }); it('matches recursively', function() { var actualMap = new Map([ ['foo', new Map([['foo1', 1], ['foo2', 2]])], [new Map([[1, 'bar1'], [2, 'bar2']]), 'bar'], ['other', 'any'] ]); var containingMap = new Map([ ['foo', new jasmineUnderTest.MapContaining(new Map([['foo1', 1]]))], [new jasmineUnderTest.MapContaining(new Map([[2, 'bar2']])), 'bar'] ]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true); }); it('uses custom equality testers', function() { function tester(a, b) { // treat all negative numbers as equal return typeof a == 'number' && typeof b == 'number' ? a < 0 && b < 0 : a === b; } var actualMap = new Map([['foo', -1]]); var containing = new jasmineUnderTest.MapContaining(new Map([['foo', -2]])); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true); }); it('does not match when actual is not a map', function() { var containingMap = new Map([['foo', 'bar']]); expect( new jasmineUnderTest.MapContaining(containingMap).asymmetricMatch('foo') ).toBe(false); expect( new jasmineUnderTest.MapContaining(containingMap).asymmetricMatch(-1) ).toBe(false); expect( new jasmineUnderTest.MapContaining(containingMap).asymmetricMatch({ foo: 'bar' }) ).toBe(false); }); it('throws an error when sample is not a map', function() { expect(function() { new jasmineUnderTest.MapContaining({ foo: 'bar' }).asymmetricMatch( new Map() ); }).toThrowError(/You must provide a map/); }); it('defines a `jasmineToString` method', function() { var sample = new Map(), containing = new jasmineUnderTest.MapContaining(sample), pp = jasmine.createSpy('pp').and.returnValue('sample'); expect(containing.jasmineToString(pp)).toEqual( '' ); expect(pp).toHaveBeenCalledWith(sample); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/NotEmptySpec.js000066400000000000000000000031501416413636100240510ustar00rootroot00000000000000describe('NotEmpty', function() { it('matches a non empty object', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); expect(notEmpty.asymmetricMatch({ undefined: false })).toBe(true); expect(notEmpty.asymmetricMatch({})).toBe(false); }); it('matches a non empty array', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); expect(notEmpty.asymmetricMatch([1, 12, 3])).toBe(true); expect(notEmpty.asymmetricMatch([])).toBe(false); }); it('matches a non empty string', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); expect(notEmpty.asymmetricMatch('12312')).toBe(true); expect(notEmpty.asymmetricMatch('')).toBe(false); expect(notEmpty.asymmetricMatch('')).toBe(false); }); it('matches a non empty map', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); var fullMap = new Map(); fullMap.set('one', 1); var emptyMap = new Map(); expect(notEmpty.asymmetricMatch(fullMap)).toBe(true); expect(notEmpty.asymmetricMatch(emptyMap)).toBe(false); }); it('matches a non empty set', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); var filledSet = new Set(); filledSet.add(1); var emptySet = new Set(); expect(notEmpty.asymmetricMatch(filledSet)).toBe(true); expect(notEmpty.asymmetricMatch(emptySet)).toBe(false); }); it('matches a non empty typed array', function() { var notEmpty = new jasmineUnderTest.NotEmpty(); expect(notEmpty.asymmetricMatch(new Int16Array([1, 2, 3]))).toBe(true); expect(notEmpty.asymmetricMatch(new Int16Array())).toBe(false); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/ObjectContainingSpec.js000066400000000000000000000150401416413636100255130ustar00rootroot00000000000000describe('ObjectContaining', function() { it('matches any object actual to an empty object', function() { var containing = new jasmineUnderTest.ObjectContaining({}); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch({ foo: 1 }, matchersUtil)).toBe(true); }); it('does not match when the actual is not an object', function() { var containing = new jasmineUnderTest.ObjectContaining({}); [1, true, undefined, 'a string'].forEach(function(actual) { expect(containing.asymmetricMatch(actual)).toBe(false); }); }); it('does not match an empty object actual', function() { var containing = new jasmineUnderTest.ObjectContaining('foo'); expect(function() { containing.asymmetricMatch({}); }).toThrowError(/not 'foo'/); }); it('matches when the key/value pair is present in the actual', function() { var containing = new jasmineUnderTest.ObjectContaining({ foo: 'fooVal' }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( containing.asymmetricMatch({ foo: 'fooVal', bar: 'barVal' }, matchersUtil) ).toBe(true); }); it('does not match when the key/value pair is not present in the actual', function() { var containing = new jasmineUnderTest.ObjectContaining({ foo: 'fooVal' }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( containing.asymmetricMatch( { bar: 'barVal', quux: 'quuxVal' }, matchersUtil ) ).toBe(false); }); it('does not match when the key is present but the value is different in the actual', function() { var containing = new jasmineUnderTest.ObjectContaining({ foo: 'other' }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( containing.asymmetricMatch({ foo: 'fooVal', bar: 'barVal' }, matchersUtil) ).toBe(false); }); it("jasmineToString's itself", function() { var sample = {}, matcher = new jasmineUnderTest.ObjectContaining(sample), pp = jasmine.createSpy('pp').and.returnValue('sample'); expect(matcher.jasmineToString(pp)).toEqual( '' ); expect(pp).toHaveBeenCalledWith(sample); }); it('matches recursively', function() { var containing = new jasmineUnderTest.ObjectContaining({ one: new jasmineUnderTest.ObjectContaining({ two: {} }) }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch({ one: { two: {} } }, matchersUtil)).toBe( true ); }); it('matches when key is present with undefined value', function() { var containing = new jasmineUnderTest.ObjectContaining({ one: undefined }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch({ one: undefined }, matchersUtil)).toBe( true ); }); it('does not match when key with undefined value is not present', function() { var containing = new jasmineUnderTest.ObjectContaining({ one: undefined }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch({}, matchersUtil)).toBe(false); }); it('matches defined properties', function() { var containing = new jasmineUnderTest.ObjectContaining({ foo: 'fooVal' }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var definedPropertyObject = {}; Object.defineProperty(definedPropertyObject, 'foo', { get: function() { return 'fooVal'; } }); expect( containing.asymmetricMatch(definedPropertyObject, matchersUtil) ).toBe(true); }); it('matches prototype properties', function() { var containing = new jasmineUnderTest.ObjectContaining({ foo: 'fooVal' }); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var prototypeObject = { foo: 'fooVal' }; var obj = Object.create(prototypeObject); expect(containing.asymmetricMatch(obj, matchersUtil)).toBe(true); }); it('uses custom equality testers', function() { var tester = function(a, b) { // All "foo*" strings match each other. if ( typeof a == 'string' && typeof b == 'string' && a.substr(0, 3) == 'foo' && b.substr(0, 3) == 'foo' ) { return true; } }; var containing = new jasmineUnderTest.ObjectContaining({ foo: 'fooVal' }); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); expect(containing.asymmetricMatch({ foo: 'fooBar' }, matchersUtil)).toBe( true ); }); describe('valuesForDiff_', function() { describe('when other is not an object', function() { it('sets self to jasmineToString()', function() { var containing = new jasmineUnderTest.ObjectContaining({}), pp = jasmineUnderTest.makePrettyPrinter(), result = containing.valuesForDiff_('a', pp); expect(result).toEqual({ self: '', other: 'a' }); }); }); describe('when other is an object', function() { it('includes keys that are present in both other and sample', function() { var sample = { a: 1, b: 2 }, other = { a: 3, b: 4 }, containing = new jasmineUnderTest.ObjectContaining(sample), result = containing.valuesForDiff_(other); expect(result.self).not.toBeInstanceOf( jasmineUnderTest.ObjectContaining ); expect(result).toEqual({ self: sample, other: other }); }); it('includes keys that are present only in sample', function() { var sample = { a: 1, b: 2 }, other = { a: 3 }, containing = new jasmineUnderTest.ObjectContaining(sample), result = containing.valuesForDiff_(other); expect(result.self).not.toBeInstanceOf( jasmineUnderTest.ObjectContaining ); expect(containing.valuesForDiff_(other)).toEqual({ self: sample, other: { a: 3, b: undefined } }); }); it('omits keys that are present only in other', function() { var sample = { a: 1, b: 2 }, other = { a: 3, b: 4, c: 5 }, containing = new jasmineUnderTest.ObjectContaining(sample), result = containing.valuesForDiff_(other); expect(result.self).not.toBeInstanceOf( jasmineUnderTest.ObjectContaining ); expect(result).toEqual({ self: sample, other: { a: 3, b: 4 } }); }); }); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/SetContainingSpec.js000066400000000000000000000100561416413636100250420ustar00rootroot00000000000000describe('SetContaining', function() { it('matches any actual set to an empty set', function() { var actualSet = new Set(['foo', 'bar']); var containing = new jasmineUnderTest.SetContaining(new Set()); expect(containing.asymmetricMatch(actualSet)).toBe(true); }); it('matches when all the values in sample have matches in actual', function() { var actualSet = new Set([{ foo: 'bar' }, 'baz', [1, 2, 3]]); var containingSet = new Set([[1, 2, 3], { foo: 'bar' }]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true); }); it('does not match when a value is not in actual', function() { var actualSet = new Set([{ foo: 'bar' }, 'baz', [1, 2, 3]]); var containingSet = new Set([[1, 2], { foo: 'bar' }]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(false); }); it('matches when all the values in sample have asymmetric matches in actual', function() { var actualSet = new Set([[1, 2, 3, 4], 'other', 'foo1']); var containingSet = new Set([ jasmineUnderTest.stringMatching(/^foo\d/), jasmineUnderTest.arrayContaining([2, 3]) ]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true); }); it('does not match when a value in sample has no asymmetric matches in actual', function() { var actualSet = new Set(['a-foo1', [1, 2, 3, 4], 'other']); var containingSet = new Set([ jasmine.stringMatching(/^foo\d/), jasmine.arrayContaining([2, 3]) ]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(false); }); it('matches recursively', function() { var actualSet = new Set(['foo', new Set([1, 'bar', 2]), 'other']); var containingSet = new Set([ new jasmineUnderTest.SetContaining(new Set(['bar'])), 'foo' ]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true); }); it('uses custom equality testers', function() { function tester(a, b) { // treat all negative numbers as equal return typeof a == 'number' && typeof b == 'number' ? a < 0 && b < 0 : a === b; } var actualSet = new Set(['foo', -1]); var containing = new jasmineUnderTest.SetContaining(new Set([-2, 'foo'])); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true); }); it('does not match when actual is not a set', function() { var containingSet = new Set(['foo']); expect( new jasmineUnderTest.SetContaining(containingSet).asymmetricMatch('foo') ).toBe(false); expect( new jasmineUnderTest.SetContaining(containingSet).asymmetricMatch(1) ).toBe(false); expect( new jasmineUnderTest.SetContaining(containingSet).asymmetricMatch(['foo']) ).toBe(false); }); it('throws an error when sample is not a set', function() { expect(function() { new jasmineUnderTest.SetContaining({ foo: 'bar' }).asymmetricMatch( new Set() ); }).toThrowError(/You must provide a set/); }); it('defines a `jasmineToString` method', function() { var sample = new Set(), containing = new jasmineUnderTest.SetContaining(sample), pp = jasmine.createSpy('pp').and.returnValue('sample'); expect(containing.jasmineToString(pp)).toEqual( '' ); expect(pp).toHaveBeenCalledWith(sample); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/StringContainingSpec.js000066400000000000000000000016211416413636100255530ustar00rootroot00000000000000describe('StringContaining', function() { it('searches for a provided substring when the expected is a String', function() { var matcher = new jasmineUnderTest.StringContaining('foo'); expect(matcher.asymmetricMatch('barfoobaz')).toBe(true); expect(matcher.asymmetricMatch('barbaz')).toBe(false); }); it('raises an Error when the expected is not a String', function() { expect(function() { new jasmineUnderTest.StringContaining(/foo/); }).toThrowError(/not a String/); }); it('fails when the actual is not a String', function() { var matcher = new jasmineUnderTest.StringContaining('x'); expect(matcher.asymmetricMatch(['x'])).toBe(false); }); it("jasmineToString's itself", function() { var matching = new jasmineUnderTest.StringContaining('foo'); expect(matching.jasmineToString()).toEqual( '' ); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/StringMatchingSpec.js000066400000000000000000000017131416413636100252160ustar00rootroot00000000000000describe('StringMatching', function() { it('matches a string against a provided regexp', function() { var matcher = new jasmineUnderTest.StringMatching(/foo/); expect(matcher.asymmetricMatch('barfoobaz')).toBe(true); expect(matcher.asymmetricMatch('barbaz')).toBe(false); }); it('matches a string against provided string', function() { var matcher = new jasmineUnderTest.StringMatching('foo'); expect(matcher.asymmetricMatch('barfoobaz')).toBe(true); expect(matcher.asymmetricMatch('barbaz')).toBe(false); }); it('raises an Error when the expected is not a String or RegExp', function() { expect(function() { new jasmineUnderTest.StringMatching({}); }).toThrowError(/not a String or a RegExp/); }); it("jasmineToString's itself", function() { var matching = new jasmineUnderTest.StringMatching(/^foo/); expect(matching.jasmineToString()).toEqual( '' ); }); }); jasmine-4.0.0/spec/core/asymmetric_equality/TruthySpec.js000066400000000000000000000033601416413636100235740ustar00rootroot00000000000000describe('Truthy', function() { it('is true for a non empty string', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch('foo')).toBe(true); expect(truthy.asymmetricMatch('')).toBe(false); }); it('is true for a number that is not 0', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch(1)).toBe(true); expect(truthy.asymmetricMatch(0)).toBe(false); expect(truthy.asymmetricMatch(-23)).toBe(true); expect(truthy.asymmetricMatch(-3.1)).toBe(true); }); it('is true for a function', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch(function() {})).toBe(true); }); it('is true for an Object', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch({})).toBe(true); }); it('is true for a truthful Boolean', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch(true)).toBe(true); expect(truthy.asymmetricMatch(false)).toBe(false); }); it('is true for an empty object', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch({})).toBe(true); }); it('is true for an empty array', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch([])).toBe(true); }); it('is true for a date', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch(new Date())).toBe(true); }); it('is true for a infiniti', function() { var truthy = new jasmineUnderTest.Truthy(); expect(truthy.asymmetricMatch(Infinity)).toBe(true); expect(truthy.asymmetricMatch(-Infinity)).toBe(true); }); }); jasmine-4.0.0/spec/core/baseSpec.js000066400000000000000000000150451416413636100171200ustar00rootroot00000000000000describe('base helpers', function() { describe('isError_', function() { it('correctly handles WebSocket events', function(done) { if (typeof jasmine.getGlobal().WebSocket === 'undefined') { done(); return; } var obj = (function() { var sock = new WebSocket('ws://localhost'); var event; sock.onerror = function(e) { event = e; }; return function() { return event; }; })(); var left = 20; var int = setInterval(function() { if (obj() || left === 0) { var result = jasmineUnderTest.isError_(obj()); expect(result).toBe(false); clearInterval(int); done(); } else { left--; } }, 100); }); it('returns true for an Error subclass', function() { function MyError() {} MyError.prototype = new Error(); expect(jasmineUnderTest.isError_(new MyError())).toBe(true); }); it('returns true for an un-thrown Error with no message in this environment', function() { expect(jasmineUnderTest.isError_(new Error())).toBe(true); }); it('returns true for an Error that originated from another frame', function() { var iframe, error; if (typeof window === 'undefined') { pending('This test only runs in browsers.'); } iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); try { error = iframe.contentWindow.eval('new Error()'); expect(jasmineUnderTest.isError_(error)).toBe(true); } finally { document.body.removeChild(iframe); } }); it('returns false for a falsy value', function() { expect(jasmineUnderTest.isError_(undefined)).toBe(false); }); it('returns false for a non-Error object', function() { expect(jasmineUnderTest.isError_({})).toBe(false); }); }); describe('isAsymmetricEqualityTester_', function() { it('returns false when the argument is falsy', function() { expect(jasmineUnderTest.isAsymmetricEqualityTester_(null)).toBe(false); }); it('returns false when the argument does not have a asymmetricMatch property', function() { var obj = {}; expect(jasmineUnderTest.isAsymmetricEqualityTester_(obj)).toBe(false); }); it("returns false when the argument's asymmetricMatch is not a function", function() { var obj = { asymmetricMatch: 'yes' }; expect(jasmineUnderTest.isAsymmetricEqualityTester_(obj)).toBe(false); }); it("returns true when the argument's asymmetricMatch is a function", function() { var obj = { asymmetricMatch: function() {} }; expect(jasmineUnderTest.isAsymmetricEqualityTester_(obj)).toBe(true); }); }); describe('isSet', function() { it('returns true when the object is a Set', function() { expect(jasmineUnderTest.isSet(new Set())).toBe(true); }); it('returns false when the object is not a Set', function() { expect(jasmineUnderTest.isSet({})).toBe(false); }); }); describe('isURL', function() { it('returns true when the object is a URL', function() { expect(jasmineUnderTest.isURL(new URL('http://localhost/'))).toBe(true); }); it('returns false when the object is not a URL', function() { expect(jasmineUnderTest.isURL({})).toBe(false); }); }); describe('isIterable_', function() { it('returns true when the object is an Array', function() { expect(jasmineUnderTest.isIterable_([])).toBe(true); }); it('returns true when the object is a Set', function() { expect(jasmineUnderTest.isIterable_(new Set())).toBe(true); }); it('returns true when the object is a Map', function() { expect(jasmineUnderTest.isIterable_(new Map())).toBe(true); }); it('returns true when the object implements @@iterator', function() { const myIterable = { [Symbol.iterator]: function() {} }; expect(jasmineUnderTest.isIterable_(myIterable)).toBe(true); }); it('returns false when the object does not implement @@iterator', function() { expect(jasmineUnderTest.isIterable_({})).toBe(false); }); }); describe('isPending_', function() { it('returns a promise that resolves to true when the promise is pending', function() { var promise = new Promise(function() {}); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( true ); }); it('returns a promise that resolves to false when the promise is resolved', function() { var promise = Promise.resolve(); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( false ); }); it('returns a promise that resolves to false when the promise is rejected', function() { var promise = Promise.reject(); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( false ); }); }); describe('DEFAULT_TIMEOUT_INTERVAL setter', function() { var max = 2147483647; beforeEach(function() { this.initialValue = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL; }); afterEach(function() { jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.initialValue; }); it('accepts only values <= ' + max, function() { expect(function() { jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = max + 1; }).toThrowError( 'jasmine.DEFAULT_TIMEOUT_INTERVAL cannot be greater than ' + max ); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = max; expect(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL).toEqual(max); }); it('is consistent with setTimeout in this environment', function(done) { var f1 = jasmine.createSpy('setTimeout callback for ' + max), f2 = jasmine.createSpy('setTimeout callback for ' + (max + 1)), id; // Suppress printing of TimeoutOverflowWarning in node spyOn(console, 'error'); id = setTimeout(f1, max); setTimeout(function() { clearTimeout(id); expect(f1).not.toHaveBeenCalled(); id = setTimeout(f2, max + 1); setTimeout(function() { clearTimeout(id); expect(f2).toHaveBeenCalled(); done(); }); }); }); }); describe('debugLog', function() { it("forwards to the current env's debugLog function", function() { spyOn(jasmineUnderTest.getEnv(), 'debugLog'); jasmineUnderTest.debugLog('a message'); expect(jasmineUnderTest.getEnv().debugLog).toHaveBeenCalledWith( 'a message' ); }); }); }); jasmine-4.0.0/spec/core/formatErrorMsgSpec.js000066400000000000000000000011071416413636100211510ustar00rootroot00000000000000describe('formatErrorMsg', function() { it('should format an error with a domain', function() { var formator = jasmineUnderTest.formatErrorMsg('api'); expect(formator('message')).toBe('api : message'); expect(formator('message2')).toBe('api : message2'); }); it('should format an error with a domain and usage', function() { var formator = jasmineUnderTest.formatErrorMsg('api', 'with a param'); expect(formator('message')).toBe('api : message\nUsage: with a param'); expect(formator('message2')).toBe('api : message2\nUsage: with a param'); }); }); jasmine-4.0.0/spec/core/integration/000077500000000000000000000000001416413636100173535ustar00rootroot00000000000000jasmine-4.0.0/spec/core/integration/AsymmetricEqualityTestersSpec.js000066400000000000000000000136341416413636100257400ustar00rootroot00000000000000describe('Asymmetric equality testers (Integration)', function() { function verifyPasses(expectations, setup) { it('passes', function(done) { var env = new jasmineUnderTest.Env(); env.it('a spec', function() { expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); expect(result.passedExpectations.length) .withContext('Number of passed expectations') .toEqual(1); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(0); expect( result.failedExpectations[0] && result.failedExpectations[0].message ) .withContext('Failure message') .toBeUndefined(); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyFails(expectations) { it('fails', function(done) { var env = new jasmineUnderTest.Env(); env.it('a spec', function() { expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message) .withContext( 'Failed with a thrown error rather than a matcher failure' ) .not.toMatch(/^Error: /); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } describe('any', function() { verifyPasses(function(env) { env.expect(5).toEqual(jasmineUnderTest.any(Number)); }); verifyFails(function(env) { env.expect('five').toEqual(jasmineUnderTest.any(Number)); }); }); describe('anything', function() { verifyPasses(function(env) { env.expect('').toEqual(jasmineUnderTest.anything()); }); verifyFails(function(env) { env.expect(null).toEqual(jasmineUnderTest.anything()); }); }); describe('arrayContaining', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect([1, 2, 3]).toEqual(jasmineUnderTest.arrayContaining(['2'])); }); verifyFails(function(env) { env.expect(null).toEqual(jasmineUnderTest.arrayContaining([2])); }); }); describe('arrayWithExactContents', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env .expect([1, 2]) .toEqual(jasmineUnderTest.arrayWithExactContents(['2', '1'])); }); verifyFails(function(env) { env.expect([]).toEqual(jasmineUnderTest.arrayWithExactContents([2])); }); }); describe('empty', function() { verifyPasses(function(env) { env.expect([]).toEqual(jasmineUnderTest.empty()); }); verifyFails(function(env) { env.expect([1]).toEqual(jasmineUnderTest.empty()); }); }); describe('falsy', function() { verifyPasses(function(env) { env.expect(false).toEqual(jasmineUnderTest.falsy()); }); verifyFails(function(env) { env.expect(true).toEqual(jasmineUnderTest.falsy()); }); }); describe('mapContaining', function() { verifyPasses(function(env) { var actual = new Map(); actual.set('a', '2'); var expected = new Map(); expected.set('a', 2); env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(actual).toEqual(jasmineUnderTest.mapContaining(expected)); }); verifyFails(function(env) { env .expect('something') .toEqual(jasmineUnderTest.mapContaining(new Map())); }); }); describe('notEmpty', function() { verifyPasses(function(env) { env.expect([1]).toEqual(jasmineUnderTest.notEmpty()); }); verifyFails(function(env) { env.expect([]).toEqual(jasmineUnderTest.notEmpty()); }); }); describe('objectContaining', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env .expect({ a: 1, b: 2 }) .toEqual(jasmineUnderTest.objectContaining({ a: '1' })); }); verifyFails(function(env) { env.expect({}).toEqual(jasmineUnderTest.objectContaining({ a: '1' })); }); }); describe('setContaining', function() { verifyPasses(function(env) { var actual = new Set(); actual.add('1'); var expected = new Set(); actual.add(1); env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(actual).toEqual(jasmineUnderTest.setContaining(expected)); }); verifyFails(function(env) { env .expect('something') .toEqual(jasmineUnderTest.setContaining(new Set())); }); }); describe('stringMatching', function() { verifyPasses(function(env) { env.expect('foo').toEqual(jasmineUnderTest.stringMatching(/o/)); }); verifyFails(function(env) { env.expect('bar').toEqual(jasmineUnderTest.stringMatching(/o/)); }); }); describe('stringContaining', function() { verifyPasses(function(env) { env.expect('foo').toEqual(jasmineUnderTest.stringContaining('o')); }); verifyFails(function(env) { env.expect('bar').toEqual(jasmineUnderTest.stringContaining('o')); }); }); describe('truthy', function() { verifyPasses(function(env) { env.expect(true).toEqual(jasmineUnderTest.truthy()); }); verifyFails(function(env) { env.expect(false).toEqual(jasmineUnderTest.truthy()); }); }); }); jasmine-4.0.0/spec/core/integration/CustomAsyncMatchersSpec.js000066400000000000000000000077771416413636100245050ustar00rootroot00000000000000describe('Custom Async Matchers (Integration)', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); afterEach(function() { env.cleanup_(); }); it('passes the spec if the custom async matcher passes', function(done) { env.it('spec using custom async matcher', function() { env.addAsyncMatchers({ toBeReal: function() { return { compare: function() { return Promise.resolve({ pass: true }); } }; } }); return env.expectAsync(true).toBeReal(); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('uses the negative compare function for a negative comparison, if provided', function(done) { env.it('spec with custom negative comparison matcher', function() { env.addAsyncMatchers({ toBeReal: function() { return { compare: function() { return Promise.resolve({ pass: true }); }, negativeCompare: function() { return Promise.resolve({ pass: true }); } }; } }); return env.expectAsync(true).not.toBeReal(); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('generates messages with the same rules as built in matchers absent a custom message', function(done) { env.it('spec with an expectation', function() { env.addAsyncMatchers({ toBeReal: function() { return { compare: function() { return Promise.resolve({ pass: false }); } }; } }); return env.expectAsync('a').toBeReal(); }); var specExpectations = function(result) { expect(result.failedExpectations[0].message).toEqual( "Expected 'a' to be real." ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('passes the jasmine utility to the matcher factory', function(done) { var matcherFactory = function(util) { return { compare: function() { return Promise.resolve({ pass: true }); } }; }, matcherFactorySpy = jasmine.createSpy( 'matcherFactorySpy', matcherFactory ); env.it('spec with expectation', function() { env.addAsyncMatchers({ toBeReal: matcherFactorySpy }); return env.expectAsync(true).toBeReal(); }); var specExpectations = function() { expect(matcherFactorySpy).toHaveBeenCalledWith( jasmine.any(jasmineUnderTest.MatchersUtil) ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('provides custom equality testers to the matcher factory via matchersUtil', function(done) { var matcherFactory = function(matchersUtil) { return { compare: function(actual, expected) { return Promise.resolve({ pass: matchersUtil.equals(actual[0], expected) }); } }; }, customEqualityFn = jasmine .createSpy('customEqualityFn') .and.callFake(function(a, b) { return a.toString() === b; }); env.it('spec with expectation', function() { env.addCustomEqualityTester(customEqualityFn); env.addAsyncMatchers({ toBeArrayWithFirstElement: matcherFactory }); return env.expectAsync([1, 2]).toBeArrayWithFirstElement('1'); }); var specExpectations = function(result) { expect(customEqualityFn).toHaveBeenCalledWith(1, '1'); expect(result.failedExpectations).toEqual([]); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); }); jasmine-4.0.0/spec/core/integration/CustomMatchersSpec.js000066400000000000000000000171041416413636100234700ustar00rootroot00000000000000describe('Custom Matchers (Integration)', function() { var env; var fakeTimer; beforeEach(function() { env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); afterEach(function() { env.cleanup_(); }); it('allows adding more matchers local to a spec', function(done) { env.it('spec defining a custom matcher', function() { env.addMatchers({ matcherForSpec: function() { return { compare: function(actual, expected) { return { pass: false, message: 'matcherForSpec: actual: ' + actual + '; expected: ' + expected }; } }; } }); env.expect('zzz').matcherForSpec('yyy'); }); env.it('spec without custom matcher defined', function() { expect(env.expect('zzz').matcherForSpec).toBeUndefined(); }); var specDoneSpy = jasmine.createSpy('specDoneSpy'); var expectations = function() { var firstSpecResult = specDoneSpy.calls.first().args[0]; expect(firstSpecResult.status).toEqual('failed'); expect(firstSpecResult.failedExpectations[0].message).toEqual( 'matcherForSpec: actual: zzz; expected: yyy' ); done(); }; env.addReporter({ specDone: specDoneSpy }); env.execute(null, expectations); }); it('passes the spec if the custom matcher passes', function(done) { env.it('spec using custom matcher', function() { env.addMatchers({ toBeReal: function() { return { compare: function() { return { pass: true }; } }; } }); env.expect(true).toBeReal(); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('passes the spec if the custom equality matcher passes for types nested inside asymmetric equality testers', function(done) { env.it('spec using custom equality matcher', function() { var customEqualityFn = function(a, b) { // All "foo*" strings match each other. if ( typeof a == 'string' && typeof b == 'string' && a.substr(0, 3) == 'foo' && b.substr(0, 3) == 'foo' ) { return true; } }; env.addCustomEqualityTester(customEqualityFn); env .expect({ foo: 'fooValue' }) .toEqual(jasmineUnderTest.objectContaining({ foo: 'fooBar' })); env .expect(['fooValue', 'things']) .toEqual(jasmineUnderTest.arrayContaining(['fooBar'])); env .expect(['fooValue']) .toEqual(jasmineUnderTest.arrayWithExactContents(['fooBar'])); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('displays an appropriate failure message if a custom equality matcher fails', function(done) { env.it('spec using custom equality matcher', function() { var customEqualityFn = function(a, b) { // "foo" is not equal to anything if (a === 'foo' || b === 'foo') { return false; } }; env.addCustomEqualityTester(customEqualityFn); env.expect({ foo: 'foo' }).toEqual({ foo: 'foo' }); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations[0].message).toEqual( "Expected $.foo = 'foo' to equal 'foo'." ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('uses the negative compare function for a negative comparison, if provided', function(done) { env.it('spec with custom negative comparison matcher', function() { env.addMatchers({ toBeReal: function() { return { compare: function() { return { pass: true }; }, negativeCompare: function() { return { pass: true }; } }; } }); env.expect(true).not.toBeReal(); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('generates messages with the same rules as built in matchers absent a custom message', function(done) { env.it('spec with an expectation', function() { env.addMatchers({ toBeReal: function() { return { compare: function() { return { pass: false }; } }; } }); env.expect('a').toBeReal(); }); var specExpectations = function(result) { expect(result.failedExpectations[0].message).toEqual( "Expected 'a' to be real." ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('passes the expected and actual arguments to the comparison function', function(done) { var argumentSpy = jasmine .createSpy('argument spy') .and.returnValue({ pass: true }); env.it('spec with an expectation', function() { env.addMatchers({ toBeReal: function() { return { compare: argumentSpy }; } }); env.expect(true).toBeReal(); env.expect(true).toBeReal('arg'); env.expect(true).toBeReal('arg1', 'arg2'); }); var specExpectations = function() { expect(argumentSpy).toHaveBeenCalledWith(true); expect(argumentSpy).toHaveBeenCalledWith(true, 'arg'); expect(argumentSpy).toHaveBeenCalledWith(true, 'arg1', 'arg2'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('passes the jasmine utility to the matcher factory', function(done) { var matcherFactory = function(util) { return { compare: function() { return { pass: true }; } }; }, matcherFactorySpy = jasmine .createSpy('matcherFactorySpy') .and.callFake(matcherFactory); env.it('spec with expectation', function() { env.addMatchers({ toBeReal: matcherFactorySpy }); env.expect(true).toBeReal(); }); var specExpectations = function() { expect(matcherFactorySpy).toHaveBeenCalledWith( jasmine.any(jasmineUnderTest.MatchersUtil) ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('provides custom equality testers to the matcher factory via matchersUtil', function(done) { var matcherFactory = function(matchersUtil) { return { compare: function(actual, expected) { return { pass: matchersUtil.equals(actual[0], expected) }; } }; }, customEqualityFn = jasmine .createSpy('customEqualityFn') .and.callFake(function(a, b) { return a.toString() === b; }); env.it('spec with expectation', function() { env.addCustomEqualityTester(customEqualityFn); env.addMatchers({ toBeArrayWithFirstElement: matcherFactory }); env.expect([1, 2]).toBeArrayWithFirstElement('1'); }); var specExpectations = function(result) { expect(customEqualityFn).toHaveBeenCalledWith(1, '1'); expect(result.failedExpectations).toEqual([]); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); }); jasmine-4.0.0/spec/core/integration/CustomObjectFormatterSpec.js000066400000000000000000000044111416413636100250110ustar00rootroot00000000000000describe('Custom object formatters', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); it('scopes custom object formatters to a spec', function(done) { env.it('a spec with custom pretty-printer', function() { env.addCustomObjectFormatter(function(obj) { return 'custom(' + obj + ')'; }); env.expect(42).toBeUndefined(); }); env.it('a spec without custom pretty-printer', function() { env.expect(42).toBeUndefined(); }); var specResults = []; var specDone = function(result) { specResults.push(result); }; var expectations = function() { expect(specResults[0].failedExpectations[0].message).toEqual( 'Expected custom(42) to be undefined.' ); expect(specResults[1].failedExpectations[0].message).toEqual( 'Expected 42 to be undefined.' ); done(); }; env.addReporter({ specDone: specDone }); env.execute(null, expectations); }); it('scopes custom object formatters to a suite', function(done) { env.it('a spec without custom pretty-printer', function() { env.expect(42).toBeUndefined(); }); env.describe('with custom pretty-printer', function() { env.beforeAll(function() { env.addCustomObjectFormatter(function(obj) { return 'custom(' + obj + ')'; }); }); env.it('a spec', function() { env.expect(42).toBeUndefined(); }); }); var specResults = []; var specDone = function(result) { specResults.push(result); }; var expectations = function() { expect(specResults[0].failedExpectations[0].message).toEqual( 'Expected 42 to be undefined.' ); expect(specResults[1].failedExpectations[0].message).toEqual( 'Expected custom(42) to be undefined.' ); done(); }; env.addReporter({ specDone: specDone }); env.execute(null, expectations); }); it('throws an exception if you try to add a custom object formatter outside a runable', function() { expect(function() { env.addCustomObjectFormatter(function() {}); }).toThrowError( 'Custom object formatters must be added in a before function or a spec' ); }); }); jasmine-4.0.0/spec/core/integration/CustomSpyStrategiesSpec.js000066400000000000000000000100711416413636100245240ustar00rootroot00000000000000describe('Custom Spy Strategies (Integration)', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); afterEach(function() { env.cleanup_(); }); it('allows adding more strategies local to a suite', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); env.describe('suite defining a custom spy strategy', function() { env.beforeAll(function() { env.addSpyStrategy('frobnicate', strategy); }); env.it('spec in the suite', function() { var spy = env.createSpy('something').and.frobnicate(17); expect(spy(1, 2, 3)).toEqual(42); expect(strategy).toHaveBeenCalledWith(17); expect(plan).toHaveBeenCalledWith(1, 2, 3); }); }); env.it('spec without custom strategy defined', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); }); it('allows adding more strategies local to a spec', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); env.it('spec defining a custom spy strategy', function() { env.addSpyStrategy('frobnicate', strategy); var spy = env.createSpy('something').and.frobnicate(17); expect(spy(1, 2, 3)).toEqual(42); expect(strategy).toHaveBeenCalledWith(17); expect(plan).toHaveBeenCalledWith(1, 2, 3); }); env.it('spec without custom strategy defined', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); }); it('allows using custom strategies on a per-argument basis', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); env.it('spec defining a custom spy strategy', function() { env.addSpyStrategy('frobnicate', strategy); var spy = env .createSpy('something') .and.returnValue('no args return') .withArgs(1, 2, 3) .and.frobnicate(17); expect(spy()).toEqual('no args return'); expect(plan).not.toHaveBeenCalled(); expect(spy(1, 2, 3)).toEqual(42); expect(plan).toHaveBeenCalledWith(1, 2, 3); }); env.it('spec without custom strategy defined', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); }); it('allows multiple custom strategies to be used', async function() { var plan1 = jasmine.createSpy('plan 1').and.returnValue(42), strategy1 = jasmine.createSpy('strat 1').and.returnValue(plan1), plan2 = jasmine.createSpy('plan 2').and.returnValue(24), strategy2 = jasmine.createSpy('strat 2').and.returnValue(plan2), specDone = jasmine.createSpy('specDone'); env.beforeEach(function() { env.addSpyStrategy('frobnicate', strategy1); env.addSpyStrategy('jiggle', strategy2); }); env.it('frobnicates', function() { plan1.calls.reset(); plan2.calls.reset(); var spy = env.createSpy('spy').and.frobnicate(); expect(spy()).toEqual(42); expect(plan1).toHaveBeenCalled(); expect(plan2).not.toHaveBeenCalled(); }); env.it('jiggles', function() { plan1.calls.reset(); plan2.calls.reset(); var spy = env.createSpy('spy').and.jiggle(); expect(spy()).toEqual(24); expect(plan1).not.toHaveBeenCalled(); expect(plan2).toHaveBeenCalled(); }); env.addReporter({ specDone: specDone }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); expect(specDone.calls.count()).toBe(2); }); }); jasmine-4.0.0/spec/core/integration/DefaultSpyStrategySpec.js000066400000000000000000000036201416413636100243300ustar00rootroot00000000000000describe('Default Spy Strategy (Integration)', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); afterEach(function() { env.cleanup_(); }); it('allows defining a default spy strategy', async function() { env.describe('suite with default strategy', function() { env.beforeEach(function() { env.setDefaultSpyStrategy(function(and) { and.returnValue(42); }); }); env.it('spec in suite', function() { var spy = env.createSpy('something'); expect(spy()).toBe(42); }); }); env.it('spec not in suite', function() { var spy = env.createSpy('something'); expect(spy()).toBeUndefined(); }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); }); it('uses the default spy strategy defined when the spy is created', async function() { env.it('spec', function() { var a = env.createSpy('a'); env.setDefaultSpyStrategy(function(and) { and.returnValue(42); }); var b = env.createSpy('b'); env.setDefaultSpyStrategy(function(and) { and.stub(); }); var c = env.createSpy('c'); env.setDefaultSpyStrategy(); var d = env.createSpy('d'); expect(a()).toBeUndefined(); expect(b()).toBe(42); expect(c()).toBeUndefined(); expect(d()).toBeUndefined(); // Check our assumptions about which spies are "configured" (this matters because // spies that use withArgs() behave differently if they are not configured). expect(a.and.isConfigured()).toBe(false); expect(b.and.isConfigured()).toBe(true); expect(c.and.isConfigured()).toBe(true); expect(d.and.isConfigured()).toBe(false); }); const result = await env.execute(); expect(result.overallStatus).toEqual('passed'); }); }); jasmine-4.0.0/spec/core/integration/DeprecationSpec.js000066400000000000000000000222601416413636100227630ustar00rootroot00000000000000/* eslint no-console: 0 */ describe('Deprecation (integration)', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); it('reports a deprecation on the top suite', function(done) { var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']); env.addReporter(reporter); spyOn(console, 'error'); env.beforeAll(function() { env.deprecated('the message'); }); env.it('a spec', function() {}); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching(/^DEPRECATION: the message/) ); done(); }); }); it('reports a deprecation on a descendent suite', function(done) { var reporter = jasmine.createSpyObj('reporter', ['suiteDone']); env.addReporter(reporter); spyOn(console, 'error'); env.describe('a suite', function() { env.beforeAll(function() { env.deprecated('the message'); }); env.it('a spec', function() {}); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching( /^DEPRECATION: the message \(in suite: a suite\)/ ) ); done(); }); }); it('reports a deprecation on a spec', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone']); env.addReporter(reporter); spyOn(console, 'error'); env.describe('a suite', function() { env.it('a spec', function() { env.deprecated('the message'); }); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching( /^DEPRECATION: the message \(in spec: a suite a spec\)/ ) ); done(); }); }); it('omits the suite or spec context when ignoreRunnable is true', function(done) { var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']); env.addReporter(reporter); spyOn(console, 'error'); env.it('a spec', function() { env.deprecated('the message', { ignoreRunnable: true }); }); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching(/the message/) ); expect(console.error).not.toHaveBeenCalledWith( jasmine.stringMatching(/a spec/) ); done(); }); }); it('includes the stack trace', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone']); env.addReporter(reporter); spyOn(console, 'error'); env.describe('a suite', function() { env.it('a spec', function() { env.deprecated('the message'); }); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ stack: jasmine.stringMatching(/DeprecationSpec.js/) }) ] }) ); expect(console.error).toHaveBeenCalled(); expect(console.error.calls.argsFor(0)[0].replace(/\n/g, 'NL')).toMatch( /^DEPRECATION: the message \(in spec: a suite a spec\)NL.*DeprecationSpec.js/ ); done(); }); }); it('excludes the stack trace when omitStackTrace is true', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone']); env.addReporter(reporter); spyOn(console, 'error'); env.describe('a suite', function() { env.it('a spec', function() { env.deprecated('the message', { omitStackTrace: true }); }); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ stack: jasmine.falsy() }) ] }) ); expect(console.error).toHaveBeenCalled(); expect(console.error).not.toHaveBeenCalledWith( jasmine.stringMatching(/DeprecationSpec.js/) ); done(); }); }); it('emits a given deprecation only once', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone', 'suiteDone']); env.addReporter(reporter); spyOn(console, 'error'); env.describe('a suite', function() { env.beforeAll(function() { env.deprecated('the message'); env.deprecated('the message'); }); env.it('a spec', function() { env.deprecated('the message'); env.deprecated('a different message'); }); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ // only one jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ // only the other one jasmine.objectContaining({ message: jasmine.stringMatching(/^a different message/) }) ] }) ); expect(console.error).toHaveBeenCalledTimes(2); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching( /^DEPRECATION: the message \(in suite: a suite\)/ ) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching( /^DEPRECATION: a different message \(in spec: a suite a spec\)/ ) ); done(); }); }); it('emits a given deprecation each time when config.verboseDeprecations is true', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone', 'suiteDone']); env.addReporter(reporter); spyOn(console, 'error'); env.configure({ verboseDeprecations: true }); env.describe('a suite', function() { env.beforeAll(function() { env.deprecated('the message'); env.deprecated('the message'); }); env.it('a spec', function() { env.deprecated('the message'); }); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }), jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledTimes(3); expect(console.error.calls.argsFor(0)[0]).toMatch( /^DEPRECATION: the message \(in suite: a suite\)/ ); expect(console.error.calls.argsFor(1)[0]).toMatch( /^DEPRECATION: the message \(in suite: a suite\)/ ); expect(console.error.calls.argsFor(2)[0]).toMatch( /^DEPRECATION: the message \(in spec: a suite a spec\)/ ); expect(console.error.calls.argsFor(2)[0]).toMatch( /^DEPRECATION: the message \(in spec: a suite a spec\)/ ); done(); }); }); it('handles deprecations that occur before execute() is called', function(done) { var reporter = jasmine.createSpyObj('reporter', ['jasmineDone']); env.addReporter(reporter); spyOn(console, 'error'); env.deprecated('the message'); env.it('a spec', function() {}); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalledWith( jasmine.objectContaining({ deprecationWarnings: [ jasmine.objectContaining({ message: jasmine.stringMatching(/^the message/) }) ] }) ); expect(console.error).toHaveBeenCalledWith( jasmine.stringMatching(/^DEPRECATION: the message/) ); done(); }); }); }); jasmine-4.0.0/spec/core/integration/EnvSpec.js000066400000000000000000002767341416413636100212770ustar00rootroot00000000000000describe('Env integration', function() { var env; beforeEach(function() { jasmine.getEnv().registerIntegrationMatchers(); env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); it('Suites execute as expected (no nesting)', function(done) { var calls = []; var assertions = function() { expect(calls).toEqual(['with a spec', 'and another spec']); done(); }; env.configure({ random: false }); env.describe('A Suite', function() { env.it('with a spec', function() { calls.push('with a spec'); }); env.it('and another spec', function() { calls.push('and another spec'); }); }); env.execute(null, assertions); }); it('Nested Suites execute as expected', function(done) { var calls = []; var assertions = function() { expect(calls).toEqual([ 'an outer spec', 'an inner spec', 'another inner spec' ]); done(); }; env.configure({ random: false }); env.describe('Outer suite', function() { env.it('an outer spec', function() { calls.push('an outer spec'); }); env.describe('Inner suite', function() { env.it('an inner spec', function() { calls.push('an inner spec'); }); env.it('another inner spec', function() { calls.push('another inner spec'); }); }); }); env.execute(null, assertions); }); it('Multiple top-level Suites execute as expected', function(done) { var calls = []; var assertions = function() { expect(calls).toEqual([ 'an outer spec', 'an inner spec', 'another inner spec', 'a 2nd outer spec' ]); done(); }; env.configure({ random: false }); env.describe('Outer suite', function() { env.it('an outer spec', function() { calls.push('an outer spec'); }); env.describe('Inner suite', function() { env.it('an inner spec', function() { calls.push('an inner spec'); }); env.it('another inner spec', function() { calls.push('another inner spec'); }); }); }); env.describe('Another outer suite', function() { env.it('a 2nd outer spec', function() { calls.push('a 2nd outer spec'); }); }); env.execute(null, assertions); }); it('explicitly fails a spec', function(done) { var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); env.describe('failing', function() { env.it('has a default message', function() { env.fail(); }); env.it('specifies a message', function() { env.fail('messy message'); }); env.it('has a message and stack trace from an Error', function() { env.fail(new Error('error message')); }); env.it('pretty prints objects', function() { env.fail({ prop: 'value', arr: ['works', true] }); }); }); env.execute(null, function() { expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'has a default message', failedExpectations: [ jasmine.objectContaining({ message: 'Failed' }) ] }) ); expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'specifies a message', failedExpectations: [ jasmine.objectContaining({ message: 'Failed: messy message' }) ] }) ); expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'has a message and stack trace from an Error', failedExpectations: [ jasmine.objectContaining({ message: 'Failed: error message', stack: { asymmetricMatch: function(other) { var split = other.split('\n'), firstLine = split[0]; if (firstLine.indexOf('error message') >= 0) { // Chrome inserts the message and a newline before the first stacktrace line. firstLine = split[1]; } return firstLine.indexOf('EnvSpec') >= 0; } } }) ] }) ); expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'pretty prints objects', failedExpectations: [ jasmine.objectContaining({ message: "Failed: Object({ prop: 'value', arr: [ 'works', true ] })" }) ] }) ); done(); }); }); it("produces an understandable error message when 'fail' is used outside of a current spec", function(done) { env.describe('A Suite', function() { env.it('an async spec that is actually synchronous', function( underTestCallback ) { underTestCallback(); }); expect(function() { env.fail(); }).toThrowError(/'fail' was used when there was no current spec/); }); env.execute(null, done); }); it("calls associated befores/specs/afters with the same 'this'", function(done) { env.configure({ random: false }); env.describe('tests', function() { var firstTimeThrough = true, firstSpecContext, secondSpecContext; env.beforeEach(function() { if (firstTimeThrough) { firstSpecContext = this; } else { secondSpecContext = this; } expect(this).toEqual(new jasmineUnderTest.UserContext()); }); env.it('sync spec', function() { expect(this).toBe(firstSpecContext); }); env.it('another sync spec', function() { expect(this).toBe(secondSpecContext); }); env.afterEach(function() { if (firstTimeThrough) { expect(this).toBe(firstSpecContext); firstTimeThrough = false; } else { expect(this).toBe(secondSpecContext); } }); }); env.execute(null, done); }); it("calls associated befores/its/afters with the same 'this' for an async spec", function(done) { env.describe('with an async spec', function() { var specContext; env.beforeEach(function() { specContext = this; expect(this).toEqual(new jasmineUnderTest.UserContext()); }); env.it('sync spec', function(underTestCallback) { expect(this).toBe(specContext); underTestCallback(); }); env.afterEach(function() { expect(this).toBe(specContext); }); }); env.execute(null, done); }); it('calls associated beforeAlls/afterAlls only once per suite', function(done) { var before = jasmine.createSpy('beforeAll'), after = jasmine.createSpy('afterAll'); env.describe('with beforeAll and afterAll', function() { env.it('spec', function() { expect(before).toHaveBeenCalled(); expect(after).not.toHaveBeenCalled(); }); env.it('another spec', function() { expect(before).toHaveBeenCalled(); expect(after).not.toHaveBeenCalled(); }); env.beforeAll(before); env.afterAll(after); }); env.execute(null, function() { expect(after).toHaveBeenCalled(); expect(after.calls.count()).toBe(1); expect(before.calls.count()).toBe(1); done(); }); }); it('calls associated beforeAlls/afterAlls only once per suite for async', function(done) { var before = jasmine.createSpy('beforeAll'), after = jasmine.createSpy('afterAll'); env.describe('with beforeAll and afterAll', function() { env.it('spec', function() { expect(before).toHaveBeenCalled(); expect(after).not.toHaveBeenCalled(); }); env.it('another spec', function() { expect(before).toHaveBeenCalled(); expect(after).not.toHaveBeenCalled(); }); env.beforeAll(function(beforeCallbackUnderTest) { before(); beforeCallbackUnderTest(); }); env.afterAll(function(afterCallbackUnderTest) { after(); afterCallbackUnderTest(); }); }); env.execute(null, function() { expect(after).toHaveBeenCalled(); expect(after.calls.count()).toBe(1); expect(before.calls.count()).toBe(1); done(); }); }); it("calls associated beforeAlls/afterAlls with the cascaded 'this'", function(done) { env.describe('with beforeAll and afterAll', function() { env.beforeAll(function() { this.x = 1; }); env.it('has an x at the root', function() { expect(this.x).toBe(1); }); env.describe('child that deletes', function() { env.beforeAll(function() { expect(this.x).toBe(1); delete this.x; }); env.it('has no x', function() { expect(this.x).not.toBeDefined(); }); }); env.describe('child should still have x', function() { env.beforeAll(function(innerDone) { expect(this.x).toBe(1); innerDone(); }); env.it('has an x', function() { expect(this.x).toBe(1); delete this.x; }); env.it('still has an x', function() { expect(this.x).toBe(1); }); env.it('adds a y', function() { this.y = 2; expect(this.y).toBe(2); }); env.it("doesn't have y that was added in sibling", function() { expect(this.y).not.toBeDefined(); }); }); }); env.execute(null, done); }); it('tags top-level afterAll failures with a type', function(done) { var jasmineDone = jasmine.createSpy('jasmineDone'); env.it('has a spec', function() {}); env.afterAll(function() { throw 'nope'; }); env.addReporter({ jasmineDone: jasmineDone }); env.execute(null, function() { { var result = jasmineDone.calls.argsFor(0)[0]; expect(result.failedExpectations[0].globalErrorType).toEqual( 'afterAll' ); done(); } }); }); it('does not tag suite afterAll failures with a type', function(done) { var reporter = { suiteDone: jasmine.createSpy('suiteDone').and.callFake(function(result) { expect(result.failedExpectations[0].globalErrorType).toBeFalsy(); }) }; env.addReporter(reporter); env.describe('a suite', function() { env.it('has a spec', function() {}); env.afterAll(function() { throw 'nope'; }); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalled(); done(); }); }); it('when the beforeAll fails, error at suite level', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'specDone', 'suiteDone' ]); var assertions = function() { expect(reporter.specDone.calls.count()).toEqual(2); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'A suite spec that will pass', [] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'A suite nesting another spec to pass', [] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'A suite', ['Expected 1 to be 2.'] ); done(); }; env.addReporter(reporter); env.describe('A suite', function() { env.beforeAll(function() { env.expect(1).toBe(2); }); env.it('spec that will pass', function() {}); env.describe('nesting', function() { env.it('another spec to pass', function() {}); }); }); env.execute(null, assertions); }); it('copes with async failures after done has been called', function(done) { if (jasmine.getEnv().skipBrowserFlake) { jasmine.getEnv().skipBrowserFlake(); } var global = { setTimeout: function(fn, delay) { return setTimeout(fn, delay); }, clearTimeout: function(fn, delay) { clearTimeout(fn, delay); } }; spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global); env.cleanup_(); env = new jasmineUnderTest.Env(); var reporter = jasmine.createSpyObj('fakeReporter', [ 'specDone', 'suiteDone' ]); var assertions = function() { expect(reporter.specDone).not.toHaveFailedExpectationsForRunnable( 'A suite fails', ['fail thrown'] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'A suite', ['fail thrown'] ); done(); }; env.addReporter(reporter); env.fdescribe('A suite', function() { env.it('fails', function(specDone) { setTimeout(function() { specDone(); setTimeout(function() { setTimeout(function() { global.onerror('fail'); }); }); }); }); }); env.describe('Ignored', function() { env.it('is not run', function() {}); }); env.execute(null, assertions); }); it('reports multiple calls to done in the top suite as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = 'A top-level beforeAll or afterAll function called its ' + "'done' callback more than once."; env.addReporter(reporter); env.beforeAll(function(innerDone) { innerDone(); innerDone(); }); env.it('a spec, so the beforeAll runs', function() {}); env.afterAll(function(innerDone) { innerDone(); innerDone(); }); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); const errors = reporter.jasmineDone.calls.argsFor(0)[0] .failedExpectations; expect(errors.length).toEqual(2); expect(errors[0].message) .withContext('top beforeAll') .toContain(message); expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('top afterAll') .toContain(message); expect(errors[1].globalErrorType).toEqual('lateError'); done(); }); }); it('reports multiple calls to done in a non-top suite as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = "An asynchronous beforeAll or afterAll function called its 'done' " + 'callback more than once.\n(in suite: a suite)'; env.addReporter(reporter); env.describe('a suite', function() { env.beforeAll(function(innerDone) { innerDone(); innerDone(); }); env.it('a spec, so that before/afters run', function() {}); env.afterAll(function(innerDone) { innerDone(); innerDone(); }); }); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); const errors = reporter.jasmineDone.calls.argsFor(0)[0] .failedExpectations; expect(errors.length).toEqual(2); expect(errors[0].message) .withContext('suite beforeAll') .toContain(message); expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('suite afterAll') .toContain(message); expect(errors[1].globalErrorType).toEqual('lateError'); done(); }); }); it('reports multiple calls to done in a spec as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = 'An asynchronous spec, beforeEach, or afterEach function called its ' + "'done' callback more than once.\n(in spec: a suite a spec)"; env.addReporter(reporter); env.describe('a suite', function() { env.beforeEach(function(innerDone) { innerDone(); innerDone(); }); env.it('a spec', function(innerDone) { innerDone(); innerDone(); }); env.afterEach(function(innerDone) { innerDone(); innerDone(); }); }); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); const errors = reporter.jasmineDone.calls.argsFor(0)[0] .failedExpectations; expect(errors.length).toEqual(3); expect(errors[0].message) .withContext('error caused by beforeEach') .toContain(message); expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('error caused by it') .toContain(message); expect(errors[1].globalErrorType).toEqual('lateError'); expect(errors[2].message) .withContext('error caused by afterEach') .toContain(message); expect(errors[2].globalErrorType).toEqual('lateError'); done(); }); }); it('reports multiple calls to done in reporters as errors', function(done) { var message = "An asynchronous reporter callback called its 'done' callback more " + 'than once.'; var reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone']); reporter.specDone = function(result, done) { done(); done(); }; env.addReporter(reporter); env.it('a spec', function() {}); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); const errors = reporter.jasmineDone.calls.argsFor(0)[0] .failedExpectations; expect(errors.length).toEqual(1); expect(errors[0].message).toContain(message); expect(errors[0].globalErrorType).toEqual('lateError'); done(); }); }); it('does not report an error for a call to done that comes after a timeout', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']), firstSpecDone; reporter.specDone = function(result, reporterDone) { setTimeout(function() { firstSpecDone(); reporterDone(); }); }; env.addReporter(reporter); env.it( 'a spec', function(innerDone) { firstSpecDone = innerDone; }, 1 ); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalledWith( jasmine.objectContaining({ failedExpectations: [] }) ); done(); }); }); describe('suiteDone reporting', function() { it('reports when an afterAll fails an expectation', function(done) { var reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']); var assertions = function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'my suite', ['Expected 1 to equal 2.', 'Expected 2 to equal 3.'] ); done(); }; env.addReporter(reporter); env.describe('my suite', function() { env.it('my spec', function() {}); env.afterAll(function() { env.expect(1).toEqual(2); env.expect(2).toEqual(3); }); }); env.execute(null, assertions); }); it('if there are no specs, it still reports correctly', function(done) { var reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']); var assertions = function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'outer suite', ['Expected 1 to equal 2.', 'Expected 2 to equal 3.'] ); done(); }; env.addReporter(reporter); env.describe('outer suite', function() { env.describe('inner suite', function() { env.it('spec', function() {}); }); env.afterAll(function() { env.expect(1).toEqual(2); env.expect(2).toEqual(3); }); }); env.execute(null, assertions); }); it('reports when afterAll throws an exception', function(done) { var error = new Error('After All Exception'), reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']); var assertions = function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'my suite', [/^Error: After All Exception/] ); done(); }; env.addReporter(reporter); env.describe('my suite', function() { env.it('my spec', function() {}); env.afterAll(function() { throw error; }); }); env.execute(null, assertions); }); it('reports when an async afterAll fails an expectation', function(done) { var reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']); var assertions = function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'my suite', ['Expected 1 to equal 2.'] ); done(); }; env.addReporter(reporter); env.describe('my suite', function() { env.it('my spec', function() {}); env.afterAll(function(afterAllDone) { env.expect(1).toEqual(2); afterAllDone(); }); }); env.execute(null, assertions); }); it('reports when an async afterAll throws an exception', function(done) { var error = new Error('After All Exception'), reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']); var assertions = function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'my suite', [/^Error: After All Exception/] ); done(); }; env.addReporter(reporter); env.describe('my suite', function() { env.it('my spec', function() {}); env.afterAll(function(afterAllDone) { throw error; }); }); env.execute(null, assertions); }); it('reports the duration of the suite', function(done) { var duration; env.addReporter({ suiteDone: function(result) { expect(duration).toBeUndefined(); duration = result.duration; } }); env.describe('my suite', function() { env.it('takes time', function(done) { // We can't just use the mock clock here because the timer is designed // to record real time even when the mock clock is installed. setTimeout(done, 10); }); }); env.execute(null, function() { // Expect > 0 to compensate for clock imprecision expect(duration).toBeGreaterThan(0); done(); }); }); }); describe('specDone reporting', function() { it('reports the duration of the spec', function(done) { var duration; env.addReporter({ specDone: function(result) { expect(duration).toBeUndefined(); duration = result.duration; } }); env.describe('my suite', function() { env.it('takes time', function(done) { // We can't just use the mock clock here because the timer is designed // to record real time even when the mock clock is installed. setTimeout(done, 10); }); }); env.execute(null, function() { // Expect > 0 to compensate for clock imprecision expect(duration).toBeGreaterThan(0); done(); }); }); }); it('reports expectation failures in global beforeAll', function(done) { var reporter = jasmine.createSpyObj(['specDone', 'jasmineDone']); env.beforeAll(function() { env.expect(1).toBe(0); }); env.it('is a spec', function() { env.expect(true).toBe(true); }); env.addReporter(reporter); env.execute(null, function() { var results = reporter.jasmineDone.calls.argsFor(0)[0]; expect(results.failedExpectations).toEqual([ jasmine.objectContaining({ message: 'Expected 1 to be 0.' }) ]); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'is a spec', [] ); done(); }); }); it('reports expectation failures in global afterAll', function(done) { var reporter = jasmine.createSpyObj(['jasmineDone']); env.afterAll(function() { env.expect(1).toBe(0); }); env.it('is a spec', function() { env.expect(true).toBe(true); }); env.addReporter(reporter); env.execute(null, function() { var results = reporter.jasmineDone.calls.argsFor(0)[0]; expect(results.failedExpectations).toEqual([ jasmine.objectContaining({ message: 'Expected 1 to be 0.' }) ]); done(); }); }); it('Allows specifying which specs and suites to run', function(done) { var calls = [], suiteCallback = jasmine.createSpy('suite callback'), firstSpec, secondSuite; env.addReporter({ suiteDone: suiteCallback }); env.describe('first suite', function() { firstSpec = env.it('first spec', function() { calls.push('first spec'); }); env.it('second spec', function() { calls.push('second spec'); }); }); secondSuite = env.describe('second suite', function() { env.it('third spec', function() { calls.push('third spec'); }); }); env.execute([secondSuite.id, firstSpec.id], function() { expect(calls).toEqual(['third spec', 'first spec']); expect(suiteCallback).toHaveBeenCalled(); done(); }); }); it('runs before and after all functions for runnables provided to .execute()', function(done) { var calls = [], first_spec, second_spec; env.describe('first suite', function() { env.beforeAll(function() { calls.push('before'); }); env.afterAll(function() { calls.push('after'); }); first_spec = env.it('spec', function() { calls.push('first spec'); }); second_spec = env.it('spec 2', function() { calls.push('second spec'); }); }); env.execute([first_spec.id, second_spec.id], function() { expect(calls).toEqual(['before', 'first spec', 'second spec', 'after']); done(); }); }); it('Allows filtering out specs and suites to run programmatically', function(done) { var calls = [], suiteCallback = jasmine.createSpy('suite callback'), firstSpec, secondSuite; env.addReporter({ suiteDone: suiteCallback }); env.describe('first suite', function() { env.it('first spec', function() { calls.push('first spec'); }); env.it('second spec', function() { calls.push('second spec'); }); }); secondSuite = env.describe('second suite', function() { env.it('third spec', function() { calls.push('third spec'); }); }); env.configure({ specFilter: function(spec) { return /^first suite/.test(spec.getFullName()); } }); env.execute(null, function() { expect(calls.length).toEqual(2); expect(calls).toEqual( jasmine.arrayContaining(['first spec', 'second spec']) ); expect(suiteCallback).toHaveBeenCalled(); done(); }); }); it('Functions can be spied on and have their calls tracked', function(done) { var originalFunctionWasCalled = false; var subject = { spiedFunc: function() { originalFunctionWasCalled = true; return 'original result'; } }; env.it('works with spies', function() { var spy = env .spyOn(subject, 'spiedFunc') .and.returnValue('stubbed result'); expect(subject.spiedFunc).toEqual(spy); expect(subject.spiedFunc.calls.any()).toEqual(false); expect(subject.spiedFunc.calls.count()).toEqual(0); subject.spiedFunc('foo'); expect(subject.spiedFunc.calls.any()).toEqual(true); expect(subject.spiedFunc.calls.count()).toEqual(1); expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['foo']); expect(subject.spiedFunc.calls.mostRecent().object).toEqual(subject); expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual( 'stubbed result' ); expect(originalFunctionWasCalled).toEqual(false); subject.spiedFunc.and.callThrough(); subject.spiedFunc('bar'); expect(subject.spiedFunc.calls.count()).toEqual(2); expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']); expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual( 'original result' ); expect(originalFunctionWasCalled).toEqual(true); }); env.it( 'works with constructors when using callThrough spy strategy', function() { function MyClass(foo) { if (!(this instanceof MyClass)) throw new Error('You must use the new keyword.'); this.foo = foo; } var subject = { MyClass: MyClass }; var spy = env.spyOn(subject, 'MyClass').and.callThrough(); expect(function() { var result = new spy('hello world'); expect(result instanceof MyClass).toBeTruthy(); expect(result.foo).toEqual('hello world'); }).not.toThrow(); expect(function() { var result = new spy( 'passing', 'extra', 'arguments', 'to', 'constructor' ); expect(result instanceof MyClass).toBeTruthy(); expect(result.foo).toEqual('passing'); }).not.toThrow(); expect(function() { spy('hello world'); }).toThrowError('You must use the new keyword.'); } ); env.execute(null, done); }); it('can be configured to allow respying on functions', function(done) { var foo = { bar: function() { return 1; } }; env.allowRespy(true); env.describe('test suite', function() { env.it('spec 0', function() { env.spyOn(foo, 'bar'); var error = null; expect(function() { env.spyOn(foo, 'bar'); }).not.toThrow(); }); }); env.execute(null, done); }); it('removes all spies added in a spec after the spec is complete', function(done) { var originalFoo = function() {}, testObj = { foo: originalFoo }, firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() { env.spyOn(testObj, 'foo'); }), secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() { expect(testObj.foo).toBe(originalFoo); }); env.describe('test suite', function() { env.it('spec 0', firstSpec); env.it('spec 1', secondSpec); }); env.execute(null, function() { expect(firstSpec).toHaveBeenCalled(); expect(secondSpec).toHaveBeenCalled(); done(); }); }); it('removes all spies added in a suite after the suite is complete', function(done) { var originalFoo = function() {}, testObj = { foo: originalFoo }; env.describe('test suite', function() { env.beforeAll(function() { env.spyOn(testObj, 'foo'); }); env.it('spec 0', function() { expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true); }); env.it('spec 1', function() { expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true); }); }); env.describe('another suite', function() { env.it('spec 2', function() { expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(false); }); }); env.execute(null, done); }); it('removes a spy from the top suite after the run is complete', function(done) { var originalFoo = function() {}, testObj = { foo: originalFoo }; env.beforeAll(function() { env.spyOn(testObj, 'foo'); }); env.it('spec', function() { expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true); }); env.execute(null, function() { expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(false); done(); }); }); it('Mock clock can be installed and used in tests', function(done) { if (jasmine.getEnv().skipBrowserFlake) { jasmine.getEnv().skipBrowserFlake(); } var globalSetTimeout = jasmine .createSpy('globalSetTimeout') .and.callFake(function(cb, t) { return setTimeout(cb, t); }), delayedFunctionForGlobalClock = jasmine.createSpy( 'delayedFunctionForGlobalClock' ), delayedFunctionForMockClock = jasmine.createSpy( 'delayedFunctionForMockClock' ); env.cleanup_(); env = new jasmineUnderTest.Env({ global: { setTimeout: globalSetTimeout, clearTimeout: clearTimeout, setImmediate: function(cb) { return setTimeout(cb, 0); } } }); env.configure({ random: false }); env.describe('tests', function() { env.it('test with mock clock', function() { env.clock.install(); env.clock.setTimeout(delayedFunctionForMockClock, 100); env.clock.tick(100); env.clock.uninstall(); }); env.it('test without mock clock', function() { env.clock.setTimeout(delayedFunctionForGlobalClock, 100); }); }); expect(globalSetTimeout).not.toHaveBeenCalled(); expect(delayedFunctionForMockClock).not.toHaveBeenCalled(); env.execute(null, function() { expect(delayedFunctionForMockClock).toHaveBeenCalled(); expect(globalSetTimeout).toHaveBeenCalledWith( delayedFunctionForGlobalClock, 100 ); done(); }); }); it('should run async specs in order, waiting for them to complete', function(done) { var mutatedVar; env.describe('tests', function() { env.beforeEach(function() { mutatedVar = 2; }); env.it('async spec', function(underTestCallback) { setTimeout(function() { expect(mutatedVar).toEqual(2); underTestCallback(); }, 0); }); env.it('after async spec', function() { mutatedVar = 3; }); }); env.execute(null, done); }); describe('with a mock clock', function() { var realSetTimeout; function createMockedEnv() { env.cleanup_(); // explicitly pass in timing functions so we can make sure that clear stack always works // no matter how long the suite in the spec is env = new jasmineUnderTest.Env({ global: { setTimeout: function(cb, t) { var stack = jasmine.util.errorWithStack().stack; if (stack.indexOf('ClearStack') >= 0) { return realSetTimeout(cb, t); } else { return setTimeout(cb, t); } }, clearTimeout: clearTimeout, setInterval: setInterval, clearInterval: clearInterval, setImmediate: function(cb) { return realSetTimeout(cb, 0); } } }); } beforeEach(function() { this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL; realSetTimeout = setTimeout; jasmine.clock().install(); }); afterEach(function() { jasmine.clock().tick(1); jasmine.clock().tick(1); jasmine.clock().uninstall(); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.originalTimeout; }); it("should wait a default interval before failing specs that haven't called done yet", function(done) { createMockedEnv(); var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); reporter.specDone.and.callFake(function(result) { expect(result).toEqual(jasmine.objectContaining({ status: 'failed' })); realSetTimeout(function() { jasmine.clock().tick(1); }, 0); }); env.addReporter(reporter); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 8414; env.it("async spec that doesn't call done", function(underTestCallback) { env.expect(true).toBeTruthy(); jasmine.clock().tick(8416); jasmine.clock().tick(1); }); env.execute(null, function() { expect(reporter.specDone.calls.count()).toEqual(1); jasmine.clock().tick(1); realSetTimeout(done); }); }); it('should not use the mock clock for asynchronous timeouts', function(done) { if (jasmine.getEnv().skipBrowserFlake) { jasmine.getEnv().skipBrowserFlake(); } createMockedEnv(); var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']), clock = env.clock; reporter.specDone.and.callFake(function() { realSetTimeout(function() { jasmine.clock().tick(1); }, 0); }); env.addReporter(reporter); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 5; env.beforeAll(function() { clock.install(); }); env.afterAll(function() { clock.uninstall(); }); env.it('spec that should not time out', function(innerDone) { clock.tick(6); expect(true).toEqual(true); realSetTimeout(innerDone); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalledTimes(1); expect(reporter.specDone.calls.argsFor(0)[0]).toEqual( jasmine.objectContaining({ status: 'passed' }) ); jasmine.clock().tick(1); realSetTimeout(done); }); }); it('should wait a custom interval before reporting async functions that fail to complete', function(done) { if (jasmine.getEnv().skipBrowserFlake) { jasmine.getEnv().skipBrowserFlake(); } createMockedEnv(); var reporter = jasmine.createSpyObj('fakeReport', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 10000; env.describe('suite', function() { env.afterAll(function() { realSetTimeout(function() { try { jasmine.clock().tick(10); } catch (e) { // don't worry if the clock is already uninstalled } }, 100); }); env.describe('beforeAll', function() { env.beforeAll(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(5001); }, 0); }, 5000); env.it('times out', function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1); innerDone(); }, 0); }); }); env.describe('afterAll', function() { env.afterAll(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(2001); }, 0); }, 2000); env.it('times out', function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1); innerDone(); }, 0); }); }); env.describe('beforeEach', function() { env.beforeEach(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1001); }, 0); }, 1000); env.it('times out', function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1); innerDone(); }, 0); }); }); env.describe('afterEach', function() { env.afterEach(function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(4001); }, 0); }, 4000); env.it('times out', function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(1); innerDone(); }, 0); }); }); env.it( 'it times out', function(innerDone) { realSetTimeout(function() { jasmine.clock().tick(6001); }, 0); }, 6000 ); }); env.execute(null, function() { var r = reporter.jasmineDone.calls.argsFor(0)[0]; expect(r.failedExpectations).toEqual([]); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'suite beforeAll', [ /^Error: Timeout - Async function did not complete within 5000ms \(custom timeout\)/ ] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'suite afterAll', [ /^Error: Timeout - Async function did not complete within 2000ms \(custom timeout\)/ ] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite beforeEach times out', [ /^Error: Timeout - Async function did not complete within 1000ms \(custom timeout\)/ ] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite afterEach times out', [ /^Error: Timeout - Async function did not complete within 4000ms \(custom timeout\)/ ] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite it times out', [ /^Error: Timeout - Async function did not complete within 6000ms \(custom timeout\)/ ] ); jasmine.clock().tick(1); realSetTimeout(done); }); }); }); it('explicitly fails an async spec', function(done) { var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); env.describe('failing', function() { env.it('has a default message', function(innerDone) { setTimeout(function() { env.fail(); innerDone(); }, 1); }); env.it('specifies a message', function(innerDone) { setTimeout(function() { env.fail('messy message'); innerDone(); }, 1); }); env.it('fails via the done callback', function(innerDone) { setTimeout(function() { innerDone.fail('done failed'); }, 1); }); env.it('has a message from an Error', function(innerDone) { setTimeout(function() { env.fail(new Error('error message')); innerDone(); }, 1); }); env.it('has a message from an Error to done', function(innerDone) { setTimeout(function() { innerDone(new Error('done error')); }, 1); }); }); env.execute(null, function() { expect(specDone).toHaveFailedExpectationsForRunnable( 'failing has a default message', ['Failed'] ); expect(specDone).toHaveFailedExpectationsForRunnable( 'failing specifies a message', ['Failed: messy message'] ); expect(specDone).toHaveFailedExpectationsForRunnable( 'failing fails via the done callback', ['Failed: done failed'] ); expect(specDone).toHaveFailedExpectationsForRunnable( 'failing has a message from an Error', ['Failed: error message'] ); expect(specDone).toHaveFailedExpectationsForRunnable( 'failing has a message from an Error to done', ['Failed: done error'] ); setTimeout(done); }); }); describe('focused tests', function() { it('should only run the focused tests', function(done) { var calls = []; env.describe('a suite', function() { env.fit('is focused', function() { calls.push('focused'); }); env.it('is not focused', function() { calls.push('freakout'); }); }); env.execute(null, function() { expect(calls).toEqual(['focused']); done(); }); }); it('should only run focused suites', function(done) { var calls = []; env.fdescribe('a focused suite', function() { env.it('is focused', function() { calls.push('focused'); }); }); env.describe('a regular suite', function() { env.it('is not focused', function() { calls.push('freakout'); }); }); env.execute(null, function() { expect(calls).toEqual(['focused']); done(); }); }); it('should run focused tests inside an xdescribe', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'jasmineStarted', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); env.xdescribe('xd suite', function() { env.fit('with a fit spec', function() { env.expect(true).toBe(false); }); }); env.execute(null, function() { expect(reporter.jasmineStarted).toHaveBeenCalledWith({ totalSpecsDefined: 1, order: jasmine.any(jasmineUnderTest.Order) }); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'with a fit spec', status: 'failed' }) ); done(); }); }); it('should run focused suites inside an xdescribe', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'jasmineStarted', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); env.xdescribe('xd suite', function() { env.fdescribe('fd suite', function() { env.it('with a spec', function() { env.expect(true).toBe(false); }); }); }); env.execute(null, function() { expect(reporter.jasmineStarted).toHaveBeenCalledWith({ totalSpecsDefined: 1, order: jasmine.any(jasmineUnderTest.Order) }); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'with a spec', status: 'failed' }) ); done(); }); }); }); it('should report as expected', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'jasmineStarted', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); env.describe('A Suite', function() { env.it('with a top level spec', function() { env.expect(true).toBe(true); }); env.describe('with a nested suite', function() { env.xit("with an x'ed spec", function() { env.expect(true).toBe(true); }); env.it('with a spec', function() { env.expect(true).toBe(false); }); }); env.describe('with only non-executable specs', function() { env.it('is pending'); env.xit('is xed', function() { env.expect(true).toBe(true); }); }); }); env.execute(null, function() { expect(reporter.jasmineStarted).toHaveBeenCalledWith({ totalSpecsDefined: 5, order: jasmine.any(jasmineUnderTest.Order) }); expect(reporter.specDone.calls.count()).toBe(5); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'with a top level spec', status: 'passed' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: "with an x'ed spec", status: 'pending' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'with a spec', status: 'failed' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'is pending', status: 'pending' }) ); var suiteDone = reporter.suiteDone.calls.argsFor(0)[0]; expect(typeof suiteDone.duration).toBe('number'); var suiteResult = reporter.suiteStarted.calls.argsFor(0)[0]; expect(suiteResult.description).toEqual('A Suite'); done(); }); }); it('should report the random seed at the beginning and end of execution', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'jasmineStarted', 'jasmineDone', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.configure({ random: true, seed: '123456' }); env.addReporter(reporter); env.configure({ random: true }); env.execute(null, function() { expect(reporter.jasmineStarted).toHaveBeenCalled(); var startedArg = reporter.jasmineStarted.calls.argsFor(0)[0]; expect(startedArg.order.random).toEqual(true); expect(startedArg.order.seed).toEqual('123456'); var doneArg = reporter.jasmineDone.calls.argsFor(0)[0]; expect(doneArg.order.random).toEqual(true); expect(doneArg.order.seed).toEqual('123456'); done(); }); }); it('should report pending spec messages', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.it('will be pending', function() { env.pending('with a message'); }); env.execute(null, function() { var specStatus = reporter.specDone.calls.argsFor(0)[0]; expect(specStatus.status).toBe('pending'); expect(specStatus.pendingReason).toBe('with a message'); done(); }); }); it('should report pending spec messages from promise-returning functions', function(done) { function StubPromise(fn) { try { fn(); } catch (e) { this.exception = e; } } StubPromise.prototype.then = function(resolve, reject) { reject(this.exception); }; var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.it('will be pending', function() { return new StubPromise(function() { env.pending('with a message'); }); }); env.execute(null, function() { var specStatus = reporter.specDone.calls.argsFor(0)[0]; expect(specStatus.status).toBe('pending'); expect(specStatus.pendingReason).toBe('with a message'); done(); }); }); it('should report using fallback reporter', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'specDone', 'jasmineDone' ]); reporter.jasmineDone.and.callFake(function() { expect(reporter.specDone).toHaveBeenCalled(); done(); }); env.provideFallbackReporter(reporter); env.it('will be pending', function() { env.pending('with a message'); }); env.execute(); }); it('should report xdescribes as expected', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', [ 'jasmineStarted', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); env.describe('A Suite', function() { env.describe('nested', function() { env.xdescribe('xd out', function() { env.describe('nested again', function() { env.it('with a spec', function() { env.expect(true).toBe(false); }); }); }); }); }); env.execute(null, function() { expect(reporter.jasmineStarted).toHaveBeenCalledWith({ totalSpecsDefined: 1, order: jasmine.any(jasmineUnderTest.Order) }); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ status: 'pending' }) ); expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'xd out', status: 'pending' }) ); expect(reporter.suiteDone.calls.count()).toBe(4); done(); }); }); it('should be possible to get full name from a spec', function() { var topLevelSpec, nestedSpec, doublyNestedSpec; env.describe('my tests', function() { topLevelSpec = env.it('are sometimes top level', function() {}); env.describe('are sometimes', function() { nestedSpec = env.it('singly nested', function() {}); env.describe('even', function() { doublyNestedSpec = env.it('doubly nested', function() {}); }); }); }); expect(topLevelSpec.getFullName()).toBe('my tests are sometimes top level'); expect(nestedSpec.getFullName()).toBe( 'my tests are sometimes singly nested' ); expect(doublyNestedSpec.getFullName()).toBe( 'my tests are sometimes even doubly nested' ); }); it('Custom equality testers should be per spec', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.configure({ random: false }); env.describe('testing custom equality testers', function() { env.it('with a custom tester', function() { env.addCustomEqualityTester(function(a, b) { return true; }); env.expect('a').toEqual('b'); }); env.it('without a custom tester', function() { env.expect('a').toEqual('b'); }); }); env.execute(null, function() { var firstSpecResult = reporter.specDone.calls.first().args[0], secondSpecResult = reporter.specDone.calls.mostRecent().args[0]; expect(firstSpecResult.status).toEqual('passed'); expect(secondSpecResult.status).toEqual('failed'); done(); }); }); it('Custom equality testers should be per suite', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.configure({ random: false }); env.describe('testing custom equality testers', function() { env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; }); }); env.it('with a custom tester', function() { env.expect('a').toEqual('b'); }); env.it('with the same custom tester', function() { env.expect('a').toEqual('b'); }); }); env.describe('another suite', function() { env.it('without the custom tester', function() { env.expect('a').toEqual('b'); }); }); env.execute(null, function() { var firstSpecResult = reporter.specDone.calls.first().args[0], secondSpecResult = reporter.specDone.calls.argsFor(0)[0], thirdSpecResult = reporter.specDone.calls.mostRecent().args[0]; expect(firstSpecResult.status).toEqual('passed'); expect(secondSpecResult.status).toEqual('passed'); expect(thirdSpecResult.status).toEqual('failed'); done(); }); }); it('Custom equality testers for toContain should be per spec', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.configure({ random: false }); env.describe('testing custom equality testers', function() { env.it('with a custom tester', function() { env.addCustomEqualityTester(function(a, b) { return true; }); env.expect(['a']).toContain('b'); }); env.it('without a custom tester', function() { env.expect(['a']).toContain('b'); }); }); env.execute(null, function() { var firstSpecResult = reporter.specDone.calls.first().args[0], secondSpecResult = reporter.specDone.calls.mostRecent().args[0]; expect(firstSpecResult.status).toEqual('passed'); expect(secondSpecResult.status).toEqual('failed'); done(); }); }); it("produces an understandable error message when an 'expect' is used outside of a current spec", function(done) { env.describe('A Suite', function() { env.it('an async spec that is actually synchronous', function( underTestCallback ) { underTestCallback(); }); expect(function() { env.expect('a').toEqual('a'); }).toThrowError(/'expect' was used when there was no current spec/); }); env.execute(null, done); }); it('Custom equality testers for toContain should be per suite', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); env.addReporter(reporter); env.configure({ random: false }); env.describe('testing custom equality testers', function() { env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; }); }); env.it('with a custom tester', function() { env.expect(['a']).toContain('b'); }); env.it('also with the custom tester', function() { env.expect(['a']).toContain('b'); }); }); env.describe('another suite', function() { env.it('without the custom tester', function() { env.expect(['a']).toContain('b'); }); }); env.execute(null, function() { var firstSpecResult = reporter.specDone.calls.first().args[0], secondSpecResult = reporter.specDone.calls.argsFor(1)[0], thirdSpecResult = reporter.specDone.calls.mostRecent().args[0]; expect(firstSpecResult.status).toEqual('passed'); expect(secondSpecResult.status).toEqual('passed'); expect(thirdSpecResult.status).toEqual('failed'); done(); }); }); it('Custom matchers should be per spec', function(done) { var matchers = { toFoo: function() {} }; env.describe('testing custom matchers', function() { env.it('with a custom matcher', function() { env.addMatchers(matchers); expect(env.expect().toFoo).toBeDefined(); }); env.it('without a custom matcher', function() { expect(env.expect().toFoo).toBeUndefined(); }); }); env.execute(null, done); }); it('Custom matchers should be per suite', function(done) { var matchers = { toFoo: function() {} }; env.describe('testing custom matchers', function() { env.beforeAll(function() { env.addMatchers(matchers); }); env.it('with a custom matcher', function() { expect(env.expect().toFoo).toBeDefined(); }); env.it('with the same custom matcher', function() { expect(env.expect().toFoo).toBeDefined(); }); }); env.describe('another suite', function() { env.it('no longer has the custom matcher', function() { expect(env.expect().toFoo).not.toBeDefined(); }); }); env.execute(null, done); }); it('throws an exception if you try to create a spy outside of a runnable', function(done) { var obj = { fn: function() {} }, exception; env.describe('a suite', function() { try { env.spyOn(obj, 'fn'); } catch (e) { exception = e; } env.it('has a test', function() {}); }); env.execute(null, function() { expect(exception.message).toBe( 'Spies must be created in a before function or a spec' ); done(); }); }); it('throws an exception if you try to add a matcher outside of a runnable', function(done) { var obj = { fn: function() {} }, exception; env.describe('a suite', function() { try { env.addMatchers({ myMatcher: function(actual, expected) { return false; } }); } catch (e) { exception = e; } env.it('has a test', function() {}); }); env.execute(null, function() { expect(exception.message).toBe( 'Matchers must be added in a before function or a spec' ); done(); }); }); it('throws an exception if you try to add a custom equality outside of a runnable', function(done) { var obj = { fn: function() {} }, exception; env.describe('a suite', function() { try { env.addCustomEqualityTester(function(first, second) { return true; }); } catch (e) { exception = e; } env.it('has a test', function() {}); }); env.execute(null, function() { expect(exception.message).toBe( 'Custom Equalities must be added in a before function or a spec' ); done(); }); }); it('reports test properties on specs', function(done) { var env = new jasmineUnderTest.Env(), reporter = jasmine.createSpyObj('reporter', ['suiteDone', 'specDone']); reporter.specDone.and.callFake(function(e) { expect(e.properties).toEqual({ a: 'Bee' }); }); env.addReporter(reporter); env.it('calls setSpecProperty', function() { env.setSpecProperty('a', 'Bee'); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalled(); done(); }); }); it('throws an exception if you try to setSpecProperty outside of a spec', function(done) { var env = new jasmineUnderTest.Env(), exception; env.describe('a suite', function() { env.it('a spec'); try { env.setSpecProperty('a prop', 'val'); } catch (e) { exception = e; } env.it('has a test', function() {}); }); env.execute(null, function() { expect(exception.message).toBe( "'setSpecProperty' was used when there was no current spec" ); done(); }); }); it('reports test properties on suites', function(done) { var env = new jasmineUnderTest.Env(), reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); reporter.suiteDone.and.callFake(function(e) { expect(e.properties).toEqual({ b: 'Sweet' }); }); env.addReporter(reporter); env.describe('calls setSuiteProperty', function() { env.beforeEach(function() { env.setSuiteProperty('b', 'Sweet'); }); env.it('a passing spec', function() { expect.nothing(); }); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalled(); done(); }); }); it('throws an exception if you try to setSuiteProperty outside of a suite', function(done) { var env = new jasmineUnderTest.Env(); try { env.setSuiteProperty('a', 'Bee'); } catch (e) { expect(e.message).toBe( "'setSuiteProperty' was used when there was no current suite" ); done(); } }); it('should associate errors thrown from async code with the correct runnable', function(done) { var reporter = jasmine.createSpyObj('fakeReport', [ 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.describe('async suite', function() { env.afterAll(function(innerDone) { setTimeout(function() { throw new Error('suite'); }, 1); }, 10); env.it('spec', function() {}); }); env.describe('suite', function() { env.it( 'async spec', function(innerDone) { setTimeout(function() { throw new Error('spec'); }, 1); }, 10 ); }); env.execute(null, function() { expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'async suite', [ /^(((Uncaught )?(exception: )?Error: suite( thrown)?)|(suite thrown))$/ ] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite async spec', [/^(((Uncaught )?(exception: )?Error: spec( thrown)?)|(spec thrown))$/] ); done(); }); }); it("should throw on suites/specs/befores/afters nested in methods other than 'describe'", function(done) { var reporter = jasmine.createSpyObj('reporter', ['suiteDone', 'specDone']); env.addReporter(reporter); env.describe('suite', function() { env.it('describe', function() { env.describe('inner suite', function() {}); }); env.it('xdescribe', function() { env.xdescribe('inner suite', function() {}); }); env.it('fdescribe', function() { env.fdescribe('inner suite', function() {}); }); }); env.describe('spec', function() { env.it('it', function() { env.it('inner spec', function() {}); }); env.it('xit', function() { env.xit('inner spec', function() {}); }); env.it('fit', function() { env.fit('inner spec', function() {}); }); }); env.describe('beforeAll', function() { env.beforeAll(function() { env.beforeAll(function() {}); }); env.it('spec', function() {}); }); env.describe('beforeEach', function() { env.beforeEach(function() { env.beforeEach(function() {}); }); env.it('spec', function() {}); }); env.describe('afterAll', function() { env.afterAll(function() { env.afterAll(function() {}); }); env.it('spec', function() {}); }); env.describe('afterEach', function() { env.afterEach(function() { env.afterEach(function() {}); }); env.it('spec', function() {}); }); env.execute(null, function() { var msg = /\'.*\' should only be used in \'describe\' function/; expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite describe', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite xdescribe', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'suite fdescribe', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable('spec it', [ msg ]); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'spec xit', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'spec fit', [msg] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'beforeAll', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'beforeEach spec', [msg] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'afterAll', [msg] ); expect(reporter.specDone).toHaveFailedExpectationsForRunnable( 'afterEach spec', [msg] ); done(); }); }); it('reports errors that occur during loading', function(done) { var global = { setTimeout: function(fn, delay) { return setTimeout(fn, delay); }, clearTimeout: function(fn, delay) { clearTimeout(fn, delay); }, onerror: function() {} }; spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global); env.cleanup_(); env = new jasmineUnderTest.Env(); var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); global.onerror( 'Uncaught SyntaxError: Unexpected end of input', 'borkenSpec.js', 42, undefined, { stack: 'a stack' } ); global.onerror('Uncaught Error: ENOCHEESE'); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.failedExpectations).toEqual([ { passed: false, globalErrorType: 'load', message: 'Uncaught SyntaxError: Unexpected end of input', stack: 'a stack', filename: 'borkenSpec.js', lineno: 42 }, { passed: false, globalErrorType: 'load', message: 'Uncaught Error: ENOCHEESE', stack: undefined, filename: undefined, lineno: undefined } ]); done(); }); }); describe('If suppressLoadErrors: true was passed', function() { it('does not install a global error handler during loading', function(done) { var originalOnerror = jasmine.createSpy('original onerror'); var global = { setTimeout: function(fn, delay) { return setTimeout(fn, delay); }, clearTimeout: function(fn, delay) { clearTimeout(fn, delay); }, onerror: originalOnerror }; spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global); var globalErrors = new jasmineUnderTest.GlobalErrors(global); var onerror = jasmine.createSpy('onerror'); globalErrors.pushListener(onerror); spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors); env.cleanup_(); env = new jasmineUnderTest.Env({ suppressLoadErrors: true }); var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); global.onerror('Uncaught Error: ENOCHEESE'); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.failedExpectations).toEqual([]); expect(originalOnerror).toHaveBeenCalledWith( 'Uncaught Error: ENOCHEESE' ); done(); }); }); }); describe('Overall status in the jasmineDone event', function() { describe('When everything passes', function() { it('is "passed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.it('passes', function() {}); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('passed'); done(); }); }); }); describe('When a spec fails', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.it('fails', function() { env.expect(true).toBe(false); }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); }); describe('when spec has no expectations', function() { var reporter; beforeEach(function() { reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.it('is a spec without any expectations', function() { // does nothing, just a mock spec without expectations }); }); it('should report "failed" status if "failSpecWithNoExpectations" is enabled', function(done) { env.configure({ failSpecWithNoExpectations: true }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); it('should report "passed" status if "failSpecWithNoExpectations" is disabled', function(done) { env.configure({ failSpecWithNoExpectations: false }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('passed'); done(); }); }); }); describe('When a top-level beforeAll fails', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.beforeAll(function() { throw new Error('nope'); }); env.it('does not run', function() {}); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); }); describe('When a suite beforeAll fails', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.describe('something', function() { env.beforeAll(function() { throw new Error('nope'); }); env.it('does not run', function() {}); }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); }); describe('When a top-level afterAll fails', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.afterAll(function() { throw new Error('nope'); }); env.it('does not run', function() {}); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); }); describe('When a suite afterAll fails', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.describe('something', function() { env.afterAll(function() { throw new Error('nope'); }); env.it('does not run', function() {}); }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); done(); }); }); }); describe('When there are load errors', function() { it('is "failed"', function(done) { var global = { setTimeout: function(fn, delay) { return setTimeout(fn, delay); }, clearTimeout: function(fn, delay) { return clearTimeout(fn, delay); } }; spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global); env.cleanup_(); env = new jasmineUnderTest.Env(); var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); reporter.jasmineDone.and.callFake(function(e) { expect(e.overallStatus).toEqual('failed'); }); env.addReporter(reporter); env.it('passes', function() {}); global.onerror('Uncaught Error: ENOCHEESE'); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); done(); }); }); }); describe('When there are no specs', function() { it('is "incomplete"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('incomplete'); expect(e.incompleteReason).toEqual('No specs found'); done(); }); }); }); describe('When a spec is focused', function() { it('is "incomplete"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.fit('is focused', function() {}); env.execute(null, function(e) { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('incomplete'); expect(e.incompleteReason).toEqual('fit() or fdescribe() was found'); done(); }); }); }); describe('When a suite is focused', function() { it('is "incomplete"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.fdescribe('something focused', function() { env.it('does a thing', function() {}); }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('incomplete'); expect(e.incompleteReason).toEqual('fit() or fdescribe() was found'); done(); }); }); }); describe('When there are both failures and focused specs', function() { it('is "failed"', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]); env.addReporter(reporter); env.fit('is focused', function() { env.expect(true).toBe(false); }); env.execute(null, function() { var e = reporter.jasmineDone.calls.argsFor(0)[0]; expect(e.overallStatus).toEqual('failed'); expect(e.incompleteReason).toBeUndefined(); done(); }); }); }); }); it('should report deprecation stack with an error object', function(done) { var exceptionFormatter = new jasmineUnderTest.ExceptionFormatter(), reporter = jasmine.createSpyObj('reporter', [ 'jasmineDone', 'suiteDone', 'specDone' ]), topLevelError, suiteLevelError, specLevelError; try { throw new Error('top level deprecation'); } catch (err) { topLevelError = err; } try { throw new Error('suite level deprecation'); } catch (err) { suiteLevelError = err; } try { throw new Error('spec level deprecation'); } catch (err) { specLevelError = err; } // prevent deprecation from being displayed spyOn(console, 'error'); env.addReporter(reporter); env.deprecated(topLevelError); env.describe('suite', function() { env.beforeAll(function() { env.deprecated(suiteLevelError); }); env.it('spec', function() { env.deprecated(specLevelError); }); }); env.execute(null, function() { var result = reporter.jasmineDone.calls.argsFor(0)[0]; expect(result.deprecationWarnings).toEqual([ jasmine.objectContaining({ message: topLevelError.message, stack: exceptionFormatter.stack(topLevelError, { omitMessage: true }) }) ]); expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'suite', deprecationWarnings: [ jasmine.objectContaining({ message: suiteLevelError.message, stack: exceptionFormatter.stack(suiteLevelError, { omitMessage: true }) }) ] }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'suite spec', deprecationWarnings: [ jasmine.objectContaining({ message: specLevelError.message, stack: exceptionFormatter.stack(specLevelError, { omitMessage: true }) }) ] }) ); done(); }); }); it('supports async matchers', function(done) { var specDone = jasmine.createSpy('specDone'), suiteDone = jasmine.createSpy('suiteDone'), jasmineDone = jasmine.createSpy('jasmineDone'); env.addReporter({ specDone: specDone, suiteDone: suiteDone, jasmineDone: jasmineDone }); function fail(innerDone) { var resolve; var p = new Promise(function(res, rej) { resolve = res; }); env .expectAsync(p) .toBeRejected() .then(innerDone); resolve(); } env.afterAll(fail); env.describe('a suite', function() { env.afterAll(fail); env.it('has an async failure', fail); }); env.execute(null, function() { var result = jasmineDone.calls.argsFor(0)[0]; expect(result.failedExpectations).toEqual([ jasmine.objectContaining({ message: 'Expected [object Promise] to be rejected.' }) ]); expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'has an async failure', failedExpectations: [ jasmine.objectContaining({ message: 'Expected [object Promise] to be rejected.' }) ] }) ); expect(suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'a suite', failedExpectations: [ jasmine.objectContaining({ message: 'Expected [object Promise] to be rejected.' }) ] }) ); done(); }); }); it('provides custom equality testers to async matchers', function(done) { if (jasmine.getEnv().skipBrowserFlake) { jasmine.getEnv().skipBrowserFlake(); } var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); env.it('has an async failure', function() { env.addCustomEqualityTester(function() { return true; }); var p = Promise.resolve('something'); return env.expectAsync(p).toBeResolvedTo('something else'); }); env.execute(null, function() { expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ description: 'has an async failure', failedExpectations: [] }) ); done(); }); }); it('includes useful stack frames in async matcher failures', function(done) { var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); env.it('has an async failure', function() { env.addCustomEqualityTester(function() { return true; }); var p = Promise.resolve(); return env.expectAsync(p).toBeRejected(); }); env.execute(null, function() { expect(specDone).toHaveBeenCalledWith( jasmine.objectContaining({ failedExpectations: [ jasmine.objectContaining({ stack: jasmine.stringMatching('EnvSpec.js') }) ] }) ); done(); }); }); it('reports an error when an async expectation occurs after the spec finishes', function(done) { var resolve, jasmineDone = jasmine.createSpy('jasmineDone'), promise = new Promise(function(res) { resolve = res; }); env.configure({ random: false }); env.describe('a suite', function() { env.it('does not wait', function() { // Note: we intentionally don't return the result of each expectAsync. // This causes the spec to finish before the expectations are evaluated. env.expectAsync(promise).toBeResolved(); env.expectAsync(promise).toBeResolvedTo('something else'); }); }); env.it('another spec', function(done) { // This is here to make sure that the async expectation evaluates // before the Jasmine under test finishes, especially on Safari 8 and 9. setTimeout(done, 10); }); env.addReporter({ specDone: function() { resolve(); }, jasmineDone: jasmineDone }); env.execute(null, function() { var result = jasmineDone.calls.argsFor(0)[0]; expect(result.failedExpectations).toEqual([ jasmine.objectContaining({ passed: false, globalErrorType: 'lateExpectation', message: 'Spec "a suite does not wait" ran a "toBeResolved" expectation ' + 'after it finished.\n' + '1. Did you forget to return or await the result of expectAsync?\n' + '2. Was done() invoked before an async operation completed?\n' + '3. Did an expectation follow a call to done()?', matcherName: 'toBeResolved' }), jasmine.objectContaining({ passed: false, globalErrorType: 'lateExpectation', message: 'Spec "a suite does not wait" ran a "toBeResolvedTo" expectation ' + 'after it finished.\n' + "Message: \"Expected a promise to be resolved to 'something else' " + 'but it was resolved to undefined."\n' + '1. Did you forget to return or await the result of expectAsync?\n' + '2. Was done() invoked before an async operation completed?\n' + '3. Did an expectation follow a call to done()?', matcherName: 'toBeResolvedTo' }) ]); done(); }); }); it('reports an error when an async expectation occurs after the suite finishes', function(done) { var resolve, jasmineDone = jasmine.createSpy('jasmineDone'), promise = new Promise(function(res) { resolve = res; }); env.configure({ random: false }); env.describe('a suite', function() { env.afterAll(function() { // Note: we intentionally don't return the result of expectAsync. // This causes the suite to finish before the expectations are evaluated. env.expectAsync(promise).toBeResolved(); }); env.it('is a spec', function() {}); }); env.it('another spec', function(done) { // This is here to make sure that the async expectation evaluates // before the Jasmine under test finishes, especially on Safari 8 and 9. setTimeout(done, 10); }); env.addReporter({ suiteDone: function() { resolve(); }, jasmineDone: jasmineDone }); env.execute(null, function() { var result = jasmineDone.calls.argsFor(0)[0]; expect(result.failedExpectations).toEqual([ jasmine.objectContaining({ passed: false, globalErrorType: 'lateExpectation', message: 'Suite "a suite" ran a "toBeResolved" expectation ' + 'after it finished.\n' + '1. Did you forget to return or await the result of expectAsync?\n' + '2. Was done() invoked before an async operation completed?\n' + '3. Did an expectation follow a call to done()?', matcherName: 'toBeResolved' }) ]); done(); }); }); it('supports asymmetric equality testers that take a matchersUtil', function(done) { var env = new jasmineUnderTest.Env(); env.it('spec using custom asymmetric equality tester', function() { var customEqualityFn = function(a, b) { if (a === 2 && b === 'two') { return true; } }; var arrayWithFirstElement = function(sample) { return { asymmetricMatch: function(actual, matchersUtil) { return matchersUtil.equals(sample, actual[0]); } }; }; env.addCustomEqualityTester(customEqualityFn); env.expect(['two']).toEqual(arrayWithFirstElement(2)); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); describe('The promise returned by #execute', function() { beforeEach(function() { this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL; }); afterEach(function() { jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval; }); it('is resolved after reporter events are dispatched', function() { var reporter = jasmine.createSpyObj('reporter', [ 'specDone', 'suiteDone', 'jasmineDone' ]); env.addReporter(reporter); env.describe('suite', function() { env.it('spec', function() {}); }); return env.execute(null).then(function() { expect(reporter.specDone).toHaveBeenCalled(); expect(reporter.suiteDone).toHaveBeenCalled(); expect(reporter.jasmineDone).toHaveBeenCalled(); }); }); it('is resolved after the stack is cleared', function(done) { var realClearStack = jasmineUnderTest.getClearStack( jasmineUnderTest.getGlobal() ), clearStackSpy = jasmine .createSpy('clearStack') .and.callFake(realClearStack); spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(clearStackSpy); // Create a new env that has the clearStack defined above env.cleanup_(); env = new jasmineUnderTest.Env(); env.describe('suite', function() { env.it('spec', function() {}); }); env.execute(null).then(function() { expect(clearStackSpy).toHaveBeenCalled(); // (many times) clearStackSpy.calls.reset(); setTimeout(function() { expect(clearStackSpy).not.toHaveBeenCalled(); done(); }); }); }); it('is resolved after QueueRunner timeouts are cleared', function() { var setTimeoutSpy = spyOn( jasmineUnderTest.getGlobal(), 'setTimeout' ).and.callThrough(); var clearTimeoutSpy = spyOn( jasmineUnderTest.getGlobal(), 'clearTimeout' ).and.callThrough(); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value env = new jasmineUnderTest.Env(); env.describe('suite', function() { env.it('spec', function() {}); }); return env.execute(null).then(function() { var timeoutIds = setTimeoutSpy.calls .all() .filter(function(call) { return call.args[1] === 123456; }) .map(function(call) { return call.returnValue; }); expect(timeoutIds.length).toBeGreaterThan(0); timeoutIds.forEach(function(timeoutId) { expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId); }); }); }); it('is resolved to the value of the jasmineDone event', async function() { env.describe('suite', function() { env.it('spec', function() { env.expect(true).toBe(false); }); }); let event; env.addReporter({ jasmineDone: e => (event = e) }); const result = await env.execute(); expect(event.overallStatus).toEqual('failed'); expect(result).toEqual(event); }); }); describe('The optional callback argument to #execute', function() { beforeEach(function() { this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL; }); afterEach(function() { jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval; }); it('is called after reporter events are dispatched', function(done) { var reporter = jasmine.createSpyObj('reporter', [ 'specDone', 'suiteDone', 'jasmineDone' ]); env.addReporter(reporter); env.describe('suite', function() { env.it('spec', function() {}); }); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalled(); expect(reporter.suiteDone).toHaveBeenCalled(); expect(reporter.jasmineDone).toHaveBeenCalled(); done(); }); }); it('is called after the stack is cleared', function(done) { var realClearStack = jasmineUnderTest.getClearStack( jasmineUnderTest.getGlobal() ), clearStackSpy = jasmine .createSpy('clearStack') .and.callFake(realClearStack); spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(clearStackSpy); // Create a new env that has the clearStack defined above env.cleanup_(); env = new jasmineUnderTest.Env(); env.describe('suite', function() { env.it('spec', function() {}); }); env.execute(null, function() { expect(clearStackSpy).toHaveBeenCalled(); // (many times) clearStackSpy.calls.reset(); setTimeout(function() { expect(clearStackSpy).not.toHaveBeenCalled(); done(); }); }); }); it('is called after QueueRunner timeouts are cleared', function(done) { var setTimeoutSpy = spyOn( jasmineUnderTest.getGlobal(), 'setTimeout' ).and.callThrough(); var clearTimeoutSpy = spyOn( jasmineUnderTest.getGlobal(), 'clearTimeout' ).and.callThrough(); jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value env = new jasmineUnderTest.Env(); env.describe('suite', function() { env.it('spec', function() {}); }); env.execute(null, function() { var timeoutIds = setTimeoutSpy.calls .all() .filter(function(call) { return call.args[1] === 123456; }) .map(function(call) { return call.returnValue; }); expect(timeoutIds.length).toBeGreaterThan(0); timeoutIds.forEach(function(timeoutId) { expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId); }); done(); }); }); }); it('sends debug logs to the reporter when the spec fails', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone']), startTime, endTime; env.addReporter(reporter); env.configure({ random: false }); env.it('fails', function() { startTime = new Date().getTime(); env.debugLog('message 1'); env.debugLog('message 2'); env.expect(1).toBe(2); endTime = new Date().getTime(); }); env.it('passes', function() { env.debugLog('message that should not be reported'); }); env.execute(null, function() { function numberInRange(min, max) { return { asymmetricMatch: function(compareTo) { return compareTo >= min && compareTo <= max; }, jasmineToString: function(pp) { return ''; } }; } var duration; expect(reporter.specDone).toHaveBeenCalledTimes(2); duration = reporter.specDone.calls.argsFor(0)[0].duration; expect(reporter.specDone.calls.argsFor(0)[0]).toEqual( jasmine.objectContaining({ debugLogs: [ { timestamp: numberInRange(0, duration), message: 'message 1' }, { timestamp: numberInRange(0, duration), message: 'message 2' } ] }) ); expect(reporter.specDone.calls.argsFor(1)[0].debugLogs).toBeFalsy(); done(); }); }); it('reports an error when debugLog is used when a spec is not running', function(done) { var reporter = jasmine.createSpyObj('reporter', ['suiteDone']); env.describe('a suite', function() { env.beforeAll(function() { env.debugLog('a message'); }); env.it('a spec', function() {}); }); env.addReporter(reporter); env.execute(null, function() { expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ failedExpectations: [ jasmine.objectContaining({ message: jasmine.stringContaining( "'debugLog' was called when there was no current spec" ) }) ] }) ); done(); }); }); it('uses custom equality testers in Spy#withArgs', async function() { env.it('a spec', function() { const createSpySpy = env.createSpy('via createSpy'); const spiedOn = { foo: function() {} }; env.spyOn(spiedOn, 'foo'); const spyObj = env.createSpyObj('spyObj', ['foo']); const spiedOnAllFuncs = { foo: function() {} }; env.spyOnAllFunctions(spiedOnAllFuncs); for (const spy of [ createSpySpy, spiedOn.foo, spyObj.foo, spiedOnAllFuncs.foo ]) { spy.and.returnValue('default strategy'); spy.withArgs(42).and.returnValue('custom strategy'); } env.addCustomEqualityTester(function(a, b) { if ((a === 'x' && b === 42) || (a === 42 && b === 'x')) { return true; } }); env .expect(createSpySpy('x')) .withContext('createSpy') .toEqual('custom strategy'); env .expect(spiedOn.foo('x')) .withContext('spyOn') .toEqual('custom strategy'); env .expect(spyObj.foo('x')) .withContext('createSpyObj') .toEqual('custom strategy'); env .expect(spiedOnAllFuncs.foo('x')) .withContext('spyOnAllFunctions') .toEqual('custom strategy'); }); let failedExpectations; env.addReporter({ specDone: r => (failedExpectations = r.failedExpectations) }); await env.execute(); expect(failedExpectations).toEqual([]); }); }); jasmine-4.0.0/spec/core/integration/MatchersSpec.js000066400000000000000000000520441416413636100222770ustar00rootroot00000000000000describe('Matchers (Integration)', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); function verifyPasses(expectations) { it('passes', function(done) { env.it('a spec', function() { expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); expect(result.passedExpectations.length) .withContext('Number of passed expectations') .toEqual(1); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(0); expect( result.failedExpectations[0] && result.failedExpectations[0].message ) .withContext('Failure message') .toBeUndefined(); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyFails(expectations) { it('fails', function(done) { env.it('a spec', function() { expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message) .withContext( 'Failed with a thrown error rather than a matcher failure' ) .not.toMatch(/^Error: /); expect(result.failedExpectations[0].message) .withContext( 'Failed with a thrown type error rather than a matcher failure' ) .not.toMatch(/^TypeError: /); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyFailsWithCustomObjectFormatters(config) { it('uses custom object formatters', function(done) { env.it('a spec', function() { env.addCustomObjectFormatter(config.formatter); config.expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message).toEqual( config.expectedMessage ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyPassesAsync(expectations) { it('passes', function(done) { env.it('a spec', function() { return expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('passed'); expect(result.passedExpectations.length) .withContext('Number of passed expectations') .toEqual(1); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(0); expect( result.failedExpectations[0] && result.failedExpectations[0].message ) .withContext('Failure message') .toBeUndefined(); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyFailsAsync(expectations) { it('fails', function(done) { env.it('a spec', function() { return expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message) .withContext( 'Failed with a thrown error rather than a matcher failure' ) .not.toMatch(/^Error: /); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } function verifyFailsWithCustomObjectFormattersAsync(config) { it('uses custom object formatters', function(done) { var env = new jasmineUnderTest.Env(); env.it('a spec', function() { env.addCustomObjectFormatter(config.formatter); return config.expectations(env); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message).toEqual( config.expectedMessage ); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); } describe('nothing', function() { verifyPasses(function(env) { env.expect().nothing(); }); }); describe('toBe', function() { verifyPasses(function(env) { env.expect(1).toBe(1); }); verifyFails(function(env) { env.expect(2).toBe(1); }); }); describe('toBeCloseTo', function() { verifyPasses(function(env) { env.expect(1.001).toBeCloseTo(1, 2); }); verifyFails(function(env) { env.expect(1.1).toBeCloseTo(1, 2); }); }); describe('toBeDefined', function() { verifyPasses(function(env) { env.expect({}).toBeDefined(); }); verifyFails(function(env) { env.expect(undefined).toBeDefined(); }); }); describe('toBeFalse', function() { verifyPasses(function(env) { env.expect(false).toBeFalse(); }); verifyFails(function(env) { env.expect(true).toBeFalse(); }); }); describe('toBeFalsy', function() { verifyPasses(function(env) { env.expect(false).toBeFalsy(); }); verifyFails(function(env) { env.expect(true).toBeFalsy(); }); }); describe('toBeGreaterThan', function() { verifyPasses(function(env) { env.expect(2).toBeGreaterThan(1); }); verifyFails(function(env) { env.expect(1).toBeGreaterThan(2); }); }); describe('toBeGreaterThanOrEqual', function() { verifyPasses(function(env) { env.expect(2).toBeGreaterThanOrEqual(1); }); verifyFails(function(env) { env.expect(1).toBeGreaterThanOrEqual(2); }); }); describe('toBeInstanceOf', function() { function Ctor() {} verifyPasses(function(env) { env.expect(new Ctor()).toBeInstanceOf(Ctor); }); verifyFails(function(env) { env.expect({}).toBeInstanceOf(Ctor); }); }); describe('toBeLessThan', function() { verifyPasses(function(env) { env.expect(1).toBeLessThan(2); }); verifyFails(function(env) { env.expect(2).toBeLessThan(1); }); }); describe('toBeLessThanOrEqual', function() { verifyPasses(function(env) { env.expect(1).toBeLessThanOrEqual(2); }); verifyFails(function(env) { env.expect(2).toBeLessThanOrEqual(1); }); }); describe('toBeNaN', function() { verifyPasses(function(env) { env.expect(NaN).toBeNaN(); }); verifyFails(function(env) { env.expect(2).toBeNaN(); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { env.expect(1).toBeNaN(); }, expectedMessage: 'Expected |1| to be NaN.' }); }); describe('toBeNegativeInfinity', function() { verifyPasses(function(env) { env.expect(Number.NEGATIVE_INFINITY).toBeNegativeInfinity(); }); verifyFails(function(env) { env.expect(2).toBeNegativeInfinity(); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { env.expect(1).toBeNegativeInfinity(); }, expectedMessage: 'Expected |1| to be -Infinity.' }); }); describe('toBeNull', function() { verifyPasses(function(env) { env.expect(null).toBeNull(); }); verifyFails(function(env) { env.expect(2).toBeNull(); }); }); describe('toBePositiveInfinity', function() { verifyPasses(function(env) { env.expect(Number.POSITIVE_INFINITY).toBePositiveInfinity(); }); verifyFails(function(env) { env.expect(2).toBePositiveInfinity(); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { env.expect(1).toBePositiveInfinity(); }, expectedMessage: 'Expected |1| to be Infinity.' }); }); describe('toBeResolved', function() { verifyPassesAsync(function(env) { return env.expectAsync(Promise.resolve()).toBeResolved(); }); verifyFailsAsync(function(env) { return env.expectAsync(Promise.reject()).toBeResolved(); }); }); describe('toBeResolvedTo', function() { verifyPassesAsync(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); return env.expectAsync(Promise.resolve('5')).toBeResolvedTo(5); }); verifyFailsAsync(function(env) { return env.expectAsync(Promise.resolve('foo')).toBeResolvedTo('bar'); }); verifyFailsWithCustomObjectFormattersAsync({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { return env.expectAsync(Promise.resolve('x')).toBeResolvedTo('y'); }, expectedMessage: 'Expected a promise to be resolved to |y| ' + 'but it was resolved to |x|.' }); }); describe('toBeRejected', function() { verifyPassesAsync(function(env) { return env.expectAsync(Promise.reject('nope')).toBeRejected(); }); verifyFailsAsync(function(env) { return env.expectAsync(Promise.resolve()).toBeRejected(); }); }); describe('toBeRejectedWith', function() { verifyPassesAsync(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); return env.expectAsync(Promise.reject('5')).toBeRejectedWith(5); }); verifyFailsAsync(function(env) { return env.expectAsync(Promise.resolve()).toBeRejectedWith('nope'); }); verifyFailsWithCustomObjectFormattersAsync({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { return env.expectAsync(Promise.reject('x')).toBeRejectedWith('y'); }, expectedMessage: 'Expected a promise to be rejected with |y| ' + 'but it was rejected with |x|.' }); }); describe('toBeRejectedWithError', function() { verifyPassesAsync(function(env) { return env .expectAsync(Promise.reject(new Error())) .toBeRejectedWithError(Error); }); verifyFailsAsync(function(env) { return env.expectAsync(Promise.resolve()).toBeRejectedWithError(Error); }); verifyFailsWithCustomObjectFormattersAsync({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { return env .expectAsync(Promise.reject('foo')) .toBeRejectedWithError('foo'); }, expectedMessage: 'Expected a promise to be rejected with Error: |foo| ' + 'but it was rejected with |foo|.' }); }); describe('toBeTrue', function() { verifyPasses(function(env) { env.expect(true).toBeTrue(); }); verifyFails(function(env) { env.expect(false).toBeTrue(); }); }); describe('toBeTruthy', function() { verifyPasses(function(env) { env.expect(true).toBeTruthy(); }); verifyFails(function(env) { env.expect(false).toBeTruthy(); }); }); describe('toBeUndefined', function() { verifyPasses(function(env) { env.expect(undefined).toBeUndefined(); }); verifyFails(function(env) { env.expect(1).toBeUndefined(); }); }); describe('toContain', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(['1', '2', '3']).toContain(2); }); verifyFails(function(env) { env.expect('bar').toContain('oo'); }); }); describe('toEqual', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(5).toEqual('5'); }); verifyFails(function(env) { env.expect('a').toEqual('b'); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { if (val === 5) { return 'five'; } else if (val === 4) { return 'four'; } }, expectations: function(env) { env.expect([{ foo: 4 }]).toEqual([{ foo: 5 }]); }, expectedMessage: 'Expected $[0].foo = four to equal five.' }); }); describe('toHaveSize', function() { verifyPasses(function(env) { env.expect(['a', 'b']).toHaveSize(2); }); verifyFails(function(env) { env.expect(['a', 'b']).toHaveSize(1); }); }); describe('toHaveBeenCalled', function() { verifyPasses(function(env) { var spy = env.createSpy('spy'); spy(); env.expect(spy).toHaveBeenCalled(); }); verifyFails(function(env) { var spy = env.createSpy('spy'); env.expect(spy).toHaveBeenCalled(); }); }); describe('toHaveBeenCalledBefore', function() { verifyPasses(function(env) { var a = env.createSpy('a'), b = env.createSpy('b'); a(); b(); env.expect(a).toHaveBeenCalledBefore(b); }); verifyFails(function(env) { var a = env.createSpy('a'), b = env.createSpy('b'); b(); a(); env.expect(a).toHaveBeenCalledBefore(b); }); }); describe('toHaveBeenCalledTimes', function() { verifyPasses(function(env) { var spy = env.createSpy('spy'); spy(); env.expect(spy).toHaveBeenCalledTimes(1); }); verifyFails(function(env) { var spy = env.createSpy('spy'); env.expect(spy).toHaveBeenCalledTimes(1); }); }); describe('toHaveBeenCalledWith', function() { verifyPasses(function(env) { var spy = env.createSpy(); spy('5'); env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(spy).toHaveBeenCalledWith(5); }); verifyFails(function(env) { var spy = env.createSpy(); env.expect(spy).toHaveBeenCalledWith('foo'); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { var spy = env.createSpy('foo'); env.expect(spy).toHaveBeenCalledWith('x'); }, expectedMessage: 'Expected spy foo to have been called with:\n' + ' |x|\n' + 'but it was never called.' }); }); describe('toHaveBeenCalledOnceWith', function() { verifyPasses(function(env) { var spy = env.createSpy(); spy('5', 3); env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env.expect(spy).toHaveBeenCalledOnceWith(5, 3); }); verifyFails(function(env) { var spy = env.createSpy(); env.expect(spy).toHaveBeenCalledOnceWith(5, 3); }); }); describe('toHaveClass', function() { beforeEach(function() { this.domHelpers = jasmine.getEnv().domHelpers(); }); verifyPasses(function(env) { var domHelpers = jasmine.getEnv().domHelpers(); var el = domHelpers.createElementWithClassName('foo'); env.expect(el).toHaveClass('foo'); }); verifyFails(function(env) { var domHelpers = jasmine.getEnv().domHelpers(); var el = domHelpers.createElementWithClassName('foo'); env.expect(el).toHaveClass('bar'); }); }); describe('toMatch', function() { verifyPasses(function(env) { env.expect('foo').toMatch(/oo$/); }); verifyFails(function(env) { env.expect('bar').toMatch(/oo$/); }); }); describe('toThrow', function() { verifyPasses(function(env) { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); env .expect(function() { throw '5'; }) .toThrow(5); }); verifyFails(function(env) { env.expect(function() {}).toThrow(); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { var spy = env.createSpy('foo'); env .expect(function() { throw 'x'; }) .not.toThrow(); }, expectedMessage: 'Expected function not to throw, but it threw |x|.' }); }); describe('toThrowError', function() { verifyPasses(function(env) { env .expect(function() { throw new Error(); }) .toThrowError(); }); verifyFails(function(env) { env.expect(function() {}).toThrowError(); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { var spy = env.createSpy('foo'); env .expect(function() { throw 'x'; }) .toThrowError(); }, expectedMessage: 'Expected function to throw an Error, but it threw |x|.' }); }); describe('toThrowMatching', function() { function throws() { throw new Error('nope'); } verifyPasses(function(env) { env.expect(throws).toThrowMatching(function() { return true; }); }); verifyFails(function(env) { env.expect(throws).toThrowMatching(function() { return false; }); }); verifyFailsWithCustomObjectFormatters({ formatter: function(val) { return '|' + val + '|'; }, expectations: function(env) { var spy = env.createSpy('foo'); env .expect(function() { throw new Error('nope'); }) .toThrowMatching(function() { return false; }); }, expectedMessage: 'Expected function to throw an exception matching ' + 'a predicate, but it threw Error with message |nope|.' }); }); describe('When an async matcher is used with .already()', function() { it('propagates the matcher result when the promise is resolved', function(done) { env.it('a spec', function() { return env.expectAsync(Promise.resolve()).already.toBeRejected(); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message).toEqual( 'Expected [object Promise] to be rejected.' ); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('propagates the matcher result when the promise is rejected', function(done) { env.it('a spec', function() { return env .expectAsync(Promise.reject(new Error('nope'))) .already.toBeResolved(); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message).toEqual( 'Expected a promise to be resolved but it was ' + 'rejected with Error: nope.' ); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); it('fails when the promise is pending', function(done) { var promise = new Promise(function() {}); env.it('a spec', function() { return env.expectAsync(promise).already.toBeResolved(); }); var specExpectations = function(result) { expect(result.status).toEqual('failed'); expect(result.failedExpectations.length) .withContext('Number of failed expectations') .toEqual(1); expect(result.failedExpectations[0].message).toEqual( 'Expected a promise to be settled ' + '(via expectAsync(...).already) but it was pending.' ); expect(result.failedExpectations[0].matcherName) .withContext('Matcher name') .not.toEqual(''); }; env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); }); }); jasmine-4.0.0/spec/core/integration/SpecRunningSpec.js000066400000000000000000001210131416413636100227550ustar00rootroot00000000000000describe('spec running', function() { var env; beforeEach(function() { jasmine.getEnv().registerIntegrationMatchers(); env = new jasmineUnderTest.Env(); env.configure({ random: false }); }); afterEach(function() { env.cleanup_(); }); it('should assign spec ids sequentially', function() { var it0, it1, it2, it3, it4; env.describe('test suite', function() { it0 = env.it('spec 0', function() {}); it1 = env.it('spec 1', function() {}); it2 = env.xit('spec 2', function() {}); it3 = env.it('spec 3', function() {}); }); env.describe('test suite 2', function() { it4 = env.it('spec 4', function() {}); }); expect(it0.id).toEqual('spec0'); expect(it1.id).toEqual('spec1'); expect(it2.id).toEqual('spec2'); expect(it3.id).toEqual('spec3'); expect(it4.id).toEqual('spec4'); }); it('nested suites', function(done) { var foo = 0; var bar = 0; var baz = 0; var quux = 0; var nested = env.describe('suite', function() { env.describe('nested', function() { env.it('should run nested suites', function() { foo++; }); env.it('should run nested suites', function() { bar++; }); }); env.describe('nested 2', function() { env.it('should run suites following nested suites', function() { baz++; }); }); env.it('should run tests following nested suites', function() { quux++; }); }); expect(foo).toEqual(0); expect(bar).toEqual(0); expect(baz).toEqual(0); expect(quux).toEqual(0); env.execute(null, function() { expect(foo).toEqual(1); expect(bar).toEqual(1); expect(baz).toEqual(1); expect(quux).toEqual(1); done(); }); }); it('should permit nested describes', function(done) { var actions = []; env.beforeEach(function() { actions.push('topSuite beforeEach'); }); env.afterEach(function() { actions.push('topSuite afterEach'); }); env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.it('does it 1', function() { actions.push('outer it 1'); }); env.describe('Inner 1', function() { env.beforeEach(function() { actions.push('inner 1 beforeEach'); }); env.afterEach(function() { actions.push('inner 1 afterEach'); }); env.it('does it 2', function() { actions.push('inner 1 it'); }); }); env.it('does it 3', function() { actions.push('outer it 2'); }); env.describe('Inner 2', function() { env.beforeEach(function() { actions.push('inner 2 beforeEach'); }); env.afterEach(function() { actions.push('inner 2 afterEach'); }); env.it('does it 2', function() { actions.push('inner 2 it'); }); }); }); env.execute(null, function() { var expected = [ 'topSuite beforeEach', 'outer beforeEach', 'outer it 1', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'inner 1 beforeEach', 'inner 1 it', 'inner 1 afterEach', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'outer it 2', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'inner 2 beforeEach', 'inner 2 it', 'inner 2 afterEach', 'outer afterEach', 'topSuite afterEach' ]; expect(actions).toEqual(expected); done(); }); }); it('should run multiple befores and afters ordered so functions declared later are treated as more specific', function(done) { var actions = []; env.beforeAll(function() { actions.push('runner beforeAll1'); }); env.afterAll(function() { actions.push('runner afterAll1'); }); env.beforeAll(function() { actions.push('runner beforeAll2'); }); env.afterAll(function() { actions.push('runner afterAll2'); }); env.beforeEach(function() { actions.push('runner beforeEach1'); }); env.afterEach(function() { actions.push('runner afterEach1'); }); env.beforeEach(function() { actions.push('runner beforeEach2'); }); env.afterEach(function() { actions.push('runner afterEach2'); }); env.describe('Something', function() { env.beforeEach(function() { actions.push('beforeEach1'); }); env.afterEach(function() { actions.push('afterEach1'); }); env.beforeEach(function() { actions.push('beforeEach2'); }); env.afterEach(function() { actions.push('afterEach2'); }); env.it('does it 1', function() { actions.push('outer it 1'); }); }); env.execute(null, function() { var expected = [ 'runner beforeAll1', 'runner beforeAll2', 'runner beforeEach1', 'runner beforeEach2', 'beforeEach1', 'beforeEach2', 'outer it 1', 'afterEach2', 'afterEach1', 'runner afterEach2', 'runner afterEach1', 'runner afterAll2', 'runner afterAll1' ]; expect(actions).toEqual(expected); done(); }); }); it('should run beforeAlls before beforeEachs and afterAlls after afterEachs', function(done) { var actions = []; env.beforeAll(function() { actions.push('runner beforeAll'); }); env.afterAll(function() { actions.push('runner afterAll'); }); env.beforeEach(function() { actions.push('runner beforeEach'); }); env.afterEach(function() { actions.push('runner afterEach'); }); env.describe('Something', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.beforeAll(function() { actions.push('inner beforeAll'); }); env.afterAll(function() { actions.push('inner afterAll'); }); env.it('does something or other', function() { actions.push('it'); }); }); env.execute(null, function() { var expected = [ 'runner beforeAll', 'inner beforeAll', 'runner beforeEach', 'inner beforeEach', 'it', 'inner afterEach', 'runner afterEach', 'inner afterAll', 'runner afterAll' ]; expect(actions).toEqual(expected); done(); }); }); it('should run beforeAlls and afterAlls in the order declared when runnablesToRun is provided', function(done) { var actions = [], spec, spec2; env.beforeAll(function() { actions.push('runner beforeAll'); }); env.afterAll(function() { actions.push('runner afterAll'); }); env.beforeEach(function() { actions.push('runner beforeEach'); }); env.afterEach(function() { actions.push('runner afterEach'); }); env.describe('Something', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.beforeAll(function() { actions.push('inner beforeAll'); }); env.afterAll(function() { actions.push('inner afterAll'); }); spec = env.it('does something', function() { actions.push('it'); }); spec2 = env.it('does something or other', function() { actions.push('it2'); }); }); env.execute([spec2.id, spec.id], function() { var expected = [ 'runner beforeAll', 'inner beforeAll', 'runner beforeEach', 'inner beforeEach', 'it2', 'inner afterEach', 'runner afterEach', 'runner beforeEach', 'inner beforeEach', 'it', 'inner afterEach', 'runner afterEach', 'inner afterAll', 'runner afterAll' ]; expect(actions).toEqual(expected); done(); }); }); it('only runs *Alls once in a focused suite', function(done) { var actions = []; env.fdescribe('Suite', function() { env.beforeAll(function() { actions.push('beforeAll'); }); env.it('should run beforeAll once', function() { actions.push('spec'); }); env.afterAll(function() { actions.push('afterAll'); }); }); env.execute(null, function() { expect(actions).toEqual(['beforeAll', 'spec', 'afterAll']); done(); }); }); describe('focused runnables', function() { it('runs the relevant alls and eachs for each runnable', function(done) { var actions = []; env.beforeAll(function() { actions.push('beforeAll'); }); env.afterAll(function() { actions.push('afterAll'); }); env.beforeEach(function() { actions.push('beforeEach'); }); env.afterEach(function() { actions.push('afterEach'); }); env.fdescribe('a focused suite', function() { env.it('is run', function() { actions.push('spec in fdescribe'); }); }); env.describe('an unfocused suite', function() { env.fit('has a focused spec', function() { actions.push('focused spec'); }); }); env.execute(null, function() { var expected = [ 'beforeAll', 'beforeEach', 'spec in fdescribe', 'afterEach', 'beforeEach', 'focused spec', 'afterEach', 'afterAll' ]; expect(actions).toEqual(expected); done(); }); }); it('focused specs in focused suites cause non-focused siblings to not run', function(done) { var actions = []; env.fdescribe('focused suite', function() { env.it('unfocused spec', function() { actions.push('unfocused spec'); }); env.fit('focused spec', function() { actions.push('focused spec'); }); }); env.execute(null, function() { var expected = ['focused spec']; expect(actions).toEqual(expected); done(); }); }); it('focused suites in focused suites cause non-focused siblings to not run', function(done) { var actions = []; env.fdescribe('focused suite', function() { env.it('unfocused spec', function() { actions.push('unfocused spec'); }); env.fdescribe('inner focused suite', function() { env.it('inner spec', function() { actions.push('inner spec'); }); }); }); env.execute(null, function() { var expected = ['inner spec']; expect(actions).toEqual(expected); done(); }); }); it('focused runnables unfocus ancestor focused suites', function(done) { var actions = []; env.fdescribe('focused suite', function() { env.it('unfocused spec', function() { actions.push('unfocused spec'); }); env.describe('inner focused suite', function() { env.fit('focused spec', function() { actions.push('focused spec'); }); }); }); env.execute(null, function() { var expected = ['focused spec']; expect(actions).toEqual(expected); done(); }); }); }); it("shouldn't run disabled suites", function(done) { var specInADisabledSuite = jasmine.createSpy('specInADisabledSuite'), suite = env.describe('A Suite', function() { env.xdescribe('with a disabled suite', function() { env.it('spec inside a disabled suite', specInADisabledSuite); }); }); env.execute(null, function() { expect(specInADisabledSuite).not.toHaveBeenCalled(); done(); }); }); it("shouldn't run before/after functions in disabled suites", function(done) { var shouldNotRun = jasmine.createSpy('shouldNotRun'), suite = env.xdescribe('A disabled Suite', function() { // None of the before/after functions should run. env.beforeAll(shouldNotRun); env.beforeEach(shouldNotRun); env.afterEach(shouldNotRun); env.afterAll(shouldNotRun); env.it('spec inside a disabled suite', shouldNotRun); }); env.execute(null, function() { expect(shouldNotRun).not.toHaveBeenCalled(); done(); }); }); it('should allow top level suites to be disabled', function(done) { var specInADisabledSuite = jasmine.createSpy('specInADisabledSuite'), otherSpec = jasmine.createSpy('otherSpec'); env.xdescribe('A disabled suite', function() { env.it('spec inside a disabled suite', specInADisabledSuite); }); env.describe('Another suite', function() { env.it('another spec', otherSpec); }); env.execute(null, function() { expect(specInADisabledSuite).not.toHaveBeenCalled(); expect(otherSpec).toHaveBeenCalled(); done(); }); }); it('should set all pending specs to pending when a suite is run', function(done) { var pendingSpec, suite = env.describe('default current suite', function() { pendingSpec = env.it('I am a pending spec'); }), reporter = jasmine.createSpyObj('reporter', ['specDone']); env.addReporter(reporter); env.execute(null, function() { expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ status: 'pending' }) ); done(); }); }); it('should recover gracefully when there are errors in describe functions', function(done) { var specs = [], reporter = jasmine.createSpyObj(['specDone', 'suiteDone']); reporter.specDone.and.callFake(function(result) { specs.push(result.fullName); }); expect(function() { env.describe('outer1', function() { env.describe('inner1', function() { env.it('should thingy', function() { this.expect(true).toEqual(true); }); throw new Error('inner error'); }); env.describe('inner2', function() { env.it('should other thingy', function() { this.expect(true).toEqual(true); }); }); throw new Error('outer error'); }); }).not.toThrow(); env.describe('outer2', function() { env.it('should xxx', function() { this.expect(true).toEqual(true); }); }); env.addReporter(reporter); env.execute(null, function() { expect(specs).toEqual([ 'outer1 inner1 should thingy', 'outer1 inner2 should other thingy', 'outer2 should xxx' ]); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable( 'outer1 inner1', [/inner error/] ); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('outer1', [ /outer error/ ]); done(); }); }); it('re-enters suites that have no *Alls', function(done) { var actions = [], spec1, spec2, spec3; env.describe('top', function() { spec1 = env.it('spec1', function() { actions.push('spec1'); }); spec2 = env.it('spec2', function() { actions.push('spec2'); }); }); spec3 = env.it('spec3', function() { actions.push('spec3'); }); env.execute([spec2.id, spec3.id, spec1.id], function() { expect(actions).toEqual(['spec2', 'spec3', 'spec1']); done(); }); }); it('refuses to re-enter suites with a beforeAll', function() { var actions = [], spec1, spec2, spec3; env.describe('top', function() { env.beforeAll(function() {}); spec1 = env.it('spec1', function() { actions.push('spec1'); }); spec2 = env.it('spec2', function() { actions.push('spec2'); }); }); spec3 = env.it('spec3', function() { actions.push('spec3'); }); expect(function() { env.execute([spec2.id, spec3.id, spec1.id]); }).toThrowError(/beforeAll/); expect(actions).toEqual([]); }); it('refuses to re-enter suites with a afterAll', function() { var actions = [], spec1, spec2, spec3; env.describe('top', function() { env.afterAll(function() {}); spec1 = env.it('spec1', function() { actions.push('spec1'); }); spec2 = env.it('spec2', function() { actions.push('spec2'); }); }); spec3 = env.it('spec3', function() { actions.push('spec3'); }); expect(function() { env.execute([spec2.id, spec3.id, spec1.id]); }).toThrowError(/afterAll/); expect(actions).toEqual([]); }); it('should run the tests in a consistent order when a seed is supplied', function(done) { var actions = []; env.configure({ random: true, seed: '123456' }); env.beforeEach(function() { actions.push('topSuite beforeEach'); }); env.afterEach(function() { actions.push('topSuite afterEach'); }); env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.it('does it 1', function() { actions.push('outer it 1'); }); env.describe('Inner 1', function() { env.beforeEach(function() { actions.push('inner 1 beforeEach'); }); env.afterEach(function() { actions.push('inner 1 afterEach'); }); env.it('does it 2', function() { actions.push('inner 1 it'); }); }); env.it('does it 3', function() { actions.push('outer it 2'); }); env.describe('Inner 2', function() { env.beforeEach(function() { actions.push('inner 2 beforeEach'); }); env.afterEach(function() { actions.push('inner 2 afterEach'); }); env.it('does it 2', function() { actions.push('inner 2 it'); }); }); }); env.execute(null, function() { var expected = [ 'topSuite beforeEach', 'outer beforeEach', 'outer it 2', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'inner 2 beforeEach', 'inner 2 it', 'inner 2 afterEach', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'inner 1 beforeEach', 'inner 1 it', 'inner 1 afterEach', 'outer afterEach', 'topSuite afterEach', 'topSuite beforeEach', 'outer beforeEach', 'outer it 1', 'outer afterEach', 'topSuite afterEach' ]; expect(actions).toEqual(expected); done(); }); }); function hasStandardErrorHandlingBehavior() { it('skips to cleanup functions after a thrown error', async function() { const actions = []; env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); throw new Error('error'); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.describe('Inner', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.it('does it', function() { actions.push('inner it'); }); }); }); await env.execute(); expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after a rejected promise', async function() { const actions = []; env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); return Promise.reject(new Error('error')); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.describe('Inner', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.it('does it', function() { actions.push('inner it'); }); }); }); await env.execute(); expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after done.fail is called', async function() { const actions = []; env.describe('Something', function() { env.beforeEach(function(done) { actions.push('beforeEach'); done.fail('error'); }); env.afterEach(function() { actions.push('afterEach'); }); env.it('does it', function() { actions.push('it'); }); }); await env.execute(); expect(actions).toEqual(['beforeEach', 'afterEach']); }); it('skips to cleanup functions when an async function times out', async function() { const actions = []; env.describe('Something', function() { env.beforeEach(function(innerDone) { actions.push('beforeEach'); }, 1); env.afterEach(function() { actions.push('afterEach'); }); env.it('does it', function() { actions.push('it'); }); }); await env.execute(); expect(actions).toEqual(['beforeEach', 'afterEach']); }); it('skips to cleanup functions after pending() is called', async function() { const actions = []; env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); pending(); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.describe('Inner', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.it('does it', function() { actions.push('inner it'); }); }); }); await env.execute(); expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('runs all reporter callbacks even if one fails', async function() { const laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); env.it('a spec', function() {}); env.addReporter({ specDone: function() { throw new Error('nope'); } }); env.addReporter(laterReporter); await env.execute(); expect(laterReporter.specDone).toHaveBeenCalled(); }); it('skips cleanup functions that are defined in child suites when a beforeEach errors', async function() { const parentAfterEachFn = jasmine.createSpy('parentAfterEachFn'); const childAfterEachFn = jasmine.createSpy('childAfterEachFn'); env.describe('parent suite', function() { env.beforeEach(function() { throw new Error('nope'); }); env.afterEach(parentAfterEachFn); env.describe('child suite', function() { env.it('a spec', function() {}); env.afterEach(childAfterEachFn); }); }); await env.execute(); expect(parentAfterEachFn).toHaveBeenCalled(); expect(childAfterEachFn).not.toHaveBeenCalled(); }); } describe('When stopSpecOnExpectationFailure is true', function() { beforeEach(function() { env.configure({ stopSpecOnExpectationFailure: true }); }); hasStandardErrorHandlingBehavior(); it('skips to cleanup functions after an expectation failure', async function() { var actions = []; env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); env.expect(1).toBe(2); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.describe('Inner', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.it('does it', function() { actions.push('inner it'); }); }); }); await env.execute(); expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); }); describe('When stopSpecOnExpectationFailure is false', function() { beforeEach(function() { env.configure({ stopSpecOnExpectationFailure: false }); }); hasStandardErrorHandlingBehavior(); it('does not skip anything after an expectation failure', async function() { var actions = []; env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); env.expect(1).toBe(2); }); env.afterEach(function() { actions.push('outer afterEach'); }); env.describe('Inner', function() { env.beforeEach(function() { actions.push('inner beforeEach'); }); env.afterEach(function() { actions.push('inner afterEach'); }); env.it('does it', function() { actions.push('inner it'); }); }); }); await env.execute(); expect(actions).toEqual([ 'outer beforeEach', 'inner beforeEach', 'inner it', 'inner afterEach', 'outer afterEach' ]); }); }); describe('When a top-level beforeAll function fails', function() { it('skips and reports contained specs', async function() { const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); const outerAfterEach = jasmine.createSpy('outerAfterEach'); const nestedAfterEach = jasmine.createSpy('nestedAfterEach'); const outerIt = jasmine.createSpy('outerIt'); const nestedIt = jasmine.createSpy('nestedIt'); const nestedBeforeAll = jasmine.createSpy('nestedBeforeAll'); env.beforeAll(function() { throw new Error('nope'); }); env.beforeEach(outerBeforeEach); env.it('a spec', outerIt); env.describe('a nested suite', function() { env.beforeAll(nestedBeforeAll); env.beforeEach(nestedBeforeEach); env.it('a nested spec', nestedIt); env.afterEach(nestedAfterEach); }); env.afterEach(outerAfterEach); const reporter = jasmine.createSpyObj('reporter', [ 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); await env.execute(); expect(outerBeforeEach).not.toHaveBeenCalled(); expect(outerIt).not.toHaveBeenCalled(); expect(nestedBeforeAll).not.toHaveBeenCalled(); expect(nestedBeforeEach).not.toHaveBeenCalled(); expect(nestedIt).not.toHaveBeenCalled(); expect(nestedAfterEach).not.toHaveBeenCalled(); expect(outerAfterEach).not.toHaveBeenCalled(); expect(reporter.suiteStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a nested suite' }) ); // The child suite should be reported as passed, for consistency with // suites that contain failing specs but no suite-level errors. expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a nested suite', status: 'passed', failedExpectations: [] }) ); expect(reporter.specStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a spec' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a spec', status: 'failed', failedExpectations: [ jasmine.objectContaining({ passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }) ] }) ); expect(reporter.specStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a nested suite a nested spec' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a nested suite a nested spec', status: 'failed', failedExpectations: [ jasmine.objectContaining({ passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }) ] }) ); }); }); describe('When a suite beforeAll function fails', function() { it('skips and reports contained specs', async function() { const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); const outerAfterEach = jasmine.createSpy('outerAfterEach'); const nestedAfterEach = jasmine.createSpy('nestedAfterEach'); const outerIt = jasmine.createSpy('outerIt'); const nestedIt = jasmine.createSpy('nestedIt'); const nestedBeforeAll = jasmine.createSpy('nestedBeforeAll'); env.describe('a suite', function() { env.beforeAll(function() { throw new Error('nope'); }); env.beforeEach(outerBeforeEach); env.it('a spec', outerIt); env.describe('a nested suite', function() { env.beforeAll(nestedBeforeAll); env.beforeEach(nestedBeforeEach); env.it('a nested spec', nestedIt); env.afterEach(nestedAfterEach); }); env.afterEach(outerAfterEach); }); const reporter = jasmine.createSpyObj('reporter', [ 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); env.addReporter(reporter); await env.execute(); expect(outerBeforeEach).not.toHaveBeenCalled(); expect(outerIt).not.toHaveBeenCalled(); expect(nestedBeforeAll).not.toHaveBeenCalled(); expect(nestedBeforeEach).not.toHaveBeenCalled(); expect(nestedIt).not.toHaveBeenCalled(); expect(nestedAfterEach).not.toHaveBeenCalled(); expect(outerAfterEach).not.toHaveBeenCalled(); expect(reporter.suiteStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a nested suite' }) ); // The child suite should be reported as passed, for consistency with // suites that contain failing specs but no suite-level errors. expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a nested suite', status: 'passed', failedExpectations: [] }) ); expect(reporter.specStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a spec' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a spec', status: 'failed', failedExpectations: [ jasmine.objectContaining({ passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }) ] }) ); expect(reporter.specStarted).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a nested suite a nested spec' }) ); expect(reporter.specDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a nested suite a nested spec', status: 'failed', failedExpectations: [ jasmine.objectContaining({ passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }) ] }) ); }); it('runs afterAll functions in the current suite and outer scopes', async function() { const outerAfterAll = jasmine.createSpy('outerAfterAll'); const nestedAfterAll = jasmine.createSpy('nestedAfterAll'); const secondNestedAfterAll = jasmine.createSpy('secondNestedAfterAll'); env.describe('a nested suite', function() { env.beforeAll(function() { throw new Error('nope'); }); env.describe('more nesting', function() { env.it('a nested spec', function() {}); env.afterAll(secondNestedAfterAll); }); env.afterAll(nestedAfterAll); }); env.afterAll(outerAfterAll); await env.execute(); expect(secondNestedAfterAll).not.toHaveBeenCalled(); expect(nestedAfterAll).toHaveBeenCalled(); expect(outerAfterAll).toHaveBeenCalled(); }); }); describe('when stopOnSpecFailure is on', function() { it('does not run further specs when one fails', function(done) { var actions = [], config; env.describe('wrapper', function() { env.it('fails', function() { actions.push('fails'); env.expect(1).toBe(2); }); }); env.describe('holder', function() { env.it('does not run', function() { actions.push('does not run'); }); }); env.configure({ random: false }); env.configure({ stopOnSpecFailure: true }); env.execute(null, function() { expect(actions).toEqual(['fails']); done(); }); }); it('runs afterAll functions', async function() { const actions = []; env.describe('outer suite', function() { env.describe('inner suite', function() { env.it('fails', function() { actions.push('fails'); env.expect(1).toBe(2); }); env.afterAll(function() { actions.push('inner afterAll'); }); }); env.afterAll(function() { actions.push('outer afterAll'); }); }); env.afterAll(function() { actions.push('top afterAll'); }); env.configure({ stopOnSpecFailure: true }); await env.execute(); expect(actions).toEqual([ 'fails', 'inner afterAll', 'outer afterAll', 'top afterAll' ]); }); }); describe('run multiple times', function() { beforeEach(function() { env.configure({ autoCleanClosures: false, random: false }); }); it('should be able to run multiple times', function(done) { var actions = []; env.describe('Suite', function() { env.it('spec1', function() { actions.push('spec1'); }); env.describe('inner suite', function() { env.it('spec2', function() { actions.push('spec2'); }); }); }); env.execute(null, function() { expect(actions).toEqual(['spec1', 'spec2']); env.execute(null, function() { expect(actions).toEqual(['spec1', 'spec2', 'spec1', 'spec2']); done(); }); }); }); it('should reset results between runs', function(done) { var specResults = {}; var suiteResults = {}; var firstExecution = true; env.addReporter({ specDone: function(spec) { specResults[spec.description] = spec.status; }, suiteDone: function(suite) { suiteResults[suite.description] = suite.status; }, jasmineDone: function() { firstExecution = false; } }); env.describe('suite0', function() { env.it('spec1', function() { if (firstExecution) { env.expect(1).toBe(2); } }); env.describe('suite1', function() { env.it('spec2', function() { if (firstExecution) { env.pending(); } }); env.xit('spec3', function() {}); // Always pending }); env.describe('suite2', function() { env.it('spec4', function() { if (firstExecution) { throw new Error('spec 3 fails'); } }); }); env.describe('suite3', function() { env.beforeEach(function() { throw new Error('suite 3 fails'); }); env.it('spec5', function() {}); }); env.xdescribe('suite4', function() { // Always pending env.it('spec6', function() {}); }); env.describe('suite5', function() { env.it('spec7'); }); }); env.execute(null, function() { expect(specResults).toEqual({ spec1: 'failed', spec2: 'pending', spec3: 'pending', spec4: 'failed', spec5: 'failed', spec6: 'pending', spec7: 'pending' }); expect(suiteResults).toEqual({ suite0: 'passed', suite1: 'passed', suite2: 'passed', suite3: 'passed', suite4: 'pending', suite5: 'passed' }); env.execute(null, function() { expect(specResults).toEqual({ spec1: 'passed', spec2: 'passed', spec3: 'pending', spec4: 'passed', spec5: 'failed', spec6: 'pending', spec7: 'pending' }); expect(suiteResults).toEqual({ suite0: 'passed', suite1: 'passed', suite2: 'passed', suite3: 'passed', suite4: 'pending', suite5: 'passed' }); done(); }); }); }); it('should execute before and after hooks per run', function(done) { var timeline = []; var timelineFn = function(hookName) { return function() { timeline.push(hookName); }; }; var expectedTimeLine = [ 'beforeAll', 'beforeEach', 'spec1', 'afterEach', 'beforeEach', 'spec2', 'afterEach', 'afterAll' ]; env.describe('suite0', function() { env.beforeAll(timelineFn('beforeAll')); env.beforeEach(timelineFn('beforeEach')); env.afterEach(timelineFn('afterEach')); env.afterAll(timelineFn('afterAll')); env.it('spec1', timelineFn('spec1')); env.it('spec2', timelineFn('spec2')); }); env.execute(null, function() { expect(timeline).toEqual(expectedTimeLine); timeline = []; env.execute(null, function() { expect(timeline).toEqual(expectedTimeLine); done(); }); }); }); it('should be able to filter out different tests in subsequent runs', function(done) { var specResults = {}; var focussedSpec = 'spec1'; env.configure({ specFilter: function(spec) { return spec.description === focussedSpec; } }); env.addReporter({ specDone: function(spec) { specResults[spec.description] = spec.status; } }); env.describe('suite0', function() { env.it('spec1', function() {}); env.it('spec2', function() {}); env.it('spec3', function() {}); }); env.execute(null, function() { expect(specResults).toEqual({ spec1: 'passed', spec2: 'excluded', spec3: 'excluded' }); focussedSpec = 'spec2'; env.execute(null, function() { expect(specResults).toEqual({ spec1: 'excluded', spec2: 'passed', spec3: 'excluded' }); focussedSpec = 'spec3'; env.execute(null, function() { expect(specResults).toEqual({ spec1: 'excluded', spec2: 'excluded', spec3: 'passed' }); done(); }); }); }); }); }); }); jasmine-4.0.0/spec/core/matchers/000077500000000000000000000000001416413636100166365ustar00rootroot00000000000000jasmine-4.0.0/spec/core/matchers/DiffBuilderSpec.js000066400000000000000000000144721416413636100221760ustar00rootroot00000000000000describe('DiffBuilder', function() { it('records the actual and expected objects', function() { var diffBuilder = jasmineUnderTest.DiffBuilder(); diffBuilder.setRoots({ x: 'actual' }, { x: 'expected' }); diffBuilder.recordMismatch(); expect(diffBuilder.getMessage()).toEqual( "Expected Object({ x: 'actual' }) to equal Object({ x: 'expected' })." ); }); it('prints the path at which the difference was found', function() { var diffBuilder = jasmineUnderTest.DiffBuilder(); diffBuilder.setRoots({ foo: { x: 'actual' } }, { foo: { x: 'expected' } }); diffBuilder.withPath('foo', function() { diffBuilder.recordMismatch(); }); expect(diffBuilder.getMessage()).toEqual( "Expected $.foo = Object({ x: 'actual' }) to equal Object({ x: 'expected' })." ); }); it('prints multiple messages, separated by newlines', function() { var diffBuilder = jasmineUnderTest.DiffBuilder(); diffBuilder.setRoots({ foo: 1, bar: 3 }, { foo: 2, bar: 4 }); diffBuilder.withPath('foo', function() { diffBuilder.recordMismatch(); }); diffBuilder.withPath('bar', function() { diffBuilder.recordMismatch(); }); var message = 'Expected $.foo = 1 to equal 2.\n' + 'Expected $.bar = 3 to equal 4.'; expect(diffBuilder.getMessage()).toEqual(message); }); it('allows customization of the message', function() { var diffBuilder = jasmineUnderTest.DiffBuilder(); diffBuilder.setRoots({ x: 'bar' }, { x: 'foo' }); function darthVaderFormatter(actual, expected, path) { return ( 'I find your lack of ' + expected + ' disturbing. (was ' + actual + ', at ' + path + ')' ); } diffBuilder.withPath('x', function() { diffBuilder.recordMismatch(darthVaderFormatter); }); expect(diffBuilder.getMessage()).toEqual( 'I find your lack of foo disturbing. (was bar, at $.x)' ); }); it('uses the injected pretty-printer', function() { var prettyPrinter = function(val) { return '|' + val + '|'; }, diffBuilder = jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); prettyPrinter.customFormat_ = function() {}; diffBuilder.setRoots({ foo: 'actual' }, { foo: 'expected' }); diffBuilder.withPath('foo', function() { diffBuilder.recordMismatch(); }); expect(diffBuilder.getMessage()).toEqual( 'Expected $.foo = |actual| to equal |expected|.' ); }); it('passes the injected pretty-printer to the diff formatter', function() { var diffFormatter = jasmine.createSpy('diffFormatter'), prettyPrinter = function() {}, diffBuilder = jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); prettyPrinter.customFormat_ = function() {}; diffBuilder.setRoots({ x: 'bar' }, { x: 'foo' }); diffBuilder.withPath('x', function() { diffBuilder.recordMismatch(diffFormatter); }); diffBuilder.getMessage(); expect(diffFormatter).toHaveBeenCalledWith( 'bar', 'foo', jasmine.anything(), prettyPrinter ); }); it('uses custom object formatters on leaf nodes', function() { var formatter = function(x) { if (typeof x === 'number') { return '[number:' + x + ']'; } }; const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); var diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); diffBuilder.setRoots(5, 4); diffBuilder.recordMismatch(); expect(diffBuilder.getMessage()).toEqual( 'Expected [number:5] to equal [number:4].' ); }); it('uses custom object formatters on non leaf nodes', function() { var formatter = function(x) { if (x.hasOwnProperty('a')) { return '[thing with a=' + x.a + ', b=' + JSON.stringify(x.b) + ']'; } }; const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); var diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); var expectedMsg = 'Expected $[0].foo = [thing with a=1, b={"x":42}] to equal [thing with a=1, b={"x":43}].\n' + "Expected $[0].bar = 'yes' to equal 'no'."; diffBuilder.setRoots( [{ foo: { a: 1, b: { x: 42 } }, bar: 'yes' }], [{ foo: { a: 1, b: { x: 43 } }, bar: 'no' }] ); diffBuilder.withPath(0, function() { diffBuilder.withPath('foo', function() { diffBuilder.withPath('b', function() { diffBuilder.withPath('x', function() { diffBuilder.recordMismatch(); }); }); }); diffBuilder.withPath('bar', function() { diffBuilder.recordMismatch(); }); }); expect(diffBuilder.getMessage()).toEqual(expectedMsg); }); it('builds diffs involving asymmetric equality testers that implement valuesForDiff_ at the root', function() { var prettyPrinter = jasmineUnderTest.makePrettyPrinter([]), diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }), expectedMsg = 'Expected $.foo = 1 to equal 2.\n' + 'Expected $.baz = undefined to equal 3.'; diffBuilder.setRoots( { foo: 1, bar: 2 }, jasmine.objectContaining({ foo: 2, baz: 3 }) ); diffBuilder.withPath('foo', function() { diffBuilder.recordMismatch(); }); diffBuilder.withPath('baz', function() { diffBuilder.recordMismatch(); }); expect(diffBuilder.getMessage()).toEqual(expectedMsg); }); it('builds diffs involving asymmetric equality testers that implement valuesForDiff_ below the root', function() { var prettyPrinter = jasmineUnderTest.makePrettyPrinter([]), diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }), expectedMsg = 'Expected $.x.foo = 1 to equal 2.\n' + 'Expected $.x.baz = undefined to equal 3.'; diffBuilder.setRoots( { x: { foo: 1, bar: 2 } }, { x: jasmine.objectContaining({ foo: 2, baz: 3 }) } ); diffBuilder.withPath('x', function() { diffBuilder.withPath('foo', function() { diffBuilder.recordMismatch(); }); diffBuilder.withPath('baz', function() { diffBuilder.recordMismatch(); }); }); expect(diffBuilder.getMessage()).toEqual(expectedMsg); }); }); jasmine-4.0.0/spec/core/matchers/MismatchTreeSpec.js000066400000000000000000000104061416413636100223750ustar00rootroot00000000000000describe('MismatchTree', function() { describe('#add', function() { describe('When the path is empty', function() { it('flags the root node as mismatched', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath([])); expect(tree.isMismatch).toBe(true); }); }); describe('When the path is not empty', function() { it('flags the node as mismatched', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b'])); expect(tree.child('a').child('b').isMismatch).toBe(true); }); it('does not flag ancestors as mismatched', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b'])); expect(tree.isMismatch).toBe(false); expect(tree.child('a').isMismatch).toBe(false); }); }); it('stores the formatter on only the target node', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b']), formatter); expect(tree.formatter).toBeFalsy(); expect(tree.child('a').formatter).toBeFalsy(); expect(tree.child('a').child('b').formatter).toBe(formatter); }); it('stores the path to the node', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b']), formatter); expect(tree.child('a').child('b').path.components).toEqual(['a', 'b']); }); }); describe('#traverse', function() { it('calls the callback for all nodes that are or contain mismatches', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b']), formatter); tree.add(new jasmineUnderTest.ObjectPath(['c'])); var visit = jasmine.createSpy('visit').and.returnValue(true); tree.traverse(visit); expect(visit).toHaveBeenCalledWith( new jasmineUnderTest.ObjectPath([]), false, undefined ); expect(visit).toHaveBeenCalledWith( new jasmineUnderTest.ObjectPath(['a']), false, undefined ); expect(visit).toHaveBeenCalledWith( new jasmineUnderTest.ObjectPath(['a', 'b']), true, formatter ); expect(visit).toHaveBeenCalledWith( new jasmineUnderTest.ObjectPath(['c']), true, undefined ); }); it('does not call the callback if there are no mismatches', function() { var tree = new jasmineUnderTest.MismatchTree(); var visit = jasmine.createSpy('visit'); tree.traverse(visit); expect(visit).not.toHaveBeenCalled(); }); it('visits parents before children', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b'])); var visited = []; tree.traverse(function(path) { visited.push(path); return true; }); expect(visited).toEqual([ new jasmineUnderTest.ObjectPath([]), new jasmineUnderTest.ObjectPath(['a']), new jasmineUnderTest.ObjectPath(['a', 'b']) ]); }); it('visits children in the order they were recorded', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['length'])); tree.add(new jasmineUnderTest.ObjectPath([1])); var visited = []; tree.traverse(function(path) { visited.push(path); return true; }); expect(visited).toEqual([ new jasmineUnderTest.ObjectPath([]), new jasmineUnderTest.ObjectPath(['length']), new jasmineUnderTest.ObjectPath([1]) ]); }); it('does not visit children if the callback returns falsy', function() { var tree = new jasmineUnderTest.MismatchTree(); tree.add(new jasmineUnderTest.ObjectPath(['a', 'b'])); var visited = []; tree.traverse(function(path) { visited.push(path); return path.depth() === 0; }); expect(visited).toEqual([ new jasmineUnderTest.ObjectPath([]), new jasmineUnderTest.ObjectPath(['a']) ]); }); }); function formatter() {} }); jasmine-4.0.0/spec/core/matchers/NullDiffBuilderSpec.js000066400000000000000000000004301416413636100230160ustar00rootroot00000000000000describe('NullDiffBuilder', function() { it('responds to withPath() by calling the passed function', function() { var spy = jasmine.createSpy('callback'); jasmineUnderTest.NullDiffBuilder().withPath('does not matter', spy); expect(spy).toHaveBeenCalled(); }); }); jasmine-4.0.0/spec/core/matchers/ObjectPathSpec.js000066400000000000000000000030351416413636100220330ustar00rootroot00000000000000describe('ObjectPath', function() { var ObjectPath = jasmineUnderTest.ObjectPath; it('represents the path to a node in an object tree', function() { expect(new ObjectPath(['foo', 'bar']).toString()).toEqual('$.foo.bar'); }); it('has a depth', function() { expect(new ObjectPath().depth()).toEqual(0); expect(new ObjectPath(['foo']).depth()).toEqual(1); }); it('renders numbers as array access', function() { expect(new ObjectPath(['foo', 0]).toString()).toEqual('$.foo[0]'); }); it('renders properties that are valid identifiers with dot notation', function() { expect(new ObjectPath(['foo123']).toString()).toEqual('$.foo123'); expect(new ObjectPath(['x_y']).toString()).toEqual('$.x_y'); expect(new ObjectPath(['A$B']).toString()).toEqual('$.A$B'); }); it('renders properties with non-identifier-safe characters with square bracket notation', function() { expect(new ObjectPath(['a b c']).toString()).toEqual("$['a b c']"); expect(new ObjectPath(['1hello']).toString()).toEqual("$['1hello']"); }); it('renders as the empty string when empty', function() { expect(new ObjectPath().toString()).toEqual(''); }); it('stringifies properties that are not strings or numbers', function() { expect(new ObjectPath([{}]).toString()).toEqual("$['[object Object]']"); }); it('can be created based on another path', function() { var root = new ObjectPath(); var path = root.add('foo'); expect(path.toString()).toEqual('$.foo'); expect(root.toString()).toEqual(''); }); }); jasmine-4.0.0/spec/core/matchers/async/000077500000000000000000000000001416413636100177535ustar00rootroot00000000000000jasmine-4.0.0/spec/core/matchers/async/toBePendingSpec.js000066400000000000000000000030561416413636100233260ustar00rootroot00000000000000describe('toBePending', function() { it('passes if the actual promise is pending', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), actual = new Promise(function() {}); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if the actual promise is resolved', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), actual = Promise.resolve(); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: false })); }); }); it('fails if the actual promise is rejected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), actual = Promise.reject(new Error('promise was rejected')); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: false })); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError('Expected toBePending to be called on a promise.'); }); }); jasmine-4.0.0/spec/core/matchers/async/toBeRejectedSpec.js000066400000000000000000000022411416413636100234620ustar00rootroot00000000000000describe('toBeRejected', function() { it('passes if the actual is rejected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil), actual = Promise.reject('AsyncExpectationSpec rejection'); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if the actual is resolved', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil), actual = Promise.resolve(); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: false })); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError('Expected toBeRejected to be called on a promise.'); }); }); jasmine-4.0.0/spec/core/matchers/async/toBeRejectedWithErrorSpec.js000066400000000000000000000162311416413636100253340ustar00rootroot00000000000000describe('#toBeRejectedWithError', function() { it('passes when Error type matches', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new TypeError('foo')); return matcher.compare(actual, TypeError).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be rejected with TypeError, but it was.' }) ); }); }); it('passes when Error type and message matches', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new TypeError('foo')); return matcher.compare(actual, TypeError, 'foo').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: "Expected a promise not to be rejected with TypeError: 'foo', but it was." }) ); }); }); it('passes when Error matches and is exactly Error', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error()); return matcher.compare(actual, Error).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be rejected with Error, but it was.' }) ); }); }); it('passes when Error message matches a string', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error('foo')); return matcher.compare(actual, 'foo').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: "Expected a promise not to be rejected with Error: 'foo', but it was." }) ); }); }); it('passes when Error message matches a RegExp', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error('foo')); return matcher.compare(actual, /foo/).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be rejected with Error: /foo/, but it was.' }) ); }); }); it('passes when Error message is empty', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error()); return matcher.compare(actual, '').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: "Expected a promise not to be rejected with Error: '', but it was." }) ); }); }); it('passes when no arguments', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error()); return matcher.compare(actual, void 0).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be rejected with Error, but it was.' }) ); }); }); it('fails when resolved', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.resolve(new Error('foo')); return matcher.compare(actual, 'foo').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: 'Expected a promise to be rejected but it was resolved.' }) ); }); }); it('fails when rejected with non Error type', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject('foo'); return matcher.compare(actual, 'foo').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: "Expected a promise to be rejected with Error: 'foo' but it was rejected with 'foo'." }) ); }); }); it('fails when Error type mismatches', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error('foo')); return matcher.compare(actual, TypeError, 'foo').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: "Expected a promise to be rejected with TypeError: 'foo' but it was rejected with type Error." }) ); }); }); it('fails when Error message mismatches', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = Promise.reject(new Error('foo')); return matcher.compare(actual, 'bar').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: "Expected a promise to be rejected with Error: 'bar' but it was rejected with Error: foo." }) ); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError( matchersUtil ), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError( 'Expected toBeRejectedWithError to be called on a promise.' ); }); }); jasmine-4.0.0/spec/core/matchers/async/toBeRejectedWithSpec.js000066400000000000000000000060261416413636100243230ustar00rootroot00000000000000describe('#toBeRejectedWith', function() { it('should return true if the promise is rejected with the expected value', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.reject({ error: 'PEBCAK' }); return matcher.compare(actual, { error: 'PEBCAK' }).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('should fail if the promise resolves', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.resolve(); return matcher.compare(actual, '').then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: false })); }); }); it('should fail if the promise is rejected with a different value', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.reject('A Bad Apple'); return matcher.compare(actual, 'Some Cool Thing').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: "Expected a promise to be rejected with 'Some Cool Thing' but it was rejected with 'A Bad Apple'." }) ); }); }); it('should build its error correctly when negated', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.reject(true); return matcher.compare(actual, true).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be rejected with true.' }) ); }); }); it('should support custom equality testers', function() { var customEqualityTesters = [ function() { return true; } ], matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: customEqualityTesters }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.reject('actual'); return matcher.compare(actual, 'expected').then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError( 'Expected toBeRejectedWith to be called on a promise.' ); }); }); jasmine-4.0.0/spec/core/matchers/async/toBeResolvedSpec.js000066400000000000000000000025531416413636100235260ustar00rootroot00000000000000describe('toBeResolved', function() { it('passes if the actual is resolved', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil), actual = Promise.resolve(); return matcher.compare(actual).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if the actual is rejected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter([]) }), matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil), actual = Promise.reject(new Error('AsyncExpectationSpec rejection')); return matcher.compare(actual).then(function(result) { expect(result).toEqual({ pass: false, message: 'Expected a promise to be resolved but it was rejected ' + 'with Error: AsyncExpectationSpec rejection.' }); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError('Expected toBeResolved to be called on a promise.'); }); }); jasmine-4.0.0/spec/core/matchers/async/toBeResolvedToSpec.js000066400000000000000000000064341416413636100240330ustar00rootroot00000000000000describe('#toBeResolvedTo', function() { it('passes if the promise is resolved to the expected value', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.resolve({ foo: 42 }); return matcher.compare(actual, { foo: 42 }).then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if the promise is rejected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.reject(new Error('AsyncExpectationSpec error')); return matcher.compare(actual, '').then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: "Expected a promise to be resolved to '' but it was rejected " + 'with Error: AsyncExpectationSpec error.' }) ); }); }); it('fails if the promise is resolved to a different value', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.resolve({ foo: 17 }); return matcher.compare(actual, { foo: 42 }).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: false, message: 'Expected a promise to be resolved to Object({ foo: 42 }) but it was resolved to Object({ foo: 17 }).' }) ); }); }); it('builds its message correctly when negated', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.resolve(true); return matcher.compare(actual, true).then(function(result) { expect(result).toEqual( jasmine.objectContaining({ pass: true, message: 'Expected a promise not to be resolved to true.' }) ); }); }); it('supports custom equality testers', function() { var customEqualityTesters = [ function() { return true; } ], matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: customEqualityTesters, pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.resolve('actual'); return matcher.compare(actual, 'expected').then(function(result) { expect(result).toEqual(jasmine.objectContaining({ pass: true })); }); }); it('fails if actual is not a promise', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = 'not a promise'; function f() { return matcher.compare(actual); } expect(f).toThrowError( 'Expected toBeResolvedTo to be called on a promise.' ); }); }); jasmine-4.0.0/spec/core/matchers/matchersUtilSpec.js000066400000000000000000001115761416413636100224660ustar00rootroot00000000000000describe('matchersUtil', function() { it('exposes the injected pretty-printer as .pp', function() { var pp = function() {}, matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }); expect(matchersUtil.pp).toBe(pp); }); describe('equals', function() { it('passes for literals that are triple-equal', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(null, null)).toBe(true); expect(matchersUtil.equals(void 0, void 0)).toBe(true); }); it('fails for things that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals({ a: 'foo' }, 1)).toBe(false); }); it('passes for Strings that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals('foo', 'foo')).toBe(true); }); it('fails for Strings that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals('foo', 'bar')).toBe(false); }); it('passes for Numbers that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(123, 123)).toBe(true); }); it('fails for Numbers that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(123, 456)).toBe(false); }); it('fails for a Number and a String that have equivalent values', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(123, '123')).toBe(false); }); it('passes for Dates that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals(new Date('Jan 1, 1970'), new Date('Jan 1, 1970')) ).toBe(true); }); it('fails for Dates that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals(new Date('Jan 1, 1970'), new Date('Feb 3, 1991')) ).toBe(false); }); it('passes for Booleans that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(true, true)).toBe(true); }); it('fails for Booleans that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(true, false)).toBe(false); }); it('passes for RegExps that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(/foo/, /foo/)).toBe(true); }); it('fails for RegExps that are not equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(/foo/, /bar/)).toBe(false); expect( matchersUtil.equals(new RegExp('foo', 'i'), new RegExp('foo')) ).toBe(false); }); it('passes for Arrays that are equivalent', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals([1, 2], [1, 2])).toBe(true); }); it('passes for Arrays that are equivalent, with elements added by changing length', function() { var foo = [], matchersUtil = new jasmineUnderTest.MatchersUtil(); foo.length = 1; expect(matchersUtil.equals(foo, [undefined])).toBe(true); }); it('fails for Arrays that have different lengths', function() { const matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false); }); it('fails for Arrays that have different elements', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals([1, 2, 3], [1, 5, 3])).toBe(false); }); it('fails for Arrays whose contents are equivalent, but have differing properties', function() { var one = [1, 2, 3], two = [1, 2, 3], matchersUtil = new jasmineUnderTest.MatchersUtil(); one.foo = 'bar'; two.foo = 'baz'; expect(matchersUtil.equals(one, two)).toBe(false); }); it('passes for Arrays with equivalent contents and properties', function() { var one = [1, 2, 3], two = [1, 2, 3], matchersUtil = new jasmineUnderTest.MatchersUtil(); one.foo = 'bar'; two.foo = 'bar'; expect(matchersUtil.equals(one, two)).toBe(true); }); it('passes for Errors that are the same type and have the same message', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(new Error('foo'), new Error('foo'))).toBe( true ); }); it('fails for Errors that are the same type and have different messages', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(new Error('foo'), new Error('bar'))).toBe( false ); }); it('fails for objects with different constructors', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); function One() {} function Two() {} expect(matchersUtil.equals(new One(), new Two())).toBe(false); }); it('passes for Objects that are equivalent (simple case)', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals({ a: 'foo' }, { a: 'foo' })).toBe(true); }); it('fails for Objects that are not equivalent (simple case)', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals({ a: 'foo' }, { a: 'bar' })).toBe(false); }); it('passes for Objects that are equivalent (deep case)', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals( { a: 'foo', b: { c: 'bar' } }, { a: 'foo', b: { c: 'bar' } } ) ).toBe(true); }); it('fails for Objects that are not equivalent (deep case)', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals( { a: 'foo', b: { c: 'baz' } }, { a: 'foo', b: { c: 'bar' } } ) ).toBe(false); }); it('passes for Objects that are equivalent (with cycles)', function() { var actual = { a: 'foo' }, expected = { a: 'foo' }, matchersUtil = new jasmineUnderTest.MatchersUtil(); actual.b = actual; expected.b = actual; expect(matchersUtil.equals(actual, expected)).toBe(true); }); it('fails for Objects that are not equivalent (with cycles)', function() { var actual = { a: 'foo' }, expected = { a: 'bar' }, matchersUtil = new jasmineUnderTest.MatchersUtil(); actual.b = actual; expected.b = actual; expect(matchersUtil.equals(actual, expected)).toBe(false); }); it('fails for Objects that have the same number of keys, but different keys/values', function() { var expected = { a: undefined }, actual = { b: 1 }, matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(actual, expected)).toBe(false); }); it('fails when comparing an empty object to an empty array (issue #114)', function() { var emptyObject = {}, emptyArray = [], matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(emptyObject, emptyArray)).toBe(false); expect(matchersUtil.equals(emptyArray, emptyObject)).toBe(false); }); it('passes for equivalent frozen objects (GitHub issue #266)', function() { var a = { foo: 1 }, b = { foo: 1 }, matchersUtil = new jasmineUnderTest.MatchersUtil(); Object.freeze(a); Object.freeze(b); expect(matchersUtil.equals(a, b)).toBe(true); }); it('passes for equivalent Promises (GitHub issue #1314)', function() { if (typeof Promise === 'undefined') { return; } var p1 = new Promise(function() {}), p2 = new Promise(function() {}), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(p1, p1)).toBe(true); expect(matchersUtil.equals(p1, p2)).toBe(false); }); describe('when running in a browser', function() { function isNotRunningInBrowser() { return typeof document === 'undefined'; } it('passes for equivalent DOM nodes', function() { if (isNotRunningInBrowser()) { return; } var a = document.createElement('div'); var matchersUtil = new jasmineUnderTest.MatchersUtil(); a.setAttribute('test-attr', 'attr-value'); a.appendChild(document.createTextNode('test')); var b = document.createElement('div'); b.setAttribute('test-attr', 'attr-value'); b.appendChild(document.createTextNode('test')); expect(matchersUtil.equals(a, b)).toBe(true); }); it('passes for equivalent objects from different frames', function() { if (isNotRunningInBrowser()) { return; } var matchersUtil = new jasmineUnderTest.MatchersUtil(); var iframe = document.createElement('iframe'); document.body.appendChild(iframe); iframe.contentWindow.eval('window.testObject = {}'); expect(matchersUtil.equals({}, iframe.contentWindow.testObject)).toBe( true ); document.body.removeChild(iframe); }); it('fails for DOM nodes with different attributes or child nodes', function() { if (isNotRunningInBrowser()) { return; } var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a = document.createElement('div'); a.setAttribute('test-attr', 'attr-value'); a.appendChild(document.createTextNode('test')); var b = document.createElement('div'); b.setAttribute('test-attr', 'attr-value2'); b.appendChild(document.createTextNode('test')); expect(matchersUtil.equals(a, b)).toBe(false); b.setAttribute('test-attr', 'attr-value'); expect(matchersUtil.equals(a, b)).toBe(true); b.appendChild(document.createTextNode('2')); expect(matchersUtil.equals(a, b)).toBe(false); a.appendChild(document.createTextNode('2')); expect(matchersUtil.equals(a, b)).toBe(true); }); }); describe('when running in Node', function() { function isNotRunningInNode() { return typeof require !== 'function'; } it('passes for equivalent objects from different vm contexts', function() { if (isNotRunningInNode()) { return; } var matchersUtil = new jasmineUnderTest.MatchersUtil(); var vm = require('vm'); var sandbox = { obj: null }; vm.runInNewContext('obj = {a: 1, b: 2}', sandbox); expect(matchersUtil.equals(sandbox.obj, { a: 1, b: 2 })).toBe(true); }); it('passes for equivalent arrays from different vm contexts', function() { if (isNotRunningInNode()) { return; } var matchersUtil = new jasmineUnderTest.MatchersUtil(); var vm = require('vm'); var sandbox = { arr: null }; vm.runInNewContext('arr = [1, 2]', sandbox); expect(matchersUtil.equals(sandbox.arr, [1, 2])).toBe(true); }); }); it('passes when Any is used', function() { var number = 3, anyNumber = new jasmineUnderTest.Any(Number), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(number, anyNumber)).toBe(true); expect(matchersUtil.equals(anyNumber, number)).toBe(true); }); it('fails when Any is compared to something unexpected', function() { var number = 3, anyString = new jasmineUnderTest.Any(String), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(number, anyString)).toBe(false); expect(matchersUtil.equals(anyString, number)).toBe(false); }); it('passes when ObjectContaining is used', function() { var obj = { foo: 3, bar: 7 }, containing = new jasmineUnderTest.ObjectContaining({ foo: 3 }), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true); }); it('passes when MapContaining is used', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var obj = new Map(); obj.set(1, 2); obj.set('foo', 'bar'); var containing = new jasmineUnderTest.MapContaining(new Map()); containing.sample.set('foo', 'bar'); expect(matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true); }); it('passes when SetContaining is used', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var obj = new Set(); obj.add(1); obj.add('foo'); var containing = new jasmineUnderTest.SetContaining(new Set()); containing.sample.add(1); expect(matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true); }); it('passes when an asymmetric equality tester returns true', function() { var tester = { asymmetricMatch: function(other) { return true; } }, matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(false, tester)).toBe(true); expect(matchersUtil.equals(tester, false)).toBe(true); }); it('fails when an asymmetric equality tester returns false', function() { var tester = { asymmetricMatch: function(other) { return false; } }, matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(true, tester)).toBe(false); expect(matchersUtil.equals(tester, true)).toBe(false); }); it('passes when ArrayContaining is used', function() { var arr = ['foo', 'bar'], matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals(arr, new jasmineUnderTest.ArrayContaining(['bar'])) ).toBe(true); }); it('passes when a custom equality matcher returns true', function() { var tester = function(a, b) { return true; }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester], pp: function() {} }); expect(matchersUtil.equals(1, 2)).toBe(true); }); it('passes for two empty Objects', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals({}, {})).toBe(true); }); describe("when a custom equality matcher returns 'undefined'", function() { var tester = function(a, b) { return jasmine.undefined; }; it('passes for two empty Objects', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester], pp: function() {} }); expect(matchersUtil.equals({}, {})).toBe(true); }); }); it('fails for equivalents when a custom equality matcher returns false', function() { var tester = function(a, b) { return false; }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester], pp: function() {} }); expect(matchersUtil.equals(1, 1)).toBe(false); }); it('passes for an asymmetric equality tester that returns true when a custom equality tester return false', function() { var asymmetricTester = { asymmetricMatch: function(other) { return true; } }, symmetricTester = function(a, b) { return false; }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [symmetricTester()], pp: function() {} }); expect(matchersUtil.equals(asymmetricTester, true)).toBe(true); expect(matchersUtil.equals(true, asymmetricTester)).toBe(true); }); it('passes when an Any is compared to an Any that checks for the same type', function() { var any1 = new jasmineUnderTest.Any(Function), any2 = new jasmineUnderTest.Any(Function), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(any1, any2)).toBe(true); }); it('passes for null prototype objects with same properties', function() { var objA = Object.create(null), objB = Object.create(null), matchersUtil = new jasmineUnderTest.MatchersUtil(); objA.name = 'test'; objB.name = 'test'; expect(matchersUtil.equals(objA, objB)).toBe(true); }); it('fails for null prototype objects with different properties', function() { var objA = Object.create(null), objB = Object.create(null), matchersUtil = new jasmineUnderTest.MatchersUtil(); objA.name = 'test'; objB.test = 'name'; expect(matchersUtil.equals(objA, objB)).toBe(false); }); it('passes when comparing two empty sets', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(new Set(), new Set())).toBe(true); }); it('passes when comparing identical sets', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA = new Set(); setA.add(6); setA.add(5); var setB = new Set(); setB.add(6); setB.add(5); expect(matchersUtil.equals(setA, setB)).toBe(true); }); it('passes when comparing identical sets with different insertion order and simple elements', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA = new Set(); setA.add(3); setA.add(6); var setB = new Set(); setB.add(6); setB.add(3); expect(matchersUtil.equals(setA, setB)).toBe(true); }); it('passes when comparing identical sets with different insertion order and complex elements 1', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA1 = new Set(); setA1.add(['a', 3]); setA1.add([6, 1]); var setA2 = new Set(); setA1.add(['y', 3]); setA1.add([6, 1]); var setA = new Set(); setA.add(setA1); setA.add(setA2); var setB1 = new Set(); setB1.add([6, 1]); setB1.add(['a', 3]); var setB2 = new Set(); setB1.add([6, 1]); setB1.add(['y', 3]); var setB = new Set(); setB.add(setB1); setB.add(setB2); expect(matchersUtil.equals(setA, setB)).toBe(true); }); it('passes when comparing identical sets with different insertion order and complex elements 2', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA = new Set(); setA.add([[1, 2], [3, 4]]); setA.add([[5, 6], [7, 8]]); var setB = new Set(); setB.add([[5, 6], [7, 8]]); setB.add([[1, 2], [3, 4]]); expect(matchersUtil.equals(setA, setB)).toBe(true); }); it('fails for sets with different elements', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA = new Set(); setA.add(6); setA.add(3); setA.add(5); var setB = new Set(); setB.add(6); setB.add(4); setB.add(5); expect(matchersUtil.equals(setA, setB)).toBe(false); }); it('fails for sets of different size', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setA = new Set(); setA.add(6); setA.add(3); var setB = new Set(); setB.add(6); setB.add(4); setB.add(5); expect(matchersUtil.equals(setA, setB)).toBe(false); }); it('passes when comparing two empty maps', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(new Map(), new Map())).toBe(true); }); it('passes when comparing identical maps', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var mapA = new Map(); mapA.set(6, 5); var mapB = new Map(); mapB.set(6, 5); expect(matchersUtil.equals(mapA, mapB)).toBe(true); }); it('passes when comparing identical maps with different insertion order', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var mapA = new Map(); mapA.set('a', 3); mapA.set(6, 1); var mapB = new Map(); mapB.set(6, 1); mapB.set('a', 3); expect(matchersUtil.equals(mapA, mapB)).toBe(true); }); it('fails for maps with different elements', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var mapA = new Map(); mapA.set(6, 3); mapA.set(5, 1); var mapB = new Map(); mapB.set(6, 4); mapB.set(5, 1); expect(matchersUtil.equals(mapA, mapB)).toBe(false); }); it('fails for maps of different size', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var mapA = new Map(); mapA.set(6, 3); var mapB = new Map(); mapB.set(6, 4); mapB.set(5, 1); expect(matchersUtil.equals(mapA, mapB)).toBe(false); }); it('passes when comparing two identical URLs', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals( new URL('http://localhost/1'), new URL('http://localhost/1') ) ).toBe(true); }); it('fails when comparing two different URLs', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), url1 = new URL('http://localhost/1'); expect(matchersUtil.equals(url1, new URL('http://localhost/2'))).toBe( false ); expect(matchersUtil.equals(url1, new URL('http://localhost/1?foo'))).toBe( false ); expect(matchersUtil.equals(url1, new URL('http://localhost/1#foo'))).toBe( false ); expect(matchersUtil.equals(url1, new URL('https://localhost/1'))).toBe( false ); expect( matchersUtil.equals(url1, new URL('http://localhost:8080/1')) ).toBe(false); expect(matchersUtil.equals(url1, new URL('http://example.com/1'))).toBe( false ); }); it('passes for ArrayBuffers with same length and content', function() { var buffer1 = new ArrayBuffer(4); var buffer2 = new ArrayBuffer(4); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(buffer1, buffer2)).toBe(true); }); it('fails for ArrayBuffers with same length but different content', function() { var buffer1 = new ArrayBuffer(4); var buffer2 = new ArrayBuffer(4); var array1 = new Uint8Array(buffer1); array1[0] = 1; var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(buffer1, buffer2)).toBe(false); }); describe('Typed arrays', function() { it('fails for typed arrays of same length and contents but different types', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new Int8Array(1); var a2 = new Uint8Array(1); a1[0] = a2[0] = 0; expect(matchersUtil.equals(a1, a2)).toBe(false); }); [ 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array' ].forEach(function(typeName) { var TypedArrayCtor = jasmine.getGlobal()[typeName]; it( 'passes for ' + typeName + 's with same length and content', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(2); a1[0] = a2[0] = 0; a1[1] = a2[1] = 1; expect(matchersUtil.equals(a1, a2)).toBe(true); } ); it('fails for ' + typeName + 's with different length', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(1); a1[0] = a1[1] = a2[0] = 0; expect(matchersUtil.equals(a1, a2)).toBe(false); }); it( 'fails for ' + typeName + 's with same length but different content', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); a1[0] = 0; a2[0] = 1; expect(matchersUtil.equals(a1, a2)).toBe(false); } ); it('checks nonstandard properties of ' + typeName, function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); a1[0] = a2[0] = 0; a1.extra = 'yes'; expect(matchersUtil.equals(a1, a2)).toBe(false); }); it('works with custom equality testers with ' + typeName, function() { var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [ function() { return true; } ] }); a1[0] = 0; a2[0] = 1; expect(matchersUtil.equals(a1, a2)).toBe(true); }); }); ['BigInt64Array', 'BigUint64Array'].forEach(function(typeName) { function requireType() { var TypedArrayCtor = jasmine.getGlobal()[typeName]; if (!TypedArrayCtor) { pending('Browser does not support ' + typeName); } return TypedArrayCtor; } it( 'passes for ' + typeName + 's with same length and content', function() { var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(2); // eslint-disable-next-line compat/compat a1[0] = a2[0] = BigInt(0); // eslint-disable-next-line compat/compat a1[1] = a2[1] = BigInt(1); expect(matchersUtil.equals(a1, a2)).toBe(true); } ); it('fails for ' + typeName + 's with different length', function() { var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(1); // eslint-disable-next-line compat/compat a1[0] = a1[1] = a2[0] = BigInt(0); expect(matchersUtil.equals(a1, a2)).toBe(false); }); it( 'fails for ' + typeName + 's with same length but different content', function() { var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(2); // eslint-disable-next-line compat/compat a1[0] = a1[1] = a2[0] = BigInt(0); // eslint-disable-next-line compat/compat a2[1] = BigInt(1); expect(matchersUtil.equals(a1, a2)).toBe(false); } ); }); }); describe('when running in an environment with array polyfills', function() { var findIndexDescriptor = Object.getOwnPropertyDescriptor( Array.prototype, 'findIndex' ); beforeEach(function() { if (!findIndexDescriptor) { jasmine .getEnv() .pending( 'Environment does not have a property descriptor for Array.prototype.findIndex' ); } Object.defineProperty(Array.prototype, 'findIndex', { enumerable: true, value: function(predicate) { if (this === null) { throw new TypeError( 'Array.prototype.findIndex called on null or undefined' ); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; var value; for (var i = 0; i < length; i++) { value = list[i]; if (predicate.call(thisArg, value, i, list)) { return i; } } return -1; } }); }); afterEach(function() { Object.defineProperty( Array.prototype, 'findIndex', findIndexDescriptor ); }); it("passes when there's an array polyfill", function() { expect(['foo']).toEqual(['foo']); }); }); describe('Building diffs for asymmetric equality testers', function() { it('diffs the values returned by valuesForDiff_', function() { var tester = { asymmetricMatch: function() { return false; }, valuesForDiff_: function() { return { self: 'asymmetric tester value', other: 'other value' }; } }, actual = { x: 42 }, expected = { x: tester }, diffBuilder = jasmine.createSpyObj('diffBuilder', [ 'recordMismatch', 'withPath', 'setRoots' ]), matchersUtil = new jasmineUnderTest.MatchersUtil(); diffBuilder.withPath.and.callFake(function(p, block) { block(); }); matchersUtil.equals(actual, expected, diffBuilder); expect(diffBuilder.setRoots).toHaveBeenCalledWith(actual, expected); expect(diffBuilder.withPath).toHaveBeenCalledWith( 'x', jasmine.any(Function) ); expect(diffBuilder.recordMismatch).toHaveBeenCalledWith(); }); it('records both objects when the tester does not implement valuesForDiff', function() { var tester = { asymmetricMatch: function() { return false; } }, actual = { x: 42 }, expected = { x: tester }, diffBuilder = jasmine.createSpyObj('diffBuilder', [ 'recordMismatch', 'withPath', 'setRoots' ]), matchersUtil = new jasmineUnderTest.MatchersUtil(); diffBuilder.withPath.and.callFake(function(p, block) { block(); }); matchersUtil.equals(actual, expected, diffBuilder); expect(diffBuilder.setRoots).toHaveBeenCalledWith(actual, expected); expect(diffBuilder.withPath).toHaveBeenCalledWith( 'x', jasmine.any(Function) ); expect(diffBuilder.recordMismatch).toHaveBeenCalledWith(); }); }); it('uses a diffBuilder if one is provided as the third argument', function() { var diffBuilder = new jasmineUnderTest.DiffBuilder(), matchersUtil = new jasmineUnderTest.MatchersUtil(); spyOn(diffBuilder, 'recordMismatch'); spyOn(diffBuilder, 'withPath').and.callThrough(); matchersUtil.equals([1], [2], diffBuilder); expect(diffBuilder.withPath).toHaveBeenCalledWith( 'length', jasmine.any(Function) ); expect(diffBuilder.withPath).toHaveBeenCalledWith( 0, jasmine.any(Function) ); expect(diffBuilder.recordMismatch).toHaveBeenCalled(); }); }); describe('contains', function() { it('passes when expected is a substring of actual', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains('ABC', 'BC')).toBe(true); }); it('fails when expected is a not substring of actual', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains('ABC', 'X')).toBe(false); }); it('passes when expected is an element in an actual array', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(['foo', 'bar'], 'foo')).toBe(true); }); it('fails when expected is not an element in an actual array', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(['foo', 'bar'], 'baz')).toBe(false); }); it('passes with mixed-element arrays', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(['foo', { some: 'bar' }], 'foo')).toBe(true); expect( matchersUtil.contains(['foo', { some: 'bar' }], { some: 'bar' }) ).toBe(true); }); it('uses custom equality testers if actual is an Array', function() { var customTester = function(a, b) { return true; }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [customTester], pp: function() {} }); expect(matchersUtil.contains([1, 2], 3)).toBe(true); }); it('fails when actual is undefined', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(undefined, 'A')).toBe(false); }); it('fails when actual is null', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(null, 'A')).toBe(false); }); it('works with array-like objects that implement iterable', function() { var capturedArgs = null, matchersUtil = new jasmineUnderTest.MatchersUtil(); function testFunction() { capturedArgs = arguments; } testFunction('foo', 'bar'); expect(matchersUtil.contains(capturedArgs, 'bar')).toBe(true); expect(matchersUtil.contains(capturedArgs, 'baz')).toBe(false); }); it("passes with array-like objects that don't implement iterable", function() { const arrayLike = { 0: 'a', 1: 'b', length: 2 }; const matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.contains(arrayLike, 'b')).toBe(true); expect(matchersUtil.contains(arrayLike, 'c')).toBe(false); }); it('passes for set members', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setItem = { foo: 'bar' }; var set = new Set(); set.add(setItem); expect(matchersUtil.contains(set, setItem)).toBe(true); }); it('passes for objects that equal to a set member', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var set = new Set(); set.add({ foo: 'bar' }); expect(matchersUtil.contains(set, { foo: 'bar' })).toBe(true); }); }); describe('buildFailureMessage', function() { it('builds an English sentence for a failure case', function() { var actual = 'foo', name = 'toBar', pp = jasmineUnderTest.makePrettyPrinter(), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), message = matchersUtil.buildFailureMessage(name, false, actual); expect(message).toEqual("Expected 'foo' to bar."); }); it("builds an English sentence for a 'not' failure case", function() { var actual = 'foo', name = 'toBar', isNot = true, pp = jasmineUnderTest.makePrettyPrinter(), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), message = (message = matchersUtil.buildFailureMessage( name, isNot, actual )); expect(message).toEqual("Expected 'foo' not to bar."); }); it('builds an English sentence for an arbitrary array of expected arguments', function() { var actual = 'foo', name = 'toBar', pp = jasmineUnderTest.makePrettyPrinter(), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), message = matchersUtil.buildFailureMessage( name, false, actual, 'quux', 'corge' ); expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'."); }); it('uses the injected pretty-printer to format the expecteds and actual', function() { var actual = 'foo', expected1 = 'qux', expected2 = 'grault', name = 'toBar', isNot = false, pp = function(value) { return '<' + value + '>'; }, matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), message = (message = matchersUtil.buildFailureMessage( name, isNot, actual, expected1, expected2 )); expect(message).toEqual('Expected to bar , .'); }); }); }); jasmine-4.0.0/spec/core/matchers/nothingSpec.js000066400000000000000000000003121416413636100214510ustar00rootroot00000000000000describe('nothing', function() { it('should pass', function() { var matcher = jasmineUnderTest.matchers.nothing(), result = matcher.compare(); expect(result.pass).toBe(true); }); }); jasmine-4.0.0/spec/core/matchers/toBeCloseToSpec.js000066400000000000000000000064251416413636100222000ustar00rootroot00000000000000describe('toBeCloseTo', function() { it('passes when within two decimal places by default', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(), result; result = matcher.compare(0, 0); expect(result.pass).toBe(true); result = matcher.compare(0, 0.001); expect(result.pass).toBe(true); result = matcher.compare(0, 0.005); expect(result.pass).toBe(true); }); it('fails when not within two decimal places by default', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(), result; result = matcher.compare(0, 0.01); expect(result.pass).toBe(false); result = matcher.compare(0, 0.05); expect(result.pass).toBe(false); }); it('accepts an optional precision argument', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(), result; result = matcher.compare(0, 0.1, 0); expect(result.pass).toBe(true); result = matcher.compare(0, 0.5, 0); expect(result.pass).toBe(true); result = matcher.compare(0, 0.0001, 3); expect(result.pass).toBe(true); result = matcher.compare(0, 0.0005, 3); expect(result.pass).toBe(true); result = matcher.compare(0, 0.00001, 4); expect(result.pass).toBe(true); result = matcher.compare(0, 0.00005, 4); expect(result.pass).toBe(true); }); it('fails when one of the arguments is null', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(); expect(function() { matcher.compare(null, null); }).toThrowError( 'Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(null).' ); expect(function() { matcher.compare(0, null); }).toThrowError( 'Cannot use toBeCloseTo with null. Arguments evaluated to: expect(0).toBeCloseTo(null).' ); expect(function() { matcher.compare(null, 0); }).toThrowError( 'Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(0).' ); }); it('rounds expected values', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(), result; result = matcher.compare(1.23, 1.229); expect(result.pass).toBe(true); result = matcher.compare(1.23, 1.226); expect(result.pass).toBe(true); result = matcher.compare(1.23, 1.225); expect(result.pass).toBe(true); result = matcher.compare(1.23, 1.235); expect(result.pass).toBe(true); // 1.2249999 will be rounded to 1.225 result = matcher.compare(1.23, 1.2249999); expect(result.pass).toBe(true); // 1.2249999 will be rounded to 1.224 result = matcher.compare(1.23, 1.2244999); expect(result.pass).toBe(false); result = matcher.compare(1.23, 1.234); expect(result.pass).toBe(true); }); it('handles edge cases with rounding', function() { var matcher = jasmineUnderTest.matchers.toBeCloseTo(), result; // these cases resulted in false negatives in version of V8 // included in Node.js 12 and Chrome 74 (and Edge Chromium) result = matcher.compare(4.030904708957288, 4.0309, 5); expect(result.pass).toBe(true); result = matcher.compare(4.82665525779431, 4.82666, 5); expect(result.pass).toBe(true); result = matcher.compare(-2.82665525779431, -2.82666, 5); expect(result.pass).toBe(true); }); }); jasmine-4.0.0/spec/core/matchers/toBeDefinedSpec.js000066400000000000000000000007101416413636100221550ustar00rootroot00000000000000describe('toBeDefined', function() { it('matches for defined values', function() { var matcher = jasmineUnderTest.matchers.toBeDefined(), result; result = matcher.compare('foo'); expect(result.pass).toBe(true); }); it('fails when matching undefined values', function() { var matcher = jasmineUnderTest.matchers.toBeDefined(), result; result = matcher.compare(void 0); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeFalseSpec.js000066400000000000000000000011501416413636100216500ustar00rootroot00000000000000describe('toBeFalse', function() { it('passes for false', function() { var matcher = jasmineUnderTest.matchers.toBeFalse(), result; result = matcher.compare(false); expect(result.pass).toBe(true); }); it('fails for non-false', function() { var matcher = jasmineUnderTest.matchers.toBeFalse(), result; result = matcher.compare('foo'); expect(result.pass).toBe(false); }); it('fails for falsy', function() { var matcher = jasmineUnderTest.matchers.toBeFalse(), result; result = matcher.compare(undefined); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeFalsySpec.js000066400000000000000000000022301416413636100216740ustar00rootroot00000000000000describe('toBeFalsy', function() { it("passes for 'falsy' values", function() { var matcher = jasmineUnderTest.matchers.toBeFalsy(), result; result = matcher.compare(false); expect(result.pass).toBe(true); result = matcher.compare(0); expect(result.pass).toBe(true); result = matcher.compare(''); expect(result.pass).toBe(true); result = matcher.compare(null); expect(result.pass).toBe(true); result = matcher.compare(undefined); expect(result.pass).toBe(true); result = matcher.compare(void 0); expect(result.pass).toBe(true); }); it("fails for 'truthy' values", function() { var matcher = jasmineUnderTest.matchers.toBeFalsy(), result; result = matcher.compare(true); expect(result.pass).toBe(false); result = matcher.compare(1); expect(result.pass).toBe(false); result = matcher.compare('foo'); expect(result.pass).toBe(false); result = matcher.compare({}); expect(result.pass).toBe(false); result = matcher.compare([]); expect(result.pass).toBe(false); result = matcher.compare(function() {}); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeGreaterThanOrEqualSpec.js000066400000000000000000000014331416413636100243170ustar00rootroot00000000000000describe('toBeGreaterThanOrEqual', function() { it('passes when actual >= expected', function() { var matcher = jasmineUnderTest.matchers.toBeGreaterThanOrEqual(), result; result = matcher.compare(2, 1); expect(result.pass).toBe(true); result = matcher.compare(1, 1); expect(result.pass).toBe(true); result = matcher.compare(1.0000001, 1); expect(result.pass).toBe(true); result = matcher.compare(1.0, 1.0); expect(result.pass).toBe(true); }); it('fails when actual < expected', function() { var matcher = jasmineUnderTest.matchers.toBeGreaterThanOrEqual(), result; result = matcher.compare(1, 2); expect(result.pass).toBe(false); result = matcher.compare(1, 1.0000001); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeGreaterThanSpec.js000066400000000000000000000010271416413636100230250ustar00rootroot00000000000000describe('toBeGreaterThan', function() { it('passes when actual > expected', function() { var matcher = jasmineUnderTest.matchers.toBeGreaterThan(), result; result = matcher.compare(2, 1); expect(result.pass).toBe(true); }); it('fails when actual <= expected', function() { var matcher = jasmineUnderTest.matchers.toBeGreaterThan(), result; result = matcher.compare(1, 1); expect(result.pass).toBe(false); result = matcher.compare(1, 2); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeInstanceOfSpec.js000066400000000000000000000173421416413636100226610ustar00rootroot00000000000000describe('toBeInstanceOf', function() { describe('when expecting Number', function() { it('passes for literal number', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(3, Number); expect(result).toEqual({ pass: true, message: 'Expected instance of Number not to be an instance of Number' }); }); it('passes for NaN', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf({ pp: jasmineUnderTest.makePrettyPrinter() }); var result = matcher.compare(NaN, Number); expect(result).toEqual({ pass: true, message: 'Expected instance of NaN not to be an instance of Number' }); }); it('passes for Infinity', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(Infinity, Number); expect(result).toEqual({ pass: true, message: 'Expected instance of Number not to be an instance of Number' }); }); it('fails for a non-number', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare('foo', Number); expect(result).toEqual({ pass: false, message: 'Expected instance of String to be an instance of Number' }); }); }); describe('when expecting String', function() { it('passes for a string', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare('foo', String); expect(result).toEqual({ pass: true, message: 'Expected instance of String not to be an instance of String' }); }); it('fails for a non-string', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare({}, String); expect(result).toEqual({ pass: false, message: 'Expected instance of Object to be an instance of String' }); }); }); describe('when expecting Boolean', function() { it('passes for a boolean', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(true, Boolean); expect(result).toEqual({ pass: true, message: 'Expected instance of Boolean not to be an instance of Boolean' }); }); it('fails for a non-boolean', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare('false', Boolean); expect(result).toEqual({ pass: false, message: 'Expected instance of String to be an instance of Boolean' }); }); }); describe('when expecting RegExp', function() { it('passes for a literal regular expression', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(/foo/, RegExp); expect(result).toEqual({ pass: true, message: 'Expected instance of RegExp not to be an instance of RegExp' }); }); }); describe('when expecting Function', function() { it('passes for a function', function() { var fn = function() {}; var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(fn, Function); expect(result).toEqual({ pass: true, message: 'Expected instance of Function not to be an instance of Function' }); }); it('passes for an async function', function() { var fn = eval("(async function fn() { return 'foo'; })"); var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(fn, Function); expect(result).toEqual({ pass: true, message: 'Expected instance of AsyncFunction not to be an instance of Function' }); }); }); describe('when expecting Object', function() { function Animal() {} it('passes for any object', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare({ foo: 'bar' }, Object); expect(result).toEqual({ pass: true, message: 'Expected instance of Object not to be an instance of Object' }); }); it('passes for an Error object', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(new Error('example'), Object); expect(result).toEqual({ pass: true, message: 'Expected instance of Error not to be an instance of Object' }); }); it('passes for a user-defined class', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(new Animal(), Object); expect(result).toEqual({ pass: true, message: 'Expected instance of Animal not to be an instance of Object' }); }); it('fails for a non-object', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare('foo', Object); expect(result).toEqual({ pass: false, message: 'Expected instance of String to be an instance of Object' }); }); it('passes for objects with no constructor', function() { var object = Object.create(null); var matcher = jasmineUnderTest.matchers.toBeInstanceOf({ pp: jasmineUnderTest.makePrettyPrinter() }); var result = matcher.compare(object, Object); expect(result).toEqual({ pass: true, message: 'Expected instance of null({ }) not to be an instance of Object' }); }); }); describe('when expecting a user-defined class', function() { // Base class function Animal() {} // Subclasses, defined using syntax that is as old as possible function Dog() { Animal.call(this); } Dog.prototype = new Animal(); Dog.prototype.constructor = Dog; function Cat() { Animal.call(this); } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; it('passes for instances of that class', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(new Animal(), Animal); expect(result).toEqual({ pass: true, message: 'Expected instance of Animal not to be an instance of Animal' }); }); it('passes for instances of a subclass', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(new Cat(), Animal); expect(result).toEqual({ pass: true, message: 'Expected instance of Cat not to be an instance of Animal' }); }); it('does not pass for sibling classes', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); var result = matcher.compare(new Dog(), Cat); expect(result).toEqual({ pass: false, message: 'Expected instance of Dog to be an instance of Cat' }); }); }); it('raises an error if passed an invalid expected value', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); expect(function() { matcher.compare({}, 'Error'); }).toThrowError( ' : Expected value is not a constructor function\n' + 'Usage: expect(value).toBeInstanceOf()' ); }); it('raises an error if missing an expected value', function() { var matcher = jasmineUnderTest.matchers.toBeInstanceOf({ pp: jasmineUnderTest.makePrettyPrinter() }); expect(function() { matcher.compare({}, undefined); }).toThrowError( ' : Expected value is not a constructor function\n' + 'Usage: expect(value).toBeInstanceOf()' ); }); }); jasmine-4.0.0/spec/core/matchers/toBeLessThanOrEqualSpec.js000066400000000000000000000014221416413636100236320ustar00rootroot00000000000000describe('toBeLessThanOrEqual', function() { it('passes when actual <= expected', function() { var matcher = jasmineUnderTest.matchers.toBeLessThanOrEqual(), result; result = matcher.compare(1, 2); expect(result.pass).toBe(true); result = matcher.compare(1, 1); expect(result.pass).toBe(true); result = matcher.compare(1, 1.0000001); expect(result.pass).toBe(true); result = matcher.compare(1.0, 1.0); expect(result.pass).toBe(true); }); it('fails when actual < expected', function() { var matcher = jasmineUnderTest.matchers.toBeLessThanOrEqual(), result; result = matcher.compare(2, 1); expect(result.pass).toBe(false); result = matcher.compare(1.0000001, 1); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeLessThanSpec.js000066400000000000000000000010161416413636100223400ustar00rootroot00000000000000describe('toBeLessThan', function() { it('passes when actual < expected', function() { var matcher = jasmineUnderTest.matchers.toBeLessThan(), result; result = matcher.compare(1, 2); expect(result.pass).toBe(true); }); it('fails when actual <= expected', function() { var matcher = jasmineUnderTest.matchers.toBeLessThan(), result; result = matcher.compare(1, 1); expect(result.pass).toBe(false); result = matcher.compare(2, 1); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeNaNSpec.js000066400000000000000000000021221416413636100212720ustar00rootroot00000000000000describe('toBeNaN', function() { it('passes for NaN with a custom .not fail', function() { var matcher = jasmineUnderTest.matchers.toBeNaN(), result; result = matcher.compare(Number.NaN); expect(result.pass).toBe(true); expect(result.message).toEqual('Expected actual not to be NaN.'); }); it('fails for anything not a NaN', function() { var matcher = jasmineUnderTest.matchers.toBeNaN(), result; result = matcher.compare(1); expect(result.pass).toBe(false); result = matcher.compare(null); expect(result.pass).toBe(false); result = matcher.compare(void 0); expect(result.pass).toBe(false); result = matcher.compare(''); expect(result.pass).toBe(false); result = matcher.compare(Number.POSITIVE_INFINITY); expect(result.pass).toBe(false); }); it('has a custom message on failure', function() { var matcher = jasmineUnderTest.matchers.toBeNaN({ pp: jasmineUnderTest.makePrettyPrinter() }), result = matcher.compare(0); expect(result.message()).toEqual('Expected 0 to be NaN.'); }); }); jasmine-4.0.0/spec/core/matchers/toBeNegativeInfinitySpec.js000066400000000000000000000017551416413636100241050ustar00rootroot00000000000000describe('toBeNegativeInfinity', function() { it("fails for anything that isn't -Infinity", function() { var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity(), result; result = matcher.compare(1); expect(result.pass).toBe(false); result = matcher.compare(Number.NaN); expect(result.pass).toBe(false); result = matcher.compare(null); expect(result.pass).toBe(false); }); it('has a custom message on failure', function() { var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity({ pp: jasmineUnderTest.makePrettyPrinter() }), result = matcher.compare(0); expect(result.message()).toEqual('Expected 0 to be -Infinity.'); }); it('succeeds for -Infinity', function() { var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity(), result = matcher.compare(Number.NEGATIVE_INFINITY); expect(result.pass).toBe(true); expect(result.message).toEqual('Expected actual not to be -Infinity.'); }); }); jasmine-4.0.0/spec/core/matchers/toBeNullSpec.js000066400000000000000000000006401416413636100215330ustar00rootroot00000000000000describe('toBeNull', function() { it('passes for null', function() { var matcher = jasmineUnderTest.matchers.toBeNull(), result; result = matcher.compare(null); expect(result.pass).toBe(true); }); it('fails for non-null', function() { var matcher = jasmineUnderTest.matchers.toBeNull(), result; result = matcher.compare('foo'); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBePositiveInfinitySpec.js000066400000000000000000000017511416413636100241410ustar00rootroot00000000000000describe('toBePositiveInfinity', function() { it("fails for anything that isn't Infinity", function() { var matcher = jasmineUnderTest.matchers.toBePositiveInfinity(), result; result = matcher.compare(1); expect(result.pass).toBe(false); result = matcher.compare(Number.NaN); expect(result.pass).toBe(false); result = matcher.compare(null); expect(result.pass).toBe(false); }); it('has a custom message on failure', function() { var matcher = jasmineUnderTest.matchers.toBePositiveInfinity({ pp: jasmineUnderTest.makePrettyPrinter() }), result = matcher.compare(0); expect(result.message()).toEqual('Expected 0 to be Infinity.'); }); it('succeeds for Infinity', function() { var matcher = jasmineUnderTest.matchers.toBePositiveInfinity(), result = matcher.compare(Number.POSITIVE_INFINITY); expect(result.pass).toBe(true); expect(result.message).toEqual('Expected actual not to be Infinity.'); }); }); jasmine-4.0.0/spec/core/matchers/toBeSpec.js000066400000000000000000000065441416413636100207110ustar00rootroot00000000000000describe('toBe', function() { it('passes with no message when actual === expected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result; result = matcher.compare(1, 1); expect(result.pass).toBe(true); }); it('passes with a custom message when expected is an array', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result, array = [1]; result = matcher.compare(array, array); expect(result.pass).toBe(true); expect(result.message).toBe( 'Expected [ 1 ] not to be [ 1 ]. Tip: To check for deep equality, use .toEqual() instead of .toBe().' ); }); it('passes with a custom message when expected is an object', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result, obj = { foo: 'bar' }; result = matcher.compare(obj, obj); expect(result.pass).toBe(true); expect(result.message).toBe( "Expected Object({ foo: 'bar' }) not to be Object({ foo: 'bar' }). Tip: To check for deep equality, use .toEqual() instead of .toBe()." ); }); it('fails with no message when actual !== expected', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result; result = matcher.compare(1, 2); expect(result.pass).toBe(false); expect(result.message).toBeUndefined(); }); it('fails with a custom message when expected is an array', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result; result = matcher.compare([1], [1]); expect(result.pass).toBe(false); expect(result.message).toBe( 'Expected [ 1 ] to be [ 1 ]. Tip: To check for deep equality, use .toEqual() instead of .toBe().' ); }); it('fails with a custom message when expected is an object', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result; result = matcher.compare({ foo: 'bar' }, { foo: 'bar' }); expect(result.pass).toBe(false); expect(result.message).toBe( "Expected Object({ foo: 'bar' }) to be Object({ foo: 'bar' }). Tip: To check for deep equality, use .toEqual() instead of .toBe()." ); }); it('works with custom object formatters when expected is an object', function() { var formatter = function(x) { return '<' + x.foo + '>'; }, prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: prettyPrinter }), matcher = jasmineUnderTest.matchers.toBe(matchersUtil), result; result = matcher.compare({ foo: 'bar' }, { foo: 'bar' }); expect(result.pass).toBe(false); expect(result.message).toBe( 'Expected to be . Tip: To check for deep equality, use .toEqual() instead of .toBe().' ); }); }); jasmine-4.0.0/spec/core/matchers/toBeTrueSpec.js000066400000000000000000000006401416413636100215400ustar00rootroot00000000000000describe('toBeTrue', function() { it('passes for true', function() { var matcher = jasmineUnderTest.matchers.toBeTrue(), result; result = matcher.compare(true); expect(result.pass).toBe(true); }); it('fails for non-true', function() { var matcher = jasmineUnderTest.matchers.toBeTrue(), result; result = matcher.compare('foo'); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeTruthySpec.js000066400000000000000000000022331416413636100221200ustar00rootroot00000000000000describe('toBeTruthy', function() { it("passes for 'truthy' values", function() { var matcher = jasmineUnderTest.matchers.toBeTruthy(), result; result = matcher.compare(true); expect(result.pass).toBe(true); result = matcher.compare(1); expect(result.pass).toBe(true); result = matcher.compare('foo'); expect(result.pass).toBe(true); result = matcher.compare({}); expect(result.pass).toBe(true); result = matcher.compare([]); expect(result.pass).toBe(true); result = matcher.compare(function() {}); expect(result.pass).toBe(true); }); it("fails for 'falsy' values", function() { var matcher = jasmineUnderTest.matchers.toBeTruthy(), result; result = matcher.compare(false); expect(result.pass).toBe(false); result = matcher.compare(0); expect(result.pass).toBe(false); result = matcher.compare(''); expect(result.pass).toBe(false); result = matcher.compare(null); expect(result.pass).toBe(false); result = matcher.compare(undefined); expect(result.pass).toBe(false); result = matcher.compare(void 0); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toBeUndefinedSpec.js000066400000000000000000000007151416413636100225250ustar00rootroot00000000000000describe('toBeUndefined', function() { it('passes for undefined values', function() { var matcher = jasmineUnderTest.matchers.toBeUndefined(), result; result = matcher.compare(void 0); expect(result.pass).toBe(true); }); it('fails when matching defined values', function() { var matcher = jasmineUnderTest.matchers.toBeUndefined(), result; result = matcher.compare('foo'); expect(result.pass).toBe(false); }); }); jasmine-4.0.0/spec/core/matchers/toContainSpec.js000066400000000000000000000015521416413636100217500ustar00rootroot00000000000000describe('toContain', function() { it('delegates to jasmineUnderTest.matchersUtil.contains', function() { var matchersUtil = { contains: jasmine.createSpy('delegated-contains').and.returnValue(true) }, matcher = jasmineUnderTest.matchers.toContain(matchersUtil), result; result = matcher.compare('ABC', 'B'); expect(matchersUtil.contains).toHaveBeenCalledWith('ABC', 'B'); expect(result.pass).toBe(true); }); it('works with custom equality testers', function() { var tester = function(a, b) { return a.toString() === b.toString(); }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }), matcher = jasmineUnderTest.matchers.toContain(matchersUtil), result; result = matcher.compare(['1', '2'], 2); expect(result.pass).toBe(true); }); }); jasmine-4.0.0/spec/core/matchers/toEqualSpec.js000066400000000000000000001051341416413636100214250ustar00rootroot00000000000000describe('toEqual', function() { 'use strict'; function compareEquals(actual, expected) { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil); var result = matcher.compare(actual, expected); return result; } it('delegates to equals function', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equals').and.returnValue(true), buildFailureMessage: function() { return 'does not matter'; }, DiffBuilder: new jasmineUnderTest.DiffBuilder() }, matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), result; result = matcher.compare(1, 1); expect(matchersUtil.equals).toHaveBeenCalledWith(1, 1, jasmine.anything()); expect(result.pass).toBe(true); }); it('works with custom equality testers', function() { var tester = function(a, b) { return a.toString() === b.toString(); }, matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), result; result = matcher.compare(1, '1'); expect(result.pass).toBe(true); }); it('reports the difference between objects that are not equal', function() { var actual = { x: 1, y: 3 }, expected = { x: 2, y: 3 }, message = 'Expected $.x = 1 to equal 2.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports the difference between nested objects that are not equal', function() { var actual = { x: { y: 1 } }, expected = { x: { y: 2 } }, message = 'Expected $.x.y = 1 to equal 2.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it("formats property access so that it's valid JavaScript", function() { var actual = { 'my prop': 1 }, expected = { 'my prop': 2 }, message = "Expected $['my prop'] = 1 to equal 2."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports missing properties', function() { var actual = { x: {} }, expected = { x: { y: 1 } }, message = 'Expected $.x to have properties\n' + ' y: 1'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports extra properties', function() { var actual = { x: { y: 1, z: 2 } }, expected = { x: {} }, message = 'Expected $.x not to have properties\n' + ' y: 1\n' + ' z: 2'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('pretty-prints properties', function() { var actual = { x: { y: 'foo bar' } }, expected = { x: {} }, message = 'Expected $.x not to have properties\n' + " y: 'foo bar'"; expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses custom object formatters to pretty-print simple properties', function() { function formatter(x) { if (typeof x === 'number') { return '|' + x + '|'; } } var actual = { x: { y: 1, z: 2, f: 4 } }, expected = { x: { y: 1, z: 2, g: 3 } }, pp = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), message = 'Expected $.x to have properties\n' + ' g: |3|\n' + 'Expected $.x not to have properties\n' + ' f: |4|'; expect(matcher.compare(actual, expected).message).toEqual(message); }); it('uses custom object formatters to show simple values in diffs', function() { function formatter(x) { if (typeof x === 'number') { return '|' + x + '|'; } } var actual = [{ foo: 4 }], expected = [{ foo: 5 }], prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: prettyPrinter }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), message = 'Expected $[0].foo = |4| to equal |5|.'; expect(matcher.compare(actual, expected).message).toEqual(message); }); it('uses custom object formatters to show more complex objects diffs', function() { function formatter(x) { if (x.hasOwnProperty('a')) { return '[thing with a=' + x.a + ', b=' + x.b + ']'; } } var actual = [ { foo: { a: 1, b: 2 }, bar: 'should not be pretty printed' } ], expected = [ { foo: { a: 5, b: 2 }, bar: "shouldn't be pretty printed" } ], prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: prettyPrinter }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), message = 'Expected $[0].foo = [thing with a=1, b=2] to equal [thing with a=5, b=2].\n' + "Expected $[0].bar = 'should not be pretty printed' to equal 'shouldn't be pretty printed'."; expect(matcher.compare(actual, expected).message).toEqual(message); }); it('reports extra and missing properties of the root-level object', function() { var actual = { x: 1 }, expected = { a: 1 }, message = 'Expected object to have properties\n' + ' a: 1\n' + 'Expected object not to have properties\n' + ' x: 1'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports multiple incorrect values', function() { var actual = { x: 1, y: 2 }, expected = { x: 3, y: 4 }, message = 'Expected $.x = 1 to equal 3.\n' + 'Expected $.y = 2 to equal 4.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatch between actual child object and expected child number', function() { var actual = { x: { y: 2 } }, expected = { x: 1 }, message = 'Expected $.x = Object({ y: 2 }) to equal 1.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses the default failure message if actual is not an object', function() { var actual = 1, expected = { x: {} }, message = 'Expected 1 to equal Object({ x: Object({ }) }).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses the default failure message if expected is not an object', function() { var actual = { x: {} }, expected = 1, message = 'Expected Object({ x: Object({ }) }) to equal 1.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses the default failure message given arrays with different lengths', function() { var actual = [1, 2], expected = [1, 2, 3], message = 'Expected $.length = 2 to equal 3.\n' + 'Expected $[2] = undefined to equal 3.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports a mismatch between elements of equal-length arrays', function() { var actual = [1, 2, 5], expected = [1, 2, 3], message = 'Expected $[2] = 5 to equal 3.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports a mismatch between multiple array elements', function() { var actual = [2, 2, 5], expected = [1, 2, 3], message = 'Expected $[0] = 2 to equal 1.\n' + 'Expected $[2] = 5 to equal 3.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports a mismatch between properties of objects in arrays', function() { var actual = [{ x: 1 }], expected = [{ x: 2 }], message = 'Expected $[0].x = 1 to equal 2.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports a mismatch between arrays in objects', function() { var actual = { x: [1] }, expected = { x: [2] }, message = 'Expected $.x[0] = 1 to equal 2.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between nested arrays', function() { var actual = [[1]], expected = [[2]], message = 'Expected $[0][0] = 1 to equal 2.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between arrays of different types', function() { var actual = new Uint32Array([1, 2, 3]), expected = new Uint16Array([1, 2, 3]), message = 'Expected Uint32Array [ 1, 2, 3 ] to equal Uint16Array [ 1, 2, 3 ].'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving NaN', function() { var actual = { x: 0 }, expected = { x: 0 / 0 }, message = 'Expected $.x = 0 to equal NaN.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving regular expressions', function() { var actual = { x: '1' }, expected = { x: /1/ }, message = "Expected $.x = '1' to equal /1/."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving infinities', function() { var actual = { x: 0 }, expected = { x: 1 / 0 }, message = 'Expected $.x = 0 to equal Infinity.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving booleans', function() { var actual = { x: false }, expected = { x: true }, message = 'Expected $.x = false to equal true.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving strings', function() { var actual = { x: 'foo' }, expected = { x: 'bar' }, message = "Expected $.x = 'foo' to equal 'bar'."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving undefined', function() { var actual = { x: void 0 }, expected = { x: 0 }, message = 'Expected $.x = undefined to equal 0.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches involving null', function() { var actual = { x: null }, expected = { x: 0 }, message = 'Expected $.x = null to equal 0.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between objects with different constructors', function() { function Foo() {} function Bar() {} var actual = { x: new Foo() }, expected = { x: new Bar() }, message = 'Expected $.x to be a kind of Bar, but was Foo({ }).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses custom object formatters for the value but not the type when reporting objects with different constructors', function() { function Foo() {} function Bar() {} function formatter(x) { if (x instanceof Foo || x instanceof Bar) { return '|' + x + '|'; } } var actual = { x: new Foo() }, expected = { x: new Bar() }, message = 'Expected $.x to be a kind of Bar, but was |[object Object]|.', pp = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil); expect(matcher.compare(actual, expected).message).toEqual(message); }); it('reports type mismatches at the root level', function() { function Foo() {} function Bar() {} var actual = new Foo(), expected = new Bar(), message = 'Expected object to be a kind of Bar, but was Foo({ }).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports value mismatches at the root level', function() { expect(compareEquals(1, 2).message).toEqual('Expected 1 to equal 2.'); }); it('reports mismatches between objects with their own constructor property', function() { function Foo() {} function Bar() {} var actual = { x: { constructor: 'blerf' } }, expected = { x: { constructor: 'ftarrh' } }, message = "Expected $.x.constructor = 'blerf' to equal 'ftarrh'."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between an object with a real constructor and one with its own constructor property', function() { function Foo() {} function Bar() {} var actual = { x: {} }, expected = { x: { constructor: 'ftarrh' } }, message = 'Expected $.x to have properties\n' + " constructor: 'ftarrh'"; expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(expected, actual).message).toEqual( "Expected $.x not to have properties\n constructor: 'ftarrh'" ); }); it('reports mismatches between 0 and -0', function() { var actual = { x: 0 }, expected = { x: -0 }, message = 'Expected $.x = 0 to equal -0.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between 0 and Number.MIN_VALUE', function() { var actual = { x: 0 }, expected = { x: Number.MIN_VALUE }, message = 'Expected $.x = 0 to equal 5e-324.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Errors', function() { var actual = { x: new Error('the error you got') }, expected = { x: new Error('the error you want') }, message = 'Expected $.x = Error: the error you got to equal Error: the error you want.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Functions', function() { var actual = { x: function() {} }, expected = { x: function() {} }, message = 'Expected $.x = Function to equal Function.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between an object and objectContaining', function() { var actual = { a: 1, b: 4, c: 3, extra: 'ignored' }; var expected = jasmineUnderTest.objectContaining({ a: 1, b: 2, c: 3, d: 4 }); expect(compareEquals(actual, expected).message).toEqual( 'Expected $.b = 4 to equal 2.\n' + 'Expected $.d = undefined to equal 4.' ); }); it('reports mismatches between a non-object and objectContaining', function() { var actual = 1; var expected = jasmineUnderTest.objectContaining({ a: 1 }); expect(compareEquals(actual, expected).message).toEqual( "Expected 1 to equal ''." ); }); it('reports mismatches involving a nested objectContaining', function() { var actual = { x: { a: 1, b: 4, c: 3, extra: 'ignored' } }; var expected = { x: jasmineUnderTest.objectContaining({ a: 1, b: 2, c: 3, d: 4 }) }; expect(compareEquals(actual, expected).message).toEqual( 'Expected $.x.b = 4 to equal 2.\n' + 'Expected $.x.d = undefined to equal 4.' ); }); // == Sets == it('reports mismatches between Sets', function() { var actual = new Set(); actual.add(1); var expected = new Set(); expected.add(2); var message = 'Expected Set( 1 ) to equal Set( 2 ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports deep mismatches within Sets', function() { var actual = new Set(); actual.add({ x: 1 }); var expected = new Set(); expected.add({ x: 2 }); var message = 'Expected Set( Object({ x: 1 }) ) to equal Set( Object({ x: 2 }) ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Sets nested in objects', function() { var actualSet = new Set(); actualSet.add(1); var expectedSet = new Set(); expectedSet.add(2); var actual = { sets: [actualSet] }; var expected = { sets: [expectedSet] }; var message = 'Expected $.sets[0] = Set( 1 ) to equal Set( 2 ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Sets of different lengths', function() { var actual = new Set(); actual.add(1); actual.add(2); var expected = new Set(); expected.add(2); var message = 'Expected Set( 1, 2 ) to equal Set( 2 ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Sets where actual is missing a value from expected', function() { // Use 'duplicate' object in actual so sizes match var actual = new Set(); actual.add({ x: 1 }); actual.add({ x: 1 }); var expected = new Set(); expected.add({ x: 1 }); expected.add({ x: 2 }); var message = 'Expected Set( Object({ x: 1 }), Object({ x: 1 }) ) to equal Set( Object({ x: 1 }), Object({ x: 2 }) ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Sets where actual has a value missing from expected', function() { // Use 'duplicate' object in expected so sizes match var actual = new Set(); actual.add({ x: 1 }); actual.add({ x: 2 }); var expected = new Set(); expected.add({ x: 1 }); expected.add({ x: 1 }); var message = 'Expected Set( Object({ x: 1 }), Object({ x: 2 }) ) to equal Set( Object({ x: 1 }), Object({ x: 1 }) ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); // == Maps == it('does not report mismatches between deep equal Maps', function() { // values are the same but with different object identity var actual = new Map(); actual.set('a', { x: 1 }); var expected = new Map(); expected.set('a', { x: 1 }); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports deep mismatches within Maps', function() { var actual = new Map(); actual.set('a', { x: 1 }); var expected = new Map(); expected.set('a', { x: 2 }); var message = "Expected Map( [ 'a', Object({ x: 1 }) ] ) to equal Map( [ 'a', Object({ x: 2 }) ] )."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Maps nested in objects', function() { var actual = { Maps: [new Map()] }; actual.Maps[0].set('a', 1); var expected = { Maps: [new Map()] }; expected.Maps[0].set('a', 2); var message = "Expected $.Maps[0] = Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] )."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Maps of different lengths', function() { var actual = new Map(); actual.set('a', 1); var expected = new Map(); expected.set('a', 2); expected.set('b', 1); var message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ], [ 'b', 1 ] )."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between Maps with equal values but differing keys', function() { var actual = new Map(); actual.set('a', 1); var expected = new Map(); expected.set('b', 1); var message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'b', 1 ] )."; expect(compareEquals(actual, expected).message).toEqual(message); }); it('does not report mismatches between Maps with keys with same object identity', function() { var key = { x: 1 }; var actual = new Map(); actual.set(key, 2); var expected = new Map(); expected.set(key, 2); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports mismatches between Maps with identical keys with different object identity', function() { var actual = new Map(); actual.set({ x: 1 }, 2); var expected = new Map(); expected.set({ x: 1 }, 2); var message = 'Expected Map( [ Object({ x: 1 }), 2 ] ) to equal Map( [ Object({ x: 1 }), 2 ] ).'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('does not report mismatches when comparing Map key to jasmine.anything()', function() { var actual = new Map(); actual.set('a', 1); var expected = new Map(); expected.set(jasmineUnderTest.anything(), 1); expect(compareEquals(actual, expected).pass).toBe(true); }); it('does not report mismatches when comparing Maps with the same symbol keys', function() { var key = Symbol(); var actual = new Map(); actual.set(key, 1); var expected = new Map(); expected.set(key, 1); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports mismatches between Maps with different symbol keys', function() { var actual = new Map(); actual.set(Symbol(), 1); var expected = new Map(); expected.set(Symbol(), 1); var message = 'Expected Map( [ Symbol(), 1 ] ) to equal Map( [ Symbol(), 1 ] ).'; expect(compareEquals(actual, expected).message).toBe(message); }); it('does not report mismatches when comparing Map symbol key to jasmine.anything()', function() { var actual = new Map(); actual.set(Symbol(), 1); var expected = new Map(); expected.set(jasmineUnderTest.anything(), 1); expect(compareEquals(actual, expected).pass).toBe(true); }); describe('DOM nodes', function() { function isNotRunningInBrowser() { return typeof document === 'undefined'; } beforeEach(function() { this.nonBrowser = isNotRunningInBrowser(); if (this.nonBrowser) { var JSDOM = require('jsdom').JSDOM; var dom = new JSDOM(); jasmineUnderTest.getGlobal().Node = dom.window.Node; this.doc = dom.window.document; } else { this.doc = document; } }); afterEach(function() { if (this.nonBrowser) { delete jasmineUnderTest.getGlobal().Node; } }); it('reports mismatches between DOM nodes with different tags', function() { var actual = { a: this.doc.createElement('div') }, expected = { a: this.doc.createElement('p') }, message = 'Expected $.a =
to equal

.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between DOM nodes with different content', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.setAttribute('thing', 'foo'); nodeB.setAttribute('thing', 'bar'); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =

to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between SVG nodes', function() { var nodeA = this.doc.createElementNS('http://www.w3.org/2000/svg', 'svg'), nodeB = this.doc.createElementNS('http://www.w3.org/2000/svg', 'svg'); nodeA.setAttribute('height', '50'); nodeB.setAttribute('height', '30'); var rect = this.doc.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('width', '50'); nodeA.appendChild(rect); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a = ... to equal .'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports whole DOM node when attribute contains > character', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.setAttribute('thing', '>>>'); nodeB.setAttribute('thing', 'bar'); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =
to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports no content when DOM node has multiple empty text nodes', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.appendChild(this.doc.createTextNode('')); nodeA.appendChild(this.doc.createTextNode('')); nodeA.appendChild(this.doc.createTextNode('')); nodeA.appendChild(this.doc.createTextNode('')); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =
to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports content when DOM node has non empty text node', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.appendChild(this.doc.createTextNode('Hello Jasmine!')); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =
...
to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports empty DOM attributes', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.setAttribute('contenteditable', ''); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =
to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports 0 attr value as non empty DOM attribute', function() { var nodeA = this.doc.createElement('div'), nodeB = this.doc.createElement('div'); nodeA.setAttribute('contenteditable', 0); expect(nodeA.isEqualNode(nodeB)).toBe(false); var actual = { a: nodeA }, expected = { a: nodeB }, message = 'Expected $.a =
to equal
.'; expect(compareEquals(actual, expected).message).toEqual(message); }); it('reports mismatches between a DOM node and a bare Object', function() { var actual = { a: this.doc.createElement('div') }, expected = { a: {} }, message = 'Expected $.a =
to equal Object({ }).'; expect(compareEquals(actual, expected).message).toEqual(message); }); }); it('reports asymmetric mismatches', function() { var actual = { a: 1 }, expected = { a: jasmineUnderTest.any(String) }, message = 'Expected $.a = 1 to equal .'; expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).pass).toBe(false); }); it('reports asymmetric mismatches when the asymmetric comparand is the actual value', function() { var actual = { a: jasmineUnderTest.any(String) }, expected = { a: 1 }, message = 'Expected $.a = to equal 1.'; expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).pass).toBe(false); }); it('does not report a mismatch when asymmetric matchers are satisfied', function() { var actual = { a: 'a' }, expected = { a: jasmineUnderTest.any(String) }; expect(compareEquals(actual, expected).message).toEqual(''); expect(compareEquals(actual, expected).pass).toBe(true); }); it('works on big complex stuff', function() { var actual = { foo: [{ bar: 1, things: ['a', 'b'] }, { bar: 2, things: ['a', 'b'] }], baz: [{ a: { b: 1 } }], quux: 1, nan: 0, aRegexp: 'hi', inf: -1 / 0, boolean: false, notDefined: 0, aNull: void 0 }; var expected = { foo: [ { bar: 2, things: ['a', 'b', 'c'] }, { bar: 2, things: ['a', 'd'] } ], baz: [{ a: { b: 1, c: 1 } }], quux: [], nan: 0 / 0, aRegexp: /hi/, inf: 1 / 0, boolean: true, notDefined: void 0, aNull: null }; var message = 'Expected $.foo[0].bar = 1 to equal 2.\n' + 'Expected $.foo[0].things.length = 2 to equal 3.\n' + "Expected $.foo[0].things[2] = undefined to equal 'c'.\n" + "Expected $.foo[1].things[1] = 'b' to equal 'd'.\n" + 'Expected $.baz[0].a to have properties\n' + ' c: 1\n' + 'Expected $.quux = 1 to equal [ ].\n' + 'Expected $.nan = 0 to equal NaN.\n' + "Expected $.aRegexp = 'hi' to equal /hi/.\n" + 'Expected $.inf = -Infinity to equal Infinity.\n' + 'Expected $.boolean = false to equal true.\n' + 'Expected $.notDefined = 0 to equal undefined.\n' + 'Expected $.aNull = undefined to equal null.'; expect(compareEquals(actual, expected).message).toEqual(message); }); describe('different length arrays', function() { it('actual array is longer', function() { var actual = [1, 1, 2, 3, 5], expected = [1, 1, 2, 3], message = 'Expected $.length = 5 to equal 4.\n' + 'Unexpected $[4] = 5 in array.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('uses custom object formatters when the actual array is longer', function() { function formatter(x) { if (typeof x === 'number') { return '|' + x + '|'; } } var actual = [1, 1, 2, 3, 5], expected = [1, 1, 2, 3], pp = jasmineUnderTest.makePrettyPrinter([formatter]), matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toEqual(matchersUtil), message = 'Expected $.length = |5| to equal |4|.\n' + 'Unexpected $[4] = |5| in array.'; expect(matcher.compare(actual, expected).message).toEqual(message); }); it('expected array is longer', function() { var actual = [1, 1, 2, 3], expected = [1, 1, 2, 3, 5], message = 'Expected $.length = 4 to equal 5.\n' + 'Expected $[4] = undefined to equal 5.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('undefined in middle of actual array', function() { var actual = [1, void 0, 3], expected = [1, 2, 3], message = 'Expected $[1] = undefined to equal 2.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('undefined in middle of expected array', function() { var actual = [1, 2, 3], expected = [1, void 0, 3], message = 'Expected $[1] = 2 to equal undefined.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('actual array is longer by 4 elements', function() { var actual = [1, 1, 2, 3, 5, 8, 13], expected = [1, 1, 2], message = 'Expected $.length = 7 to equal 3.\n' + 'Unexpected $[3] = 3 in array.\n' + 'Unexpected $[4] = 5 in array.\n' + 'Unexpected $[5] = 8 in array.\n' + 'Unexpected $[6] = 13 in array.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('expected array is longer by 4 elements', function() { var actual = [1, 1, 2], expected = [1, 1, 2, 3, 5, 8, 13], message = 'Expected $.length = 3 to equal 7.\n' + 'Expected $[3] = undefined to equal 3.\n' + 'Expected $[4] = undefined to equal 5.\n' + 'Expected $[5] = undefined to equal 8.\n' + 'Expected $[6] = undefined to equal 13.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('different length and different elements', function() { var actual = [1], expected = [2, 3], message = 'Expected $.length = 1 to equal 2.\n' + 'Expected $[0] = 1 to equal 2.\n' + 'Expected $[1] = undefined to equal 3.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('object with nested array (actual longer than expected)', function() { var actual = { values: [1, 1, 2, 3] }, expected = { values: [1, 1, 2] }, message = 'Expected $.values.length = 4 to equal 3.\n' + 'Unexpected $.values[3] = 3 in array.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('object with nested array (expected longer than actual)', function() { var actual = { values: [1, 1, 2] }, expected = { values: [1, 1, 2, 3] }, message = 'Expected $.values.length = 3 to equal 4.\n' + 'Expected $.values[3] = undefined to equal 3.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('array with unexpected nested object', function() { var actual = [1, 1, 2, { value: 3 }], expected = [1, 1, 2], message = 'Expected $.length = 4 to equal 3.\n' + 'Unexpected $[3] = Object({ value: 3 }) in array.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('array with missing nested object', function() { var actual = [1, 1, 2], expected = [1, 1, 2, { value: 3 }], message = 'Expected $.length = 3 to equal 4.\n' + 'Expected $[3] = undefined to equal Object({ value: 3 }).'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('array with nested different length array', function() { var actual = [[1], [1, 2]], expected = [[1, 1], [2]], message = 'Expected $[0].length = 1 to equal 2.\n' + 'Expected $[0][1] = undefined to equal 1.\n' + 'Expected $[1].length = 2 to equal 1.\n' + 'Expected $[1][0] = 1 to equal 2.\n' + 'Unexpected $[1][1] = 2 in array.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); it('last element of longer array is undefined', function() { var actual = [1, 2], expected = [1, 2, void 0], message = 'Expected $.length = 2 to equal 3.'; expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).message).toEqual(message); }); }); }); jasmine-4.0.0/spec/core/matchers/toHaveBeenCalledBeforeSpec.js000066400000000000000000000077001416413636100242630ustar00rootroot00000000000000describe('toHaveBeenCalledBefore', function() { it('throws an exception when the actual is not a spy', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() {}, spy = new jasmineUnderTest.Env().createSpy('a spy'); expect(function() { matcher.compare(fn, spy); }).toThrowError(Error, /Expected a spy, but got Function./); }); it('throws an exception when the expected is not a spy', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore({ pp: jasmineUnderTest.makePrettyPrinter() }), spy = new jasmineUnderTest.Env().createSpy('a spy'), fn = function() {}; expect(function() { matcher.compare(spy, fn); }).toThrowError(Error, /Expected a spy, but got Function./); }); it('fails when the actual was not called', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'); secondSpy(); const result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toMatch( /Expected spy first spy to have been called./ ); }); it('fails when the expected was not called', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'); firstSpy(); const result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toMatch( /Expected spy second spy to have been called./ ); }); it('fails when the actual is called after the expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'), result; secondSpy(); firstSpy(); result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toEqual( 'Expected spy first spy to have been called before spy second spy' ); }); it('fails when the actual is called before and after the expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'), result; firstSpy(); secondSpy(); firstSpy(); result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toEqual( 'Expected latest call to spy first spy to have been called before first call to spy second spy (no interleaved calls)' ); }); it('fails when the expected is called before and after the actual', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'), result; secondSpy(); firstSpy(); secondSpy(); result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toEqual( 'Expected first call to spy second spy to have been called after latest call to spy first spy (no interleaved calls)' ); }); it('passes when the actual is called before the expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(), firstSpy = new jasmineUnderTest.Spy('first spy'), secondSpy = new jasmineUnderTest.Spy('second spy'), result; firstSpy(); secondSpy(); result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(true); expect(result.message).toEqual( 'Expected spy first spy to not have been called before spy second spy, but it was' ); }); }); jasmine-4.0.0/spec/core/matchers/toHaveBeenCalledOnceWithSpec.js000066400000000000000000000104721416413636100246010ustar00rootroot00000000000000describe('toHaveBeenCalledOnceWith', function() { it('passes when the actual was called only once and with matching parameters', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(true); expect(result.message).toEqual( "Expected spy called-spy to have been called 0 times, multiple times, or once, but with arguments different from:\n [ 'a', 'b' ]\nBut the actual call was:\n [ 'a', 'b' ].\n\n" ); }); it('supports custom equality testers', function() { var customEqualityTesters = [ function() { return true; } ], matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: customEqualityTesters }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith( matchersUtil ), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); result = matcher.compare(calledSpy, 'a', 'a'); expect(result.pass).toBe(true); }); it('fails when the actual was never called', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(false); expect(result.message).toEqual( "Expected spy called-spy to have been called only once, and with given args:\n [ 'a', 'b' ]\nBut it was never called.\n\n" ); }); it('fails when the actual was called once with different parameters', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'c'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(false); expect(result.message).toEqual( "Expected spy called-spy to have been called only once, and with given args:\n [ 'a', 'b' ]\nBut the actual call was:\n [ 'a', 'c' ].\nExpected $[1] = 'c' to equal 'b'.\n\n" ); }); it('fails when the actual was called multiple times with expected parameters', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); calledSpy('a', 'b'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(false); expect(result.message).toEqual( "Expected spy called-spy to have been called only once, and with given args:\n [ 'a', 'b' ]\nBut the actual calls were:\n [ 'a', 'b' ],\n [ 'a', 'b' ].\n\n" ); }); it('fails when the actual was called multiple times (one of them - with expected parameters)', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); calledSpy('a', 'c'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(false); expect(result.message).toEqual( "Expected spy called-spy to have been called only once, and with given args:\n [ 'a', 'b' ]\nBut the actual calls were:\n [ 'a', 'b' ],\n [ 'a', 'c' ].\n\n" ); }); it('throws an exception when the actual is not a spy', function() { var pp = jasmineUnderTest.makePrettyPrinter(), util = new jasmineUnderTest.MatchersUtil({ pp: pp }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledOnceWith(util), fn = function() {}; expect(function() { matcher.compare(fn); }).toThrowError(/Expected a spy, but got Function./); }); }); jasmine-4.0.0/spec/core/matchers/toHaveBeenCalledSpec.js000066400000000000000000000033401416413636100231340ustar00rootroot00000000000000describe('toHaveBeenCalled', function() { it('passes when the actual was called, with a custom .not fail message', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalled(), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy(); result = matcher.compare(calledSpy); expect(result.pass).toBe(true); expect(result.message).toEqual( 'Expected spy called-spy not to have been called.' ); }); it('fails when the actual was not called', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalled(), uncalledSpy = new jasmineUnderTest.Spy('uncalled spy'), result; result = matcher.compare(uncalledSpy); expect(result.pass).toBe(false); }); it('throws an exception when the actual is not a spy', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalled({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() {}; expect(function() { matcher.compare(fn); }).toThrowError(Error, /Expected a spy, but got Function./); }); it('throws an exception when invoked with any arguments', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalled(), spy = new jasmineUnderTest.Spy('sample spy'); expect(function() { matcher.compare(spy, 'foo'); }).toThrowError(Error, /Does not take arguments, use toHaveBeenCalledWith/); }); it('has a custom message on failure', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalled(), spy = new jasmineUnderTest.Spy('sample-spy'), result; result = matcher.compare(spy); expect(result.message).toEqual( 'Expected spy sample-spy to have been called.' ); }); }); jasmine-4.0.0/spec/core/matchers/toHaveBeenCalledTimesSpec.js000066400000000000000000000056221416413636100241430ustar00rootroot00000000000000describe('toHaveBeenCalledTimes', function() { it('passes when the actual 0 matches the expected 0 ', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; result = matcher.compare(calledSpy, 0); expect(result.pass).toBeTruthy(); }); it('passes when the actual matches the expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy(); result = matcher.compare(calledSpy, 1); expect(result.pass).toBe(true); }); it('fails when expected numbers is not supplied', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), spy = new jasmineUnderTest.Spy('spy'), result; spy(); expect(function() { matcher.compare(spy); }).toThrowError( /The expected times failed is a required argument and must be a number./ ); }); it('fails when the actual was called less than the expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), uncalledSpy = new jasmineUnderTest.Spy('uncalled spy'), result; result = matcher.compare(uncalledSpy, 2); expect(result.pass).toBe(false); }); it('fails when the actual was called more than expected', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), uncalledSpy = new jasmineUnderTest.Spy('uncalled spy'), result; uncalledSpy(); uncalledSpy(); result = matcher.compare(uncalledSpy, 1); expect(result.pass).toBe(false); }); it('throws an exception when the actual is not a spy', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() {}; expect(function() { matcher.compare(fn); }).toThrowError(/Expected a spy, but got Function./); }); it('has a custom message on failure that tells it was called only once', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), spy = new jasmineUnderTest.Spy('sample-spy'), result; spy(); spy(); spy(); spy(); result = matcher.compare(spy, 1); expect(result.message).toEqual( 'Expected spy sample-spy to have been called once. It was called ' + 4 + ' times.' ); }); it('has a custom message on failure that tells how many times it was called', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledTimes(), spy = new jasmineUnderTest.Spy('sample-spy'), result; spy(); spy(); spy(); spy(); result = matcher.compare(spy, 2); expect(result.message).toEqual( 'Expected spy sample-spy to have been called 2 times. It was called ' + 4 + ' times.' ); }); }); jasmine-4.0.0/spec/core/matchers/toHaveBeenCalledWithSpec.js000066400000000000000000000064251416413636100237770ustar00rootroot00000000000000describe('toHaveBeenCalledWith', function() { it('passes when the actual was called with matching parameters', function() { var matchersUtil = { contains: jasmine.createSpy('delegated-contains').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(matchersUtil), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(true); expect(result.message()).toEqual( "Expected spy called-spy not to have been called with:\n [ 'a', 'b' ]\nbut it was." ); }); it('supports custom equality testers', function() { var customEqualityTesters = [ function() { return true; } ], matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: customEqualityTesters }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(matchersUtil), calledSpy = new jasmineUnderTest.Spy('called-spy'), result; calledSpy('a', 'b'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(true); }); it('fails when the actual was not called', function() { var matchersUtil = { contains: jasmine .createSpy('delegated-contains') .and.returnValue(false), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(matchersUtil), uncalledSpy = new jasmineUnderTest.Spy('uncalled spy'), result; result = matcher.compare(uncalledSpy); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected spy uncalled spy to have been called with:\n [ ]\nbut it was never called.' ); }); it('fails when the actual was called with different parameters', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(matchersUtil), calledSpy = new jasmineUnderTest.Spy('called spy'), result; calledSpy('a'); calledSpy('c', 'd'); calledSpy('a', 'b', 'c'); result = matcher.compare(calledSpy, 'a', 'b'); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected spy called spy to have been called with:\n' + " [ 'a', 'b' ]\n" + 'but actual calls were:\n' + " [ 'a' ],\n" + " [ 'c', 'd' ],\n" + " [ 'a', 'b', 'c' ].\n\n" + 'Call 0:\n' + ' Expected $.length = 1 to equal 2.\n' + " Expected $[1] = undefined to equal 'b'.\n" + 'Call 1:\n' + " Expected $[0] = 'c' to equal 'a'.\n" + " Expected $[1] = 'd' to equal 'b'.\n" + 'Call 2:\n' + ' Expected $.length = 3 to equal 2.\n' + " Unexpected $[2] = 'c' in array." ); }); it('throws an exception when the actual is not a spy', function() { var matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() {}; expect(function() { matcher.compare(fn); }).toThrowError(/Expected a spy, but got Function./); }); }); jasmine-4.0.0/spec/core/matchers/toHaveClassSpec.js000066400000000000000000000034211416413636100222230ustar00rootroot00000000000000describe('toHaveClass', function() { beforeEach(function() { this.domHelpers = jasmine.getEnv().domHelpers(); }); it('fails for a DOM element that lacks the expected class', function() { var matcher = jasmineUnderTest.matchers.toHaveClass(), result = matcher.compare( this.domHelpers.createElementWithClassName(''), 'foo' ); expect(result.pass).toBe(false); }); it('passes for a DOM element that has the expected class', function() { var matcher = jasmineUnderTest.matchers.toHaveClass(), el = this.domHelpers.createElementWithClassName('foo bar baz'); expect(matcher.compare(el, 'foo').pass).toBe(true); expect(matcher.compare(el, 'bar').pass).toBe(true); expect(matcher.compare(el, 'bar').pass).toBe(true); }); it('fails for a DOM element that only has other classes', function() { var matcher = jasmineUnderTest.matchers.toHaveClass(), el = this.domHelpers.createElementWithClassName('foo bar'); expect(matcher.compare(el, 'fo').pass).toBe(false); }); it('throws an exception when actual is not a DOM element', function() { var matcher = jasmineUnderTest.matchers.toHaveClass({ pp: jasmineUnderTest.makePrettyPrinter() }); expect(function() { matcher.compare('x', 'foo'); }).toThrowError("'x' is not a DOM element"); expect(function() { matcher.compare(undefined, 'foo'); }).toThrowError('undefined is not a DOM element'); var textNode = this.domHelpers.document.createTextNode(''); expect(function() { matcher.compare(textNode, 'foo'); }).toThrowError('HTMLNode is not a DOM element'); expect(function() { matcher.compare({ classList: '' }, 'foo'); }).toThrowError("Object({ classList: '' }) is not a DOM element"); }); }); jasmine-4.0.0/spec/core/matchers/toHaveSizeSpec.js000066400000000000000000000072021416413636100220710ustar00rootroot00000000000000describe('toHaveSize', function() { 'use strict'; it('passes for an array whose length matches', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare([1, 2], 2); expect(result.pass).toBe(true); }); it('fails for an array whose length does not match', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare([1, 2, 3], 2); expect(result.pass).toBe(false); }); it('passes for an object with the proper number of keys', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare({ a: 1, b: 2 }, 2); expect(result.pass).toBe(true); }); it('fails for an object with a different number of keys', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare({ a: 1, b: 2 }, 1); expect(result.pass).toBe(false); }); it('passes for an object with an explicit `length` property that matches', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare({ a: 1, b: 2, length: 5 }, 5); expect(result.pass).toBe(true); }); it('fails for an object with an explicit `length` property that does not match', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare({ a: 1, b: 2, length: 5 }, 1); expect(result.pass).toBe(false); }); it('passes for a string whose length matches', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare('ab', 2); expect(result.pass).toBe(true); }); it('fails for a string whose length does not match', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare('abc', 2); expect(result.pass).toBe(false); }); it('passes for a Map whose length matches', function() { var map = new Map(); map.set('a', 1); map.set('b', 2); var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare(map, 2); expect(result.pass).toBe(true); }); it('fails for a Map whose length does not match', function() { var map = new Map(); map.set('a', 1); map.set('b', 2); var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare(map, 1); expect(result.pass).toBe(false); }); it('passes for a Set whose length matches', function() { var set = new Set(); set.add('a'); set.add('b'); var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare(set, 2); expect(result.pass).toBe(true); }); it('fails for a Set whose length does not match', function() { var set = new Set(); set.add('a'); set.add('b'); var matcher = jasmineUnderTest.matchers.toHaveSize(), result = matcher.compare(set, 1); expect(result.pass).toBe(false); }); it('throws an error for WeakSet', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { matcher.compare(new WeakSet(), 2); }).toThrowError('Cannot get size of [object WeakSet].'); }); it('throws an error for WeakMap', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { matcher.compare(new WeakMap(), 2); }).toThrowError(/Cannot get size of \[object (WeakMap|Object)\]\./); }); it('throws an error for DataView', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { matcher.compare(new DataView(new ArrayBuffer(128)), 2); }).toThrowError(/Cannot get size of \[object (DataView|Object)\]\./); }); }); jasmine-4.0.0/spec/core/matchers/toMatchSpec.js000066400000000000000000000023161416413636100214100ustar00rootroot00000000000000describe('toMatch', function() { it('passes when RegExps are equivalent', function() { var matcher = jasmineUnderTest.matchers.toMatch(), result; result = matcher.compare(/foo/, /foo/); expect(result.pass).toBe(true); }); it('fails when RegExps are not equivalent', function() { var matcher = jasmineUnderTest.matchers.toMatch(), result; result = matcher.compare(/bar/, /foo/); expect(result.pass).toBe(false); }); it('passes when the actual matches the expected string as a pattern', function() { var matcher = jasmineUnderTest.matchers.toMatch(), result; result = matcher.compare('foosball', 'foo'); expect(result.pass).toBe(true); }); it('fails when the actual matches the expected string as a pattern', function() { var matcher = jasmineUnderTest.matchers.toMatch(), result; result = matcher.compare('bar', 'foo'); expect(result.pass).toBe(false); }); it('throws an Error when the expected is not a String or RegExp', function() { var matcher = jasmineUnderTest.matchers.toMatch(); expect(function() { matcher.compare('foo', { bar: 'baz' }); }).toThrowError(/Expected is not a String or a RegExp/); }); }); jasmine-4.0.0/spec/core/matchers/toThrowErrorSpec.js000066400000000000000000000254271416413636100225010ustar00rootroot00000000000000describe('toThrowError', function() { it('throws an error when the actual is not a function', function() { var matcher = jasmineUnderTest.matchers.toThrowError(); expect(function() { matcher.compare({}); }).toThrowError(/Actual is not a Function/); }); it('throws an error when the expected is not an Error, string, or RegExp', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new Error('foo'); }; expect(function() { matcher.compare(fn, 1); }).toThrowError(/Expected is not an Error, string, or RegExp./); }); it('throws an error when the expected error type is not an Error', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new Error('foo'); }; expect(function() { matcher.compare(fn, void 0, 'foo'); }).toThrowError(/Expected error type is not an Error./); }); it('throws an error when the expected error message is not a string or RegExp', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new Error('foo'); }; expect(function() { matcher.compare(fn, Error, 1); }).toThrowError(/Expected error message is not a string or RegExp./); }); it('fails if actual does not throw at all', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { return true; }, result; result = matcher.compare(fn); expect(result.pass).toBe(false); expect(result.message).toEqual('Expected function to throw an Error.'); }); it('fails if thrown is not an instanceof Error', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw 4; }, result; result = matcher.compare(fn); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected function to throw an Error, but it threw 4.' ); }); describe('when error is from another frame', function() { function isNotRunningInBrowser() { return typeof document === 'undefined'; } var iframe = null; afterEach(function() { if (iframe !== null) { document.body.removeChild(iframe); } }); it('passes if thrown is an instanceof Error regardless of global that contains its constructor', function() { if (isNotRunningInBrowser()) { return; } var matcher = jasmineUnderTest.matchers.toThrowError(); iframe = document.body.appendChild(document.createElement('iframe')); iframe.src = 'about:blank'; var iframeDocument = iframe.contentWindow.document; iframeDocument.body.appendChild( iframeDocument.createElement('script') ).textContent = "function method() { throw new Error('foo'); }"; var result = matcher.compare(iframe.contentWindow.method); expect(result.pass).toBe(true); expect(result.message).toEqual( 'Expected function not to throw an Error, but it threw Error.' ); }); }); it('fails with the correct message if thrown is a falsy value', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw undefined; }, result; result = matcher.compare(fn); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected function to throw an Error, but it threw undefined.' ); }); it('passes if thrown is a type of Error, but there is no expected error', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new TypeError(); }, result; result = matcher.compare(fn); expect(result.pass).toBe(true); expect(result.message).toEqual( 'Expected function not to throw an Error, but it threw TypeError.' ); }); it('passes if thrown is an Error and the expected is the same message', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw new Error('foo'); }, result; result = matcher.compare(fn, 'foo'); expect(result.pass).toBe(true); expect(result.message()).toEqual( "Expected function not to throw an exception with message 'foo'." ); }); it('fails if thrown is an Error and the expected is not the same message', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw new Error('foo'); }, result; result = matcher.compare(fn, 'bar'); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw an exception with message 'bar', but it threw an exception with message 'foo'." ); }); it('passes if thrown is an Error and the expected is a RegExp that matches the message', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw new Error('a long message'); }, result; result = matcher.compare(fn, /long/); expect(result.pass).toBe(true); expect(result.message()).toEqual( 'Expected function not to throw an exception with a message matching /long/.' ); }); it('fails if thrown is an Error and the expected is a RegExp that does not match the message', function() { var matcher = jasmineUnderTest.matchers.toThrowError({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw new Error('a long message'); }, result; result = matcher.compare(fn, /foo/); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw an exception with a message matching /foo/, but it threw an exception with message 'a long message'." ); }); it('passes if thrown is an Error and the expected the same Error', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new Error(); }, result; result = matcher.compare(fn, Error); expect(result.pass).toBe(true); expect(result.message()).toEqual('Expected function not to throw Error.'); }); it('passes if thrown is a custom error that takes arguments and the expected is the same error', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), CustomError = function CustomError(arg) { arg.x; }, fn = function() { throw new CustomError({ x: 1 }); }, result; CustomError.prototype = new Error(); result = matcher.compare(fn, CustomError); expect(result.pass).toBe(true); expect(result.message()).toEqual( 'Expected function not to throw CustomError.' ); }); it('fails if thrown is an Error and the expected is a different Error', function() { var matcher = jasmineUnderTest.matchers.toThrowError(), fn = function() { throw new Error(); }, result; result = matcher.compare(fn, TypeError); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected function to throw TypeError, but it threw Error.' ); }); it('passes if thrown is a type of Error and it is equal to the expected Error and message', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrowError(matchersUtil), fn = function() { throw new TypeError('foo'); }, result; result = matcher.compare(fn, TypeError, 'foo'); expect(result.pass).toBe(true); expect(result.message()).toEqual( "Expected function not to throw TypeError with message 'foo'." ); }); it('passes if thrown is a custom error that takes arguments and it is equal to the expected custom error and message', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrowError(matchersUtil), CustomError = function CustomError(arg) { this.message = arg.message; }, fn = function() { throw new CustomError({ message: 'foo' }); }, result; CustomError.prototype = new Error(); result = matcher.compare(fn, CustomError, 'foo'); expect(result.pass).toBe(true); expect(result.message()).toEqual( "Expected function not to throw CustomError with message 'foo'." ); }); it('fails if thrown is a type of Error and the expected is a different Error', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(false), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrowError(matchersUtil), fn = function() { throw new TypeError('foo'); }, result; result = matcher.compare(fn, TypeError, 'bar'); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw TypeError with message 'bar', but it threw TypeError with message 'foo'." ); }); it('passes if thrown is a type of Error and has the same type as the expected Error and the message matches the expected message', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrowError(matchersUtil), fn = function() { throw new TypeError('foo'); }, result; result = matcher.compare(fn, TypeError, /foo/); expect(result.pass).toBe(true); expect(result.message()).toEqual( 'Expected function not to throw TypeError with a message matching /foo/.' ); }); it('fails if thrown is a type of Error and the expected is a different Error', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(false), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrowError(matchersUtil), fn = function() { throw new TypeError('foo'); }, result; result = matcher.compare(fn, TypeError, /bar/); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw TypeError with a message matching /bar/, but it threw TypeError with message 'foo'." ); }); }); jasmine-4.0.0/spec/core/matchers/toThrowMatchingSpec.js000066400000000000000000000052571416413636100231410ustar00rootroot00000000000000describe('toThrowMatching', function() { it('throws an error when the actual is not a function', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching(); expect(function() { matcher.compare({}, function() { return true; }); }).toThrowError(/Actual is not a Function/); }); it('throws an error when the expected is not a function', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching(), fn = function() { throw new Error('foo'); }; expect(function() { matcher.compare(fn, 1); }).toThrowError(/Predicate is not a Function/); }); it('fails if actual does not throw at all', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching(), fn = function() { return true; }, result; result = matcher.compare(fn, function() { return true; }); expect(result.pass).toBe(false); expect(result.message).toEqual('Expected function to throw an exception.'); }); it('fails with the correct message if thrown is a falsy value', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw undefined; }, result; result = matcher.compare(fn, function() { return false; }); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected function to throw an exception matching a predicate, but it threw undefined.' ); }); it('passes if the argument is a function that returns true when called with the error', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching(), predicate = function(e) { return e.message === 'nope'; }, fn = function() { throw new TypeError('nope'); }, result; result = matcher.compare(fn, predicate); expect(result.pass).toBe(true); expect(result.message).toEqual( 'Expected function not to throw an exception matching a predicate.' ); }); it('fails if the argument is a function that returns false when called with the error', function() { var matcher = jasmineUnderTest.matchers.toThrowMatching({ pp: jasmineUnderTest.makePrettyPrinter() }), predicate = function(e) { return e.message === 'oh no'; }, fn = function() { throw new TypeError('nope'); }, result; result = matcher.compare(fn, predicate); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw an exception matching a predicate, but it threw TypeError with message 'nope'." ); }); }); jasmine-4.0.0/spec/core/matchers/toThrowSpec.js000066400000000000000000000062571416413636100214670ustar00rootroot00000000000000describe('toThrow', function() { it('throws an error when the actual is not a function', function() { var matcher = jasmineUnderTest.matchers.toThrow(); expect(function() { matcher.compare({}); matcherComparator({}); }).toThrowError(/Actual is not a Function/); }); it('fails if actual does not throw', function() { var matcher = jasmineUnderTest.matchers.toThrow(), fn = function() { return true; }, result; result = matcher.compare(fn); expect(result.pass).toBe(false); expect(result.message).toEqual('Expected function to throw an exception.'); }); it('passes if it throws but there is no expected', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrow(matchersUtil), fn = function() { throw 5; }, result; result = matcher.compare(fn); expect(result.pass).toBe(true); expect(result.message()).toEqual( 'Expected function not to throw, but it threw 5.' ); }); it('passes even if what is thrown is falsy', function() { var matcher = jasmineUnderTest.matchers.toThrow({ pp: jasmineUnderTest.makePrettyPrinter() }), fn = function() { throw undefined; }, result; result = matcher.compare(fn); expect(result.pass).toBe(true); expect(result.message()).toEqual( 'Expected function not to throw, but it threw undefined.' ); }); it('passes if what is thrown is equivalent to what is expected', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(true), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrow(matchersUtil), fn = function() { throw 5; }, result; result = matcher.compare(fn, 5); expect(result.pass).toBe(true); expect(result.message()).toEqual('Expected function not to throw 5.'); }); it('fails if what is thrown is not equivalent to what is expected', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(false), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrow(matchersUtil), fn = function() { throw 5; }, result; result = matcher.compare(fn, 'foo'); expect(result.pass).toBe(false); expect(result.message()).toEqual( "Expected function to throw 'foo', but it threw 5." ); }); it('fails if what is thrown is not equivalent to undefined', function() { var matchersUtil = { equals: jasmine.createSpy('delegated-equal').and.returnValue(false), pp: jasmineUnderTest.makePrettyPrinter() }, matcher = jasmineUnderTest.matchers.toThrow(matchersUtil), fn = function() { throw 5; }, result; result = matcher.compare(fn, void 0); expect(result.pass).toBe(false); expect(result.message()).toEqual( 'Expected function to throw undefined, but it threw 5.' ); }); }); jasmine-4.0.0/spec/helpers/000077500000000000000000000000001416413636100155425ustar00rootroot00000000000000jasmine-4.0.0/spec/helpers/BrowserFlags.js000066400000000000000000000006141416413636100205010ustar00rootroot00000000000000(function(env) { function browserVersion(matchFn) { var userAgent = jasmine.getGlobal().navigator.userAgent; if (!userAgent) { return void 0; } var match = matchFn(userAgent); return match ? parseFloat(match[1]) : void 0; } env.firefoxVersion = browserVersion(function(userAgent) { return /Firefox\/([0-9]{0,})/.exec(userAgent); }); })(jasmine.getEnv()); jasmine-4.0.0/spec/helpers/defineJasmineUnderTest.js000066400000000000000000000004201416413636100224730ustar00rootroot00000000000000(function() { // By the time onload is called, jasmineRequire will be redefined to point // to the Jasmine source files (and not jasmine.js). So re-require window.jasmineUnderTest = jasmineRequire.core(jasmineRequire); jasmineRequire.html(jasmineUnderTest); })(); jasmine-4.0.0/spec/helpers/disableBrowserFlakes.js000066400000000000000000000002601416413636100221730ustar00rootroot00000000000000(function(env) { env.skipBrowserFlake = function() { pending( 'Skipping specs that are known to be flaky in browsers in this run' ); }; })(jasmine.getEnv()); jasmine-4.0.0/spec/helpers/domHelpers.js000066400000000000000000000010031416413636100201740ustar00rootroot00000000000000(function(env) { function domHelpers() { var doc; if (typeof document !== 'undefined') { doc = document; } else { var JSDOM = require('jsdom').JSDOM; var dom = new JSDOM(); doc = dom.window.document; } return { document: doc, createElementWithClassName: function(className) { var el = this.document.createElement('div'); el.className = className; return el; } }; } env.domHelpers = domHelpers; })(jasmine.getEnv()); jasmine-4.0.0/spec/helpers/integrationMatchers.js000066400000000000000000000035301416413636100221130ustar00rootroot00000000000000(function(env) { env.registerIntegrationMatchers = function() { jasmine.addMatchers({ toHaveFailedExpectationsForRunnable: function() { return { compare: function(actual, fullName, expectedFailures) { var foundRunnable = false, expectations = true, foundFailures = []; for (var i = 0; i < actual.calls.count(); i++) { var args = actual.calls.argsFor(i)[0]; if (args.fullName === fullName) { foundRunnable = true; for (var j = 0; j < args.failedExpectations.length; j++) { foundFailures.push(args.failedExpectations[j].message); } for (var j = 0; j < expectedFailures.length; j++) { var failure = foundFailures[j]; var expectedFailure = expectedFailures[j]; if ( Object.prototype.toString.call(expectedFailure) === '[object RegExp]' ) { expectations = expectations && expectedFailure.test(failure); } else { expectations = expectations && failure === expectedFailure; } } break; } } return { pass: foundRunnable && expectations, message: !foundRunnable ? 'The runnable "' + fullName + '" never finished' : 'Expected runnable "' + fullName + '" to have failures ' + jasmine.basicPrettyPrinter_(expectedFailures) + ' but it had ' + jasmine.basicPrettyPrinter_(foundFailures) }; } }; } }); }; })(jasmine.getEnv()); jasmine-4.0.0/spec/helpers/nodeDefineJasmineUnderTest.js000066400000000000000000000012711416413636100233060ustar00rootroot00000000000000(function() { var path = require('path'), glob = require('glob'); var jasmineUnderTestRequire = require(path.join( __dirname, '../../src/core/requireCore.js' )); global.getJasmineRequireObj = function() { return jasmineUnderTestRequire; }; function getSourceFiles() { var src_files = ['core/**/*.js', 'version.js'].map(function(file) { return path.join(__dirname, '../../', 'src/', file); }); const files = src_files.flatMap(g => glob.sync(g)); files.forEach(function(resolvedFile) { require(resolvedFile); }); } getSourceFiles(); global.jasmineUnderTest = jasmineUnderTestRequire.core( jasmineUnderTestRequire ); })(); jasmine-4.0.0/spec/helpers/resetEnv.js000066400000000000000000000002051416413636100176700ustar00rootroot00000000000000beforeEach(function() { // env is stateful. Ensure that it does not leak between tests. jasmineUnderTest.currentEnv_ = null; }); jasmine-4.0.0/spec/html/000077500000000000000000000000001416413636100150445ustar00rootroot00000000000000jasmine-4.0.0/spec/html/HtmlReporterSpec.js000066400000000000000000001650271416413636100206570ustar00rootroot00000000000000describe('HtmlReporter', function() { var env; beforeEach(function() { env = new jasmineUnderTest.Env(); }); afterEach(function() { env.cleanup_(); }); it('builds the initial DOM elements, including the title banner', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); // Main top-level elements expect(container.querySelector('div.jasmine_html-reporter')).toBeTruthy(); expect(container.querySelector('div.jasmine-banner')).toBeTruthy(); expect(container.querySelector('div.jasmine-alert')).toBeTruthy(); expect(container.querySelector('div.jasmine-results')).toBeTruthy(); expect(container.querySelector('ul.jasmine-symbol-summary')).toBeTruthy(); // title banner var banner = container.querySelector('.jasmine-banner'); var title = banner.querySelector('a.jasmine-title'); expect(title.getAttribute('href')).toEqual('http://jasmine.github.io/'); expect(title.getAttribute('target')).toEqual('_blank'); var version = banner.querySelector('.jasmine-version'); expect(version.textContent).toEqual(jasmineUnderTest.version); }); it('builds a single reporter even if initialized multiple times', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.initialize(); reporter.initialize(); expect( container.querySelectorAll('div.jasmine_html-reporter').length ).toEqual(1); }); describe('when a spec is done', function() { describe('and no expectations ran', function() { var container, reporter; beforeEach(function() { container = document.createElement('div'); reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: function() { return container; }, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); spyOn(console, 'warn'); spyOn(console, 'error'); reporter.initialize(); }); it('should log warning to the console and print a special symbol when empty spec status is passed', function() { reporter.specDone({ status: 'passed', fullName: 'Some Name', passedExpectations: [], failedExpectations: [] }); /* eslint-disable-next-line no-console */ expect(console.warn).toHaveBeenCalledWith( "Spec 'Some Name' has no expectations." ); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual('jasmine-empty'); }); it('should log error to the console and print a failure symbol when empty spec status is failed', function() { reporter.specDone({ status: 'failed', fullName: 'Some Name', passedExpectations: [], failedExpectations: [] }); /* eslint-disable-next-line no-console */ expect(console.error).toHaveBeenCalledWith( "Spec 'Some Name' has no expectations." ); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual('jasmine-failed'); }); }); it('reports the status symbol of a excluded spec', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.specDone({ id: 789, status: 'excluded', fullName: 'symbols should have titles', passedExpectations: [], failedExpectations: [] }); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual('jasmine-excluded'); expect(specEl.getAttribute('id')).toEqual('spec_789'); expect(specEl.getAttribute('title')).toEqual( 'symbols should have titles' ); }); it('reports the status symbol of a pending spec', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.specDone({ id: 789, status: 'pending', passedExpectations: [], failedExpectations: [] }); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual('jasmine-pending'); expect(specEl.getAttribute('id')).toEqual('spec_789'); }); it('reports the status symbol of a passing spec', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.specDone({ id: 123, status: 'passed', passedExpectations: [{ passed: true }], failedExpectations: [] }); var statuses = container.querySelector('.jasmine-symbol-summary'); var specEl = statuses.querySelector('li'); expect(specEl.getAttribute('class')).toEqual('jasmine-passed'); expect(specEl.getAttribute('id')).toEqual('spec_123'); }); it('reports the status symbol of a failing spec', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.specDone({ id: 345, status: 'failed', failedExpectations: [], passedExpectations: [] }); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual('jasmine-failed'); expect(specEl.getAttribute('id')).toEqual('spec_345'); }); }); describe('when there are deprecation warnings', function() { it('displays the messages in their own alert bars', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.specDone({ status: 'passed', fullName: 'a spec with a deprecation', deprecationWarnings: [{ message: 'spec deprecation' }], failedExpectations: [], passedExpectations: [] }); reporter.suiteDone({ status: 'passed', fullName: 'a suite with a deprecation', deprecationWarnings: [{ message: 'suite deprecation' }], failedExpectations: [] }); reporter.jasmineDone({ deprecationWarnings: [{ message: 'global deprecation' }], failedExpectations: [] }); var alertBars = container.querySelectorAll('.jasmine-alert .jasmine-bar'); expect(alertBars.length).toEqual(4); expect(alertBars[1].innerHTML).toMatch( /spec deprecation.*\(in spec: a spec with a deprecation\)/ ); expect(alertBars[1].getAttribute('class')).toEqual( 'jasmine-bar jasmine-warning' ); expect(alertBars[2].innerHTML).toMatch( /suite deprecation.*\(in suite: a suite with a deprecation\)/ ); expect(alertBars[3].innerHTML).toMatch(/global deprecation/); expect(alertBars[3].innerHTML).not.toMatch(/in /); }); it('displays expandable stack traces', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }), expander, expanderLink, expanderContents; reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ deprecationWarnings: [ { message: 'a deprecation', stack: 'a stack trace' } ], failedExpectations: [] }); expander = container.querySelector( '.jasmine-alert .jasmine-bar .jasmine-expander' ); expanderContents = expander.querySelector('.jasmine-expander-contents'); expect(expanderContents.textContent).toMatch(/a stack trace/); expanderLink = expander.querySelector('a'); expect(expander).not.toHaveClass('jasmine-expanded'); expect(expanderLink.textContent).toMatch(/Show stack trace/); expanderLink.click(); expect(expander).toHaveClass('jasmine-expanded'); expect(expanderLink.textContent).toMatch(/Hide stack trace/); expanderLink.click(); expect(expander).not.toHaveClass('jasmine-expanded'); expect(expanderLink.textContent).toMatch(/Show stack trace/); }); it('omits the expander when there is no stack trace', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }), warningBar; reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ deprecationWarnings: [ { message: 'a deprecation', stack: '' } ], failedExpectations: [] }); warningBar = container.querySelector('.jasmine-warning'); expect(warningBar.querySelector('.jasmine-expander')).toBeFalsy(); }); it('nicely formats the verboseDeprecations note', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }), alertBar; reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ deprecationWarnings: [ { message: 'a deprecation\nNote: This message will be shown only once. Set config.verboseDeprecations to true to see every occurrence.' } ], failedExpectations: [] }); alertBar = container.querySelector('.jasmine-warning'); expect(alertBar.innerHTML).toMatch( /a deprecation
Note: This message will be shown only once/ ); }); }); describe('when Jasmine is done', function() { it('adds a warning to the link title of specs that have no expectations', function() { if (!window.console) { window.console = { error: function() {} }; } var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); spyOn(console, 'error'); reporter.initialize(); reporter.jasmineStarted({}); reporter.suiteStarted({ id: 1 }); reporter.specStarted({ id: 1, passedExpectations: [], failedExpectations: [] }); reporter.specDone({ id: 1, status: 'passed', description: 'Spec Description', passedExpectations: [], failedExpectations: [] }); reporter.suiteDone({ id: 1 }); reporter.jasmineDone({}); var summary = container.querySelector('.jasmine-summary'); var suite = summary.childNodes[0]; var specs = suite.childNodes[1]; var spec = specs.childNodes[0]; var specLink = spec.childNodes[0]; expect(specLink.innerHTML).toMatch(/SPEC HAS NO EXPECTATIONS/); }); it('reports the run time', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ totalTime: 100 }); var duration = container.querySelector( '.jasmine-alert .jasmine-duration' ); expect(duration.innerHTML).toMatch(/finished in 0.1s/); }); it('reports the suite and spec names with status', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, addToExistingQueryString: function(key, value) { return '?foo=bar&' + key + '=' + value; } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.suiteStarted({ id: 1, description: 'A Suite', fullName: 'A Suite' }); var specResult = { id: 123, description: 'with a spec', fullName: 'A Suite with a spec', status: 'passed', failedExpectations: [], passedExpectations: [{ passed: true }] }; reporter.specStarted(specResult); reporter.specDone(specResult); reporter.suiteStarted({ id: 2, description: 'inner suite', fullName: 'A Suite inner suite' }); var specResult = { id: 124, description: 'with another spec', fullName: 'A Suite inner suite with another spec', status: 'passed', failedExpectations: [], passedExpectations: [{ passed: true }] }; reporter.specStarted(specResult); reporter.specDone(specResult); reporter.suiteDone({ id: 2, status: 'things', description: 'inner suite', fullName: 'A Suite inner suite' }); specResult = { id: 209, description: 'with a failing spec', fullName: 'A Suite inner with a failing spec', status: 'failed', failedExpectations: [{}], passedExpectations: [] }; reporter.specStarted(specResult); reporter.specDone(specResult); reporter.suiteDone({ id: 1, status: 'things', description: 'A Suite', fullName: 'A Suite' }); reporter.jasmineDone({}); var summary = container.querySelector('.jasmine-summary'); expect(summary.childNodes.length).toEqual(1); var outerSuite = summary.childNodes[0]; expect(outerSuite.childNodes.length).toEqual(4); var classes = []; for (var i = 0; i < outerSuite.childNodes.length; i++) { var node = outerSuite.childNodes[i]; classes.push(node.getAttribute('class')); } expect(classes).toEqual([ 'jasmine-suite-detail jasmine-things', 'jasmine-specs', 'jasmine-suite', 'jasmine-specs' ]); var suiteDetail = outerSuite.childNodes[0]; var suiteLink = suiteDetail.childNodes[0]; expect(suiteLink.innerHTML).toEqual('A Suite'); expect(suiteLink.getAttribute('href')).toEqual('/?foo=bar&spec=A Suite'); var specs = outerSuite.childNodes[1]; var spec = specs.childNodes[0]; expect(spec.getAttribute('class')).toEqual('jasmine-passed'); expect(spec.getAttribute('id')).toEqual('spec-123'); var specLink = spec.childNodes[0]; expect(specLink.innerHTML).toEqual('with a spec'); expect(specLink.getAttribute('href')).toEqual( '/?foo=bar&spec=A Suite with a spec' ); }); it('has an options menu', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var trigger = container.querySelector( '.jasmine-run-options .jasmine-trigger' ), payload = container.querySelector( '.jasmine-run-options .jasmine-payload' ); expect(payload).not.toHaveClass('jasmine-open'); trigger.onclick(); expect(payload).toHaveClass('jasmine-open'); trigger.onclick(); expect(payload).not.toHaveClass('jasmine-open'); }); describe('when there are global errors', function() { it('displays the exceptions in their own alert bars', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ failedExpectations: [ { message: 'Global After All Failure', globalErrorType: 'afterAll' }, { message: 'Your JS is borken', globalErrorType: 'load' } ] }); var alertBars = container.querySelectorAll( '.jasmine-alert .jasmine-bar' ); expect(alertBars.length).toEqual(3); expect(alertBars[1].getAttribute('class')).toEqual( 'jasmine-bar jasmine-errored' ); expect(alertBars[1].innerHTML).toMatch( /AfterAll Global After All Failure/ ); expect(alertBars[2].innerHTML).toMatch( /Error during loading: Your JS is borken/ ); expect(alertBars[2].innerHTML).not.toMatch(/line/); }); it('does not display the "AfterAll" prefix for other error types', function() { const container = document.createElement('div'); const getContainer = function() { return container; }; const reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ failedExpectations: [ { message: 'load error', globalErrorType: 'load' }, { message: 'lateExpectation error', globalErrorType: 'lateExpectation' }, { message: 'lateError error', globalErrorType: 'lateError' } ] }); const alertBars = container.querySelectorAll( '.jasmine-alert .jasmine-bar' ); expect(alertBars.length).toEqual(4); expect(alertBars[1].textContent).toContain('load error'); expect(alertBars[2].textContent).toContain('lateExpectation error'); expect(alertBars[3].textContent).toContain('lateError error'); for (let bar of alertBars) { expect(bar.textContent).not.toContain('AfterAll'); } }); it('displays file and line information if available', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ failedExpectations: [ { message: 'Your JS is borken', globalErrorType: 'load', filename: 'some/file.js', lineno: 42 } ] }); var alertBars = container.querySelectorAll( '.jasmine-alert .jasmine-bar' ); expect(alertBars.length).toEqual(2); expect(alertBars[1].innerHTML).toMatch( /Error during loading: Your JS is borken in some\/file.js line 42/ ); }); }); describe('UI for stop on spec failure', function() { it('should be unchecked for full execution', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); expect(stopOnFailureUI.checked).toBe(false); }); it('should be checked if stopping short', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ stopOnSpecFailure: true }); reporter.initialize(); reporter.jasmineDone({}); var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); expect(stopOnFailureUI.checked).toBe(true); }); it('should navigate and turn the setting on', function() { var container = document.createElement('div'), navigationHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, navigateWithNewParam: navigationHandler, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); stopOnFailureUI.click(); expect(navigationHandler).toHaveBeenCalledWith( 'stopOnSpecFailure', true ); }); it('should navigate and turn the setting off', function() { var container = document.createElement('div'), navigationHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, navigateWithNewParam: navigationHandler, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ stopOnSpecFailure: true }); reporter.initialize(); reporter.jasmineDone({}); var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); stopOnFailureUI.click(); expect(navigationHandler).toHaveBeenCalledWith( 'stopOnSpecFailure', false ); }); }); describe('UI for throwing errors on expectation failures', function() { it('should be unchecked if not throwing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var throwingExpectationsUI = container.querySelector('.jasmine-throw'); expect(throwingExpectationsUI.checked).toBe(false); }); it('should be checked if throwing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ stopSpecOnExpectationFailure: true }); reporter.initialize(); reporter.jasmineDone({}); var throwingExpectationsUI = container.querySelector('.jasmine-throw'); expect(throwingExpectationsUI.checked).toBe(true); }); it('should navigate and change the setting to on', function() { var container = document.createElement('div'), navigateHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, navigateWithNewParam: navigateHandler, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var throwingExpectationsUI = container.querySelector('.jasmine-throw'); throwingExpectationsUI.click(); expect(navigateHandler).toHaveBeenCalledWith( 'stopSpecOnExpectationFailure', true ); }); it('should navigate and change the setting to off', function() { var container = document.createElement('div'), navigateHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, navigateWithNewParam: navigateHandler, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ stopSpecOnExpectationFailure: true }); reporter.initialize(); reporter.jasmineDone({}); var throwingExpectationsUI = container.querySelector('.jasmine-throw'); throwingExpectationsUI.click(); expect(navigateHandler).toHaveBeenCalledWith( 'stopSpecOnExpectationFailure', false ); }); }); describe('UI for hiding disabled specs', function() { it('should be unchecked if not hiding disabled specs', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ hideDisabled: false }); reporter.initialize(); reporter.jasmineDone({}); var disabledUI = container.querySelector('.jasmine-disabled'); expect(disabledUI.checked).toBe(false); }); it('should be checked if hiding disabled', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ hideDisabled: true }); reporter.initialize(); reporter.jasmineDone({}); var disabledUI = container.querySelector('.jasmine-disabled'); expect(disabledUI.checked).toBe(true); }); it('should not display specs that have been disabled', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ hideDisabled: true }); reporter.initialize(); reporter.specDone({ id: 789, status: 'excluded', fullName: 'symbols should have titles', passedExpectations: [], failedExpectations: [] }); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute('class')).toEqual( 'jasmine-excluded-no-display' ); }); }); describe('UI for running tests in random order', function() { it('should be unchecked if not randomizing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ random: false }); reporter.initialize(); reporter.jasmineDone({}); var randomUI = container.querySelector('.jasmine-random'); expect(randomUI.checked).toBe(false); }); it('should be checked if randomizing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ random: true }); reporter.initialize(); reporter.jasmineDone({}); var randomUI = container.querySelector('.jasmine-random'); expect(randomUI.checked).toBe(true); }); it('should navigate and change the setting to on', function() { var container = document.createElement('div'), navigateHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, navigateWithNewParam: navigateHandler, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ random: false }); reporter.initialize(); reporter.jasmineDone({}); var randomUI = container.querySelector('.jasmine-random'); randomUI.click(); expect(navigateHandler).toHaveBeenCalledWith('random', true); }); it('should navigate and change the setting to off', function() { var container = document.createElement('div'), navigateHandler = jasmine.createSpy('navigate'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, navigateWithNewParam: navigateHandler, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); env.configure({ random: true }); reporter.initialize(); reporter.jasmineDone({}); var randomUI = container.querySelector('.jasmine-random'); randomUI.click(); expect(navigateHandler).toHaveBeenCalledWith('random', false); }); it('should show the seed bar if randomizing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({ order: { random: true, seed: '424242' } }); var seedBar = container.querySelector('.jasmine-seed-bar'); expect(seedBar.textContent).toBe(', randomized with seed 424242'); var seedLink = container.querySelector('.jasmine-seed-bar a'); expect(seedLink.getAttribute('href')).toBe('/?seed=424242'); }); it('should not show the current seed bar if not randomizing', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineDone({}); var seedBar = container.querySelector('.jasmine-seed-bar'); expect(seedBar).toBeNull(); }); it('should include non-spec query params in the jasmine-skipped link when present', function() { var container = document.createElement('div'), reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: function() { return container; }, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, addToExistingQueryString: function(key, value) { return '?foo=bar&' + key + '=' + value; } }); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineDone({ order: { random: true } }); var skippedLink = container.querySelector('.jasmine-skipped a'); expect(skippedLink.getAttribute('href')).toEqual('/?foo=bar&spec='); }); }); describe('and all specs pass', function() { var container; beforeEach(function() { container = document.createElement('div'); var getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 2 }); reporter.specDone({ id: 123, description: 'with a spec', fullName: 'A Suite with a spec', status: 'passed', passedExpectations: [{ passed: true }], failedExpectations: [] }); reporter.specDone({ id: 124, description: 'with another spec', fullName: 'A Suite inner suite with another spec', status: 'passed', passedExpectations: [{ passed: true }], failedExpectations: [] }); reporter.jasmineDone({}); }); it('reports the specs counts', function() { var alertBars = container.querySelectorAll( '.jasmine-alert .jasmine-bar' ); expect(alertBars.length).toEqual(1); expect(alertBars[0].innerHTML).toMatch(/2 specs, 0 failures/); }); it('reports no failure details', function() { var specFailure = container.querySelector('.jasmine-failures'); expect(specFailure.childNodes.length).toEqual(0); }); it('reports no pending specs', function() { var alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); expect(alertBar.innerHTML).not.toMatch(/pending spec[s]/); }); }); describe('and there are excluded specs', function() { var container, reporter, reporterConfig, specStatus; beforeEach(function() { container = document.createElement('div'); reporterConfig = { env: env, getContainer: function() { return container; }, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }; specStatus = { id: 123, description: 'with a excluded spec', fullName: 'A Suite with a excluded spec', status: 'excluded', passedExpectations: [], failedExpectations: [] }; }); describe('when the specs are not filtered', function() { beforeEach(function() { reporterConfig.filterSpecs = false; reporter = new jasmineUnderTest.HtmlReporter(reporterConfig); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.specStarted(specStatus); reporter.specDone(specStatus); reporter.jasmineDone({}); }); it('shows the excluded spec in the spec list', function() { var specList = container.querySelector('.jasmine-summary'); expect(specList.innerHTML).toContain('with a excluded spec'); }); }); describe('when the specs are filtered', function() { beforeEach(function() { reporterConfig.filterSpecs = true; reporter = new jasmineUnderTest.HtmlReporter(reporterConfig); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.specStarted(specStatus); reporter.specDone(specStatus); reporter.jasmineDone({}); }); it("doesn't show the excluded spec in the spec list", function() { var specList = container.querySelector('.jasmine-summary'); expect(specList.innerHTML).toEqual(''); }); }); }); describe('and there are pending specs', function() { var container, reporter; beforeEach(function() { container = document.createElement('div'); var getContainer = function() { return container; }; reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); var specStatus = { id: 123, description: 'with a spec', fullName: 'A Suite with a spec', status: 'pending', passedExpectations: [], failedExpectations: [], pendingReason: 'my custom pending reason' }; reporter.specStarted(specStatus); reporter.specDone(specStatus); reporter.jasmineDone({}); }); it('reports the pending specs count', function() { var alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); expect(alertBar.innerHTML).toMatch( /1 spec, 0 failures, 1 pending spec/ ); }); it('reports no failure details', function() { var specFailure = container.querySelector('.jasmine-failures'); expect(specFailure.childNodes.length).toEqual(0); }); it('displays the custom pending reason', function() { var pendingDetails = container.querySelector( '.jasmine-summary .jasmine-pending' ); expect(pendingDetails.innerHTML).toContain('my custom pending reason'); }); }); describe('and some tests fail', function() { var container, reporter; beforeEach(function() { container = document.createElement('div'); var getContainer = function() { return container; }; reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, addToExistingQueryString: function(key, value) { return '?foo=bar&' + key + '=' + value; } }); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.suiteStarted({ id: 1, description: 'A suite' }); reporter.suiteStarted({ id: 2, description: 'inner suite' }); var passingSpecResult = { id: 123, status: 'passed', passedExpectations: [{ passed: true }], failedExpectations: [] }; reporter.specStarted(passingSpecResult); reporter.specDone(passingSpecResult); var failingSpecResult = { id: 124, status: 'failed', description: 'a failing spec', fullName: 'a suite inner suite a failing spec', passedExpectations: [], failedExpectations: [ { message: 'a failure message', stack: 'a stack trace' } ] }; var failingSpecResultWithDebugLogs = { id: 567, status: 'failed', description: 'a failing spec', fullName: 'a suite inner suite a failing spec', passedExpectations: [], failedExpectations: [ { message: 'a failure message', stack: 'a stack trace' } ], debugLogs: [ { timestamp: 123, message: 'msg 1' }, { timestamp: 456, message: 'msg 1' } ] }; var passingSuiteResult = { id: 1, description: 'A suite' }; var failingSuiteResult = { id: 2, description: 'a suite', fullName: 'a suite', status: 'failed', failedExpectations: [{ message: 'My After All Exception' }] }; reporter.specStarted(failingSpecResult); reporter.specDone(failingSpecResult); reporter.suiteDone(passingSuiteResult); reporter.suiteDone(failingSuiteResult); reporter.suiteDone(passingSuiteResult); reporter.specStarted(failingSpecResultWithDebugLogs); reporter.specDone(failingSpecResultWithDebugLogs); reporter.jasmineDone({}); }); it('reports the specs counts', function() { var alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); expect(alertBar.innerHTML).toMatch(/3 specs, 3 failures/); }); it('reports failure messages and stack traces', function() { var specFailures = container.querySelector('.jasmine-failures'); expect(specFailures.childNodes.length).toEqual(3); var specFailure = specFailures.childNodes[0]; expect(specFailure.getAttribute('class')).toMatch(/jasmine-failed/); expect(specFailure.getAttribute('class')).toMatch( /jasmine-spec-detail/ ); var specDiv = specFailure.childNodes[0]; expect(specDiv.getAttribute('class')).toEqual('jasmine-description'); var message = specFailure.childNodes[1].childNodes[0]; expect(message.getAttribute('class')).toEqual('jasmine-result-message'); expect(message.innerHTML).toEqual('a failure message'); var stackTrace = specFailure.childNodes[1].childNodes[1]; expect(stackTrace.getAttribute('class')).toEqual('jasmine-stack-trace'); expect(stackTrace.innerHTML).toEqual('a stack trace'); var suiteFailure = specFailures.childNodes[0]; expect(suiteFailure.getAttribute('class')).toMatch(/jasmine-failed/); expect(suiteFailure.getAttribute('class')).toMatch( /jasmine-spec-detail/ ); var suiteDiv = suiteFailure.childNodes[0]; expect(suiteDiv.getAttribute('class')).toEqual('jasmine-description'); var suiteMessage = suiteFailure.childNodes[1].childNodes[0]; expect(suiteMessage.getAttribute('class')).toEqual( 'jasmine-result-message' ); expect(suiteMessage.innerHTML).toEqual('a failure message'); var suiteStackTrace = suiteFailure.childNodes[1].childNodes[1]; expect(suiteStackTrace.getAttribute('class')).toEqual( 'jasmine-stack-trace' ); expect(suiteStackTrace.innerHTML).toEqual('a stack trace'); }); it('reports traces when present', function() { var specFailure = container.querySelectorAll( '.jasmine-spec-detail.jasmine-failed' )[2], debugLogs = specFailure.querySelector('.jasmine-debug-log table'), rows; expect(debugLogs).toBeTruthy(); rows = debugLogs.querySelectorAll('tbody tr'); expect(rows.length).toEqual(2); }); it('provides links to focus on a failure and each containing suite', function() { var description = container.querySelector( '.jasmine-failures .jasmine-description' ); var links = description.querySelectorAll('a'); expect(description.textContent).toEqual( 'A suite > inner suite > a failing spec' ); expect(links.length).toEqual(3); expect(links[0].textContent).toEqual('A suite'); expect(links[0].getAttribute('href')).toMatch(/\?foo=bar&spec=A suite/); expect(links[1].textContent).toEqual('inner suite'); expect(links[1].getAttribute('href')).toMatch( /\?foo=bar&spec=A suite inner suite/ ); expect(links[2].textContent).toEqual('a failing spec'); expect(links[2].getAttribute('href')).toMatch( /\?foo=bar&spec=a suite inner suite a failing spec/ ); }); it('allows switching between failure details and the spec summary', function() { var menuBar = container.querySelectorAll('.jasmine-bar')[1]; expect(menuBar.getAttribute('class')).not.toMatch(/hidden/); var link = menuBar.querySelector('a'); expect(link.innerHTML).toEqual('Failures'); expect(link.getAttribute('href')).toEqual('#'); }); it("sets the reporter to 'Failures List' mode", function() { var reporterNode = container.querySelector('.jasmine_html-reporter'); expect(reporterNode.getAttribute('class')).toMatch( 'jasmine-failure-list' ); }); }); it('counts failures that are reported in the jasmineDone event', function() { const container = document.createElement('div'); function getContainer() { return container; } const reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, addToExistingQueryString: function(key, value) { return '?' + key + '=' + value; } }); reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 1 }); const failingSpecResult = { id: 124, status: 'failed', description: 'a failing spec', fullName: 'a suite inner suite a failing spec', passedExpectations: [], failedExpectations: [ { message: 'a failure message', stack: 'a stack trace' } ] }; reporter.specStarted(failingSpecResult); reporter.specDone(failingSpecResult); reporter.jasmineDone({ failedExpectations: [ { message: 'a failure message', stack: 'a stack trace' }, { message: 'a failure message', stack: 'a stack trace' } ] }); const alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); expect(alertBar.innerHTML).toMatch(/1 spec, 3 failures/); }); }); describe('The overall result bar', function() { describe("When the jasmineDone event's overallStatus is 'passed'", function() { it('has class jasmine-passed', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ overallStatus: 'passed', failedExpectations: [] }); var alertBar = container.querySelector('.jasmine-overall-result'); expect(alertBar).toHaveClass('jasmine-passed'); }); }); describe("When the jasmineDone event's overallStatus is 'failed'", function() { it('has class jasmine-failed', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ overallStatus: 'failed', failedExpectations: [] }); var alertBar = container.querySelector('.jasmine-overall-result'); expect(alertBar).toHaveClass('jasmine-failed'); }); }); describe("When the jasmineDone event's overallStatus is 'incomplete'", function() { it('has class jasmine-incomplete', function() { var container = document.createElement('div'), getContainer = function() { return container; }, reporter = new jasmineUnderTest.HtmlReporter({ env: env, getContainer: getContainer, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); reporter.initialize(); reporter.jasmineStarted({}); reporter.jasmineDone({ overallStatus: 'incomplete', incompleteReason: 'because nope', failedExpectations: [] }); var alertBar = container.querySelector('.jasmine-overall-result'); expect(alertBar).toHaveClass('jasmine-incomplete'); expect(alertBar.textContent).toContain('Incomplete: because nope'); }); }); }); }); jasmine-4.0.0/spec/html/HtmlSpecFilterSpec.js000066400000000000000000000011141416413636100210770ustar00rootroot00000000000000describe('jasmineUnderTest.HtmlSpecFilter', function() { it('should match when no string is provided', function() { var specFilter = new jasmineUnderTest.HtmlSpecFilter(); expect(specFilter.matches('foo')).toBe(true); expect(specFilter.matches('*bar')).toBe(true); }); it('should only match the provided string', function() { var specFilter = new jasmineUnderTest.HtmlSpecFilter({ filterString: function() { return 'foo'; } }); expect(specFilter.matches('foo')).toBe(true); expect(specFilter.matches('bar')).toBe(false); }); }); jasmine-4.0.0/spec/html/MatchersHtmlSpec.js000066400000000000000000000016071416413636100206140ustar00rootroot00000000000000describe('MatchersSpec - HTML Dependent', function() { var env, spec; beforeEach(function() { env = new jasmineUnderTest.Env(); env.describe('suite', function() { spec = env.it('spec', function() {}); }); spyOn(spec, 'addExpectationResult'); addMatchers({ toPass: function() { return lastResult().passed; }, toFail: function() { return !lastResult().passed; } }); }); afterEach(function() { env.cleanup_(); }); function match(value) { return spec.expect(value); } function lastResult() { return spec.addExpectationResult.mostRecentCall.args[1]; } xit('toEqual with DOM nodes', function() { var nodeA = document.createElement('div'); var nodeB = document.createElement('div'); expect(match(nodeA).toEqual(nodeA)).toPass(); expect(match(nodeA).toEqual(nodeB)).toFail(); }); }); jasmine-4.0.0/spec/html/PrettyPrintHtmlSpec.js000066400000000000000000000032541416413636100213520ustar00rootroot00000000000000describe('PrettyPrinter (HTML Dependent)', function() { it('should stringify non-element HTML nodes properly', function() { var sampleNode = document.createTextNode(''); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(sampleNode)).toEqual('HTMLNode'); expect(pp({ foo: sampleNode })).toEqual('Object({ foo: HTMLNode })'); }); it('should stringify empty HTML elements as their opening tags', function() { var simple = document.createElement('div'); var pp = jasmineUnderTest.makePrettyPrinter(); simple.className = 'foo'; expect(pp(simple)).toEqual('
'); }); it('should stringify non-empty HTML elements as tags with placeholders', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var nonEmpty = document.createElement('div'); nonEmpty.className = 'foo'; nonEmpty.innerHTML = '

Irrelevant

'; expect(pp(nonEmpty)).toEqual('
...
'); }); it("should print Firefox's wrapped native objects correctly", function() { if (jasmine.getEnv().firefoxVersion) { var pp = jasmineUnderTest.makePrettyPrinter(); try { new CustomEvent(); } catch (e) { var err = e; } // Different versions of FF produce different error messages. expect(pp(err)).toMatch( /Not enough arguments|CustomEvent.*only 0.*passed/ ); } }); it('should stringify HTML element with text and attributes', function() { var pp = jasmineUnderTest.makePrettyPrinter(); var el = document.createElement('div'); el.setAttribute('things', 'foo'); el.innerHTML = 'foo'; expect(pp(el)).toEqual('
...
'); }); }); jasmine-4.0.0/spec/html/QueryStringSpec.js000066400000000000000000000043421416413636100205140ustar00rootroot00000000000000describe('QueryString', function() { describe('#navigateWithNewParam', function() { it('sets the query string to include the given key/value pair', function() { var windowLocation = { search: '' }, queryString = new jasmineUnderTest.QueryString({ getWindowLocation: function() { return windowLocation; } }); queryString.navigateWithNewParam('foo', 'bar baz'); expect(windowLocation.search).toMatch(/foo=bar%20baz/); }); it('leaves existing params alone', function() { var windowLocation = { search: '?foo=bar' }, queryString = new jasmineUnderTest.QueryString({ getWindowLocation: function() { return windowLocation; } }); queryString.navigateWithNewParam('baz', 'quux'); expect(windowLocation.search).toMatch(/foo=bar/); expect(windowLocation.search).toMatch(/baz=quux/); }); }); describe('#fullStringWithNewParam', function() { it('gets the query string including the given key/value pair', function() { var windowLocation = { search: '?foo=bar' }, queryString = new jasmineUnderTest.QueryString({ getWindowLocation: function() { return windowLocation; } }); var result = queryString.fullStringWithNewParam('baz', 'quux'); expect(result).toMatch(/foo=bar/); expect(result).toMatch(/baz=quux/); }); }); describe('#getParam', function() { it('returns the value of the requested key', function() { var windowLocation = { search: '?baz=quux%20corge' }, queryString = new jasmineUnderTest.QueryString({ getWindowLocation: function() { return windowLocation; } }); expect(queryString.getParam('baz')).toEqual('quux corge'); }); it('returns null if the key is not present', function() { var windowLocation = { search: '' }, queryString = new jasmineUnderTest.QueryString({ getWindowLocation: function() { return windowLocation; } }); expect(queryString.getParam('baz')).toBeFalsy(); }); }); }); jasmine-4.0.0/spec/html/ResultsNodeSpec.js000066400000000000000000000030551416413636100204670ustar00rootroot00000000000000describe('ResultsNode', function() { it('wraps a result', function() { var fakeResult = { id: 123, message: 'foo' }, node = new jasmineUnderTest.ResultsNode(fakeResult, 'suite', null); expect(node.result).toBe(fakeResult); expect(node.type).toEqual('suite'); }); it('can add children with a type', function() { var fakeResult = { id: 123, message: 'foo' }, fakeChildResult = { id: 456, message: 'bar' }, node = new jasmineUnderTest.ResultsNode(fakeResult, 'suite', null); node.addChild(fakeChildResult, 'spec'); expect(node.children.length).toEqual(1); expect(node.children[0].result).toEqual(fakeChildResult); expect(node.children[0].type).toEqual('spec'); }); it('has a pointer back to its parent ResultNode', function() { var fakeResult = { id: 123, message: 'foo' }, fakeChildResult = { id: 456, message: 'bar' }, node = new jasmineUnderTest.ResultsNode(fakeResult, 'suite', null); node.addChild(fakeChildResult, 'spec'); expect(node.children[0].parent).toBe(node); }); it('can provide the most recent child', function() { var fakeResult = { id: 123, message: 'foo' }, fakeChildResult = { id: 456, message: 'bar' }, node = new jasmineUnderTest.ResultsNode(fakeResult, 'suite', null); node.addChild(fakeChildResult, 'spec'); expect(node.last()).toBe(node.children[node.children.length - 1]); }); }); jasmine-4.0.0/spec/html/SpyRegistryHtmlSpec.js000066400000000000000000000012451416413636100213500ustar00rootroot00000000000000describe('Spy Registry browser-specific behavior', function() { function createSpy(name, originalFn) { return jasmineUnderTest.Spy(name, originalFn); } it('can spy on and unspy window.onerror', function() { var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { return spies; }, createSpy: createSpy, global: window }), originalHandler = window.onerror; try { spyRegistry.spyOn(window, 'onerror'); spyRegistry.clearSpies(); expect(window.onerror).toBe(originalHandler); } finally { window.onerror = originalHandler; } }); }); jasmine-4.0.0/spec/javascripts/000077500000000000000000000000001416413636100164315ustar00rootroot00000000000000jasmine-4.0.0/spec/javascripts/support/000077500000000000000000000000001416413636100201455ustar00rootroot00000000000000jasmine-4.0.0/spec/javascripts/support/jasmine_selenium_runner.yml000066400000000000000000000011171416413636100256100ustar00rootroot00000000000000--- use_sauce: <%= ENV['USE_SAUCE'] %> browser: <%= ENV['JASMINE_BROWSER'] %> sauce: sauce_connect_path: <%= ENV['SAUCE_CONNECT_PATH'].inspect %> name: jasmine-core <%= Time.now.to_s %> username: <%= ENV['SAUCE_USERNAME'] %> access_key: <%= ENV['SAUCE_ACCESS_KEY'] %> build: Core <%= ENV['TRAVIS_BUILD_NUMBER'] || 'Ran locally' %> tags: - Jasmine-Core - "<%= ENV['TRAVIS_JOB_NUMBER'] %>" tunnel_identifier: <%= ENV['TRAVIS_JOB_NUMBER'] ? %Q("#{ENV['TRAVIS_JOB_NUMBER']}") : nil %> os: <%= ENV['SAUCE_OS'] %> browser_version: "<%= ENV['SAUCE_BROWSER_VERSION'] %>" jasmine-4.0.0/spec/npmPackage/000077500000000000000000000000001416413636100161465ustar00rootroot00000000000000jasmine-4.0.0/spec/npmPackage/npmPackageSpec.js000066400000000000000000000107521416413636100213720ustar00rootroot00000000000000describe('npm package', function() { var path = require('path'), temp = require('temp').track(), fs = require('fs'); beforeAll(function() { var shell = require('shelljs'), pack = shell.exec('npm pack', { silent: true }); this.tarball = pack.stdout.split('\n')[0]; this.tmpDir = temp.mkdirSync(); // automatically deleted on exit var untar = shell.exec('tar -xzf ' + this.tarball + ' -C ' + this.tmpDir, { silent: true }); expect(untar.code).toBe(0); this.packagedCore = require(path.join( this.tmpDir, 'package/lib/jasmine-core.js' )); }); beforeEach(function() { jasmine.addMatchers({ toExistInPath: function() { return { compare: function(actual, expected) { var fullPath = path.resolve(expected, actual); return { pass: fs.existsSync(fullPath) }; } }; } }); }); afterAll(function() { fs.unlinkSync(this.tarball); }); it('has a root path', function() { expect(this.packagedCore.files.path).toEqual( fs.realpathSync(path.resolve(this.tmpDir, 'package/lib/jasmine-core')) ); }); it('has a bootDir', function() { expect(this.packagedCore.files.bootDir).toEqual( fs.realpathSync(path.resolve(this.tmpDir, 'package/lib/jasmine-core')) ); }); it('has jsFiles', function() { expect(this.packagedCore.files.jsFiles).toEqual([ 'jasmine.js', 'jasmine-html.js' ]); var packagedCore = this.packagedCore; this.packagedCore.files.jsFiles.forEach(function(fileName) { expect(fileName).toExistInPath(packagedCore.files.path); }); }); it('has cssFiles', function() { expect(this.packagedCore.files.cssFiles).toEqual(['jasmine.css']); var packagedCore = this.packagedCore; this.packagedCore.files.cssFiles.forEach(function(fileName) { expect(fileName).toExistInPath(packagedCore.files.path); }); }); it('has bootFiles', function() { expect(this.packagedCore.files.bootFiles).toEqual(['boot0.js', 'boot1.js']); expect(this.packagedCore.files.nodeBootFiles).toEqual(['node_boot.js']); var packagedCore = this.packagedCore; this.packagedCore.files.bootFiles.forEach(function(fileName) { expect(fileName).toExistInPath(packagedCore.files.bootDir); }); var packagedCore = this.packagedCore; this.packagedCore.files.nodeBootFiles.forEach(function(fileName) { expect(fileName).toExistInPath(packagedCore.files.bootDir); }); }); it('has an imagesDir', function() { expect(this.packagedCore.files.imagesDir).toEqual( fs.realpathSync(path.resolve(this.tmpDir, 'package/images')) ); var images = fs.readdirSync(path.resolve(this.tmpDir, 'package/images')); expect(images).toContain('jasmine-horizontal.png'); expect(images).toContain('jasmine-horizontal.svg'); expect(images).toContain('jasmine_favicon.png'); }); it('does not have CI config files and scripts', function() { expect(fs.existsSync(path.resolve(this.tmpDir, 'package/.circleci'))).toBe( false ); expect(fs.existsSync(path.resolve(this.tmpDir, 'package/scripts'))).toBe( false ); }); it('does not have any unexpected files in the root directory', function() { var files = fs.readdirSync(this.tmpDir); expect(files).toEqual(['package']); }); it('does not have any unexpected files in the package directory', function() { var files = fs.readdirSync(path.resolve(this.tmpDir, 'package')); files.sort(); expect(files).toEqual([ 'MIT.LICENSE', 'README.md', 'images', 'lib', 'package.json' ]); }); it('only has images in the images dir', function() { var files = fs.readdirSync(path.resolve(this.tmpDir, 'package/images')), i; for (i = 0; i < files.length; i++) { expect(files[i]).toMatch(/\.(svg|png)$/); } }); it('only has JS and CSS files in the lib dir', function() { var files = [], i; function getFiles(dir) { var dirents = fs.readdirSync(dir, { withFileTypes: true }), j; for (j = 0; j < dirents.length; j++) { const dirent = dirents[j]; if (dirent.isDirectory()) { getFiles(path.resolve(dir, dirent.name)); } else { files.push(path.resolve(dir, dirent.name)); } } } getFiles(path.resolve(this.tmpDir, 'package/lib')); for (i = 0; i < files.length; i++) { expect(files[i]).toMatch(/\.(js|css)$/); } }); }); jasmine-4.0.0/spec/performance/000077500000000000000000000000001416413636100164015ustar00rootroot00000000000000jasmine-4.0.0/spec/performance/large_object_test.js000066400000000000000000000014011416413636100224120ustar00rootroot00000000000000describe('Printing a big object', function() { var bigObject; function rand(upper) { return Math.round(upper * Math.random()); } function generateObject(level) { var object = {}; for (var i = 0; i < 50; i++) { var decide = rand(2); switch (decide) { case 0: object['cycle' + i] = object; break; case 1: object['number' + i] = rand(100); break; case 2: if (level < 3) { object['nesting' + i] = generateObject(level + 1); } break; } } return object; } it('takes a reasonable amount of time', function() { bigObject = generateObject(0); expect(jasmineUnderTest.pp(bigObject)).toMatch(/cycle/); }); }); jasmine-4.0.0/spec/performance/performance_test.js000066400000000000000000000003461416413636100223020ustar00rootroot00000000000000describe('performance', function() { for (var i = 0; i < 10000; i++) { it('should pass', function() { expect(true).toBe(true); }); it('should fail', function() { expect(true).toBe(false); }); } }); jasmine-4.0.0/spec/support/000077500000000000000000000000001416413636100156145ustar00rootroot00000000000000jasmine-4.0.0/spec/support/ci.js000066400000000000000000000006221416413636100165450ustar00rootroot00000000000000/* eslint-env node, es6 */ const path = require('path'), jasmineBrowser = require('jasmine-browser-runner'), jasmineCore = require('../../lib/jasmine-core'); var config = require(path.resolve('spec/support/jasmine-browser.js')); config.clearReporters = true; config.jasmineCore = jasmineCore; jasmineBrowser.runSpecs(config).catch(function(error) { console.error(error); process.exit(1); }); jasmine-4.0.0/spec/support/jasmine-browser-performance.json000066400000000000000000000002651416413636100241200ustar00rootroot00000000000000{ "srcDir": "src", "specDir": "spec", "specFiles": [ "performance/performance_test.js" ], "helpers": [ "helpers/defineJasmineUnderTest.js" ], "random": true } jasmine-4.0.0/spec/support/jasmine-browser.js000066400000000000000000000024301416413636100212600ustar00rootroot00000000000000/* eslint-env node, es6 */ module.exports = { srcDir: 'src', srcFiles: [ 'core/requireCore.js', 'core/base.js', 'core/util.js', 'core/Spec.js', 'core/Env.js', 'core/JsApiReporter.js', 'core/PrettyPrinter.js', 'core/Suite.js', 'core/**/*.js', 'html/**/*.js', '**/*.js', '!boot/**.js' ], specDir: 'spec', specFiles: ['**/*[Ss]pec.js', '!npmPackage/**/*'], helpers: [ 'helpers/generator.js', 'helpers/BrowserFlags.js', 'helpers/domHelpers.js', 'helpers/integrationMatchers.js', 'helpers/defineJasmineUnderTest.js', 'helpers/resetEnv.js' ], random: true, browser: { name: process.env.JASMINE_BROWSER || 'firefox', useSauce: process.env.USE_SAUCE === 'true', sauce: { name: `jasmine-core ${new Date().toISOString()}`, os: process.env.SAUCE_OS, browserVersion: process.env.SAUCE_BROWSER_VERSION, build: `Core ${process.env.TRAVIS_BUILD_NUMBER || 'Ran locally'}`, tags: ['Jasmine-Core'], tunnelIdentifier: process.env.SAUCE_TUNNEL_IDENTIFIER, username: process.env.SAUCE_USERNAME, accessKey: process.env.SAUCE_ACCESS_KEY } } }; if (process.env.SKIP_JASMINE_BROWSER_FLAKES === 'true') { module.exports.helpers.push('helpers/disableBrowserFlakes.js'); } jasmine-4.0.0/spec/support/jasmine-performance.json000066400000000000000000000002551416413636100224360ustar00rootroot00000000000000{ "spec_dir": "spec", "spec_files": [ "performance/performance_test.js" ], "helper_files": [ "helpers/nodeDefineJasmineUnderTest.js" ], "random": true } jasmine-4.0.0/spec/support/jasmine-performance.yml000066400000000000000000000002311416413636100222600ustar00rootroot00000000000000src_dir: - 'src' src_files: - '**/*.js' helpers: - 'helpers/**/*.js' spec_files: - 'performance/performance_test.js' spec_dir: spec random: true jasmine-4.0.0/spec/support/jasmine.json000066400000000000000000000005131416413636100201340ustar00rootroot00000000000000{ "spec_dir": "spec", "spec_files": [ "core/**/*[Ss]pec.js", "npmPackage/**/*[Ss]pec.js" ], "helpers": [ "helpers/domHelpers.js", "helpers/integrationMatchers.js", "helpers/overrideConsoleLogForCircleCi.js", "helpers/nodeDefineJasmineUnderTest.js", "helpers/resetEnv.js" ], "random": true } jasmine-4.0.0/spec/support/localJasmineBrowser.js000066400000000000000000000005501416413636100221170ustar00rootroot00000000000000var path = require('path'), jasmineBrowser = require('jasmine-browser-runner'), jasmineCore = require('../../lib/jasmine-core.js'); var configFile = process.argv[2] || 'jasmine-browser.js'; var config = require(path.resolve('spec/support', configFile)); config.jasmineCore = jasmineCore; config.batchReporter = true; jasmineBrowser.startServer(config); jasmine-4.0.0/src/000077500000000000000000000000001416413636100137355ustar00rootroot00000000000000jasmine-4.0.0/src/boot/000077500000000000000000000000001416413636100147005ustar00rootroot00000000000000jasmine-4.0.0/src/boot/boot0.js000066400000000000000000000031401416413636100162570ustar00rootroot00000000000000/** This file starts the process of "booting" Jasmine. It initializes Jasmine, makes its globals available, and creates the env. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project source files or spec files are loaded. */ (function() { var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); /** * ## Require & Instantiate * * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. */ var jasmine = jasmineRequire.core(jasmineRequire), global = jasmine.getGlobal(); global.jasmine = jasmine; /** * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. */ jasmineRequire.html(jasmine); /** * Create the Jasmine environment. This is used to run all specs in a project. */ var env = jasmine.getEnv(); /** * ## The Global Interface * * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. */ var jasmineInterface = jasmineRequire.interface(jasmine, env); /** * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. */ for (var property in jasmineInterface) { global[property] = jasmineInterface[property]; } })(); jasmine-4.0.0/src/boot/boot1.js000066400000000000000000000065651416413636100162760ustar00rootroot00000000000000/** This file finishes 'booting' Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `boot0.js` but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. If a project is using Jasmine via the standalone distribution, this file can be customized directly. If you only wish to configure the Jasmine env, you can load another file that calls `jasmine.getEnv().configure({...})` after `boot0.js` is loaded and before this file is loaded. */ (function() { var env = jasmine.getEnv(); /** * ## Runner Parameters * * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. */ var queryString = new jasmine.QueryString({ getWindowLocation: function() { return window.location; } }); var filterSpecs = !!queryString.getParam('spec'); var config = { stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'), stopSpecOnExpectationFailure: queryString.getParam( 'stopSpecOnExpectationFailure' ), hideDisabled: queryString.getParam('hideDisabled') }; var random = queryString.getParam('random'); if (random !== undefined && random !== '') { config.random = random; } var seed = queryString.getParam('seed'); if (seed) { config.seed = seed; } /** * ## Reporters * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). */ var htmlReporter = new jasmine.HtmlReporter({ env: env, navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, getContainer: function() { return document.body; }, createElement: function() { return document.createElement.apply(document, arguments); }, createTextNode: function() { return document.createTextNode.apply(document, arguments); }, timer: new jasmine.Timer(), filterSpecs: filterSpecs }); /** * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. */ env.addReporter(jsApiReporter); env.addReporter(htmlReporter); /** * Filter which specs will be run by matching the start of the full name against the `spec` query param. */ var specFilter = new jasmine.HtmlSpecFilter({ filterString: function() { return queryString.getParam('spec'); } }); config.specFilter = function(spec) { return specFilter.matches(spec.getFullName()); }; env.configure(config); /** * ## Execution * * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. */ var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } htmlReporter.initialize(); env.execute(); }; })(); jasmine-4.0.0/src/boot/node_boot.js000066400000000000000000000006521416413636100172110ustar00rootroot00000000000000module.exports = function(jasmineRequire) { var jasmine = jasmineRequire.core(jasmineRequire); var env = jasmine.getEnv({ suppressLoadErrors: true }); var jasmineInterface = jasmineRequire.interface(jasmine, env); extend(global, jasmineInterface); function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; } return jasmine; }; jasmine-4.0.0/src/core/000077500000000000000000000000001416413636100146655ustar00rootroot00000000000000jasmine-4.0.0/src/core/CallTracker.js000066400000000000000000000057751416413636100174300ustar00rootroot00000000000000getJasmineRequireObj().CallTracker = function(j$) { /** * @namespace Spy#calls * @since 2.0.0 */ function CallTracker() { var calls = []; var opts = {}; this.track = function(context) { if (opts.cloneArgs) { context.args = j$.util.cloneArgs(context.args); } calls.push(context); }; /** * Check whether this spy has been invoked. * @name Spy#calls#any * @since 2.0.0 * @function * @return {Boolean} */ this.any = function() { return !!calls.length; }; /** * Get the number of invocations of this spy. * @name Spy#calls#count * @since 2.0.0 * @function * @return {Integer} */ this.count = function() { return calls.length; }; /** * Get the arguments that were passed to a specific invocation of this spy. * @name Spy#calls#argsFor * @since 2.0.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Array} */ this.argsFor = function(index) { var call = calls[index]; return call ? call.args : []; }; /** * Get the "this" object that was passed to a specific invocation of this spy. * @name Spy#calls#thisFor * @since 3.8.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Object?} */ this.thisFor = function(index) { var call = calls[index]; return call ? call.object : undefined; }; /** * Get the raw calls array for this spy. * @name Spy#calls#all * @since 2.0.0 * @function * @return {Spy.callData[]} */ this.all = function() { return calls; }; /** * Get all of the arguments for each invocation of this spy in the order they were received. * @name Spy#calls#allArgs * @since 2.0.0 * @function * @return {Array} */ this.allArgs = function() { var callArgs = []; for (var i = 0; i < calls.length; i++) { callArgs.push(calls[i].args); } return callArgs; }; /** * Get the first invocation of this spy. * @name Spy#calls#first * @since 2.0.0 * @function * @return {ObjecSpy.callData} */ this.first = function() { return calls[0]; }; /** * Get the most recent invocation of this spy. * @name Spy#calls#mostRecent * @since 2.0.0 * @function * @return {ObjecSpy.callData} */ this.mostRecent = function() { return calls[calls.length - 1]; }; /** * Reset this spy as if it has never been called. * @name Spy#calls#reset * @since 2.0.0 * @function */ this.reset = function() { calls = []; }; /** * Set this spy to do a shallow clone of arguments passed to each invocation. * @name Spy#calls#saveArgumentsByValue * @since 2.5.0 * @function */ this.saveArgumentsByValue = function() { opts.cloneArgs = true; }; } return CallTracker; }; jasmine-4.0.0/src/core/ClearStack.js000066400000000000000000000032121416413636100172350ustar00rootroot00000000000000getJasmineRequireObj().clearStack = function(j$) { var maxInlineCallCount = 10; function messageChannelImpl(global, setTimeout) { var channel = new global.MessageChannel(), head = {}, tail = head; var taskRunning = false; channel.port1.onmessage = function() { head = head.next; var task = head.task; delete head.task; if (taskRunning) { global.setTimeout(task, 0); } else { try { taskRunning = true; task(); } finally { taskRunning = false; } } }; var currentCallCount = 0; return function clearStack(fn) { currentCallCount++; if (currentCallCount < maxInlineCallCount) { tail = tail.next = { task: fn }; channel.port2.postMessage(0); } else { currentCallCount = 0; setTimeout(fn); } }; } function getClearStack(global) { var currentCallCount = 0; var realSetTimeout = global.setTimeout; var setTimeoutImpl = function clearStack(fn) { Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]); }; if (j$.isFunction_(global.setImmediate)) { var realSetImmediate = global.setImmediate; return function(fn) { currentCallCount++; if (currentCallCount < maxInlineCallCount) { realSetImmediate(fn); } else { currentCallCount = 0; setTimeoutImpl(fn); } }; } else if (!j$.util.isUndefined(global.MessageChannel)) { return messageChannelImpl(global, setTimeoutImpl); } else { return setTimeoutImpl; } } return getClearStack; }; jasmine-4.0.0/src/core/Clock.js000066400000000000000000000133121416413636100162560ustar00rootroot00000000000000getJasmineRequireObj().Clock = function() { /* global process */ var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string'; /** * @class Clock * @since 1.3.0 * @classdesc Jasmine's mock clock is used when testing time dependent code.
* _Note:_ Do not construct this directly. You can get the current clock with * {@link jasmine.clock}. * @hideconstructor */ function Clock(global, delayedFunctionSchedulerFactory, mockDate) { var self = this, realTimingFunctions = { setTimeout: global.setTimeout, clearTimeout: global.clearTimeout, setInterval: global.setInterval, clearInterval: global.clearInterval }, fakeTimingFunctions = { setTimeout: setTimeout, clearTimeout: clearTimeout, setInterval: setInterval, clearInterval: clearInterval }, installed = false, delayedFunctionScheduler, timer; self.FakeTimeout = FakeTimeout; /** * Install the mock clock over the built-in methods. * @name Clock#install * @since 2.0.0 * @function * @return {Clock} */ self.install = function() { if (!originalTimingFunctionsIntact()) { throw new Error( 'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?' ); } replace(global, fakeTimingFunctions); timer = fakeTimingFunctions; delayedFunctionScheduler = delayedFunctionSchedulerFactory(); installed = true; return self; }; /** * Uninstall the mock clock, returning the built-in methods to their places. * @name Clock#uninstall * @since 2.0.0 * @function */ self.uninstall = function() { delayedFunctionScheduler = null; mockDate.uninstall(); replace(global, realTimingFunctions); timer = realTimingFunctions; installed = false; }; /** * Execute a function with a mocked Clock * * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes. * @name Clock#withMock * @since 2.3.0 * @function * @param {Function} closure The function to be called. */ self.withMock = function(closure) { this.install(); try { closure(); } finally { this.uninstall(); } }; /** * Instruct the installed Clock to also mock the date returned by `new Date()` * @name Clock#mockDate * @since 2.1.0 * @function * @param {Date} [initialDate=now] The `Date` to provide. */ self.mockDate = function(initialDate) { mockDate.install(initialDate); }; self.setTimeout = function(fn, delay, params) { return Function.prototype.apply.apply(timer.setTimeout, [ global, arguments ]); }; self.setInterval = function(fn, delay, params) { return Function.prototype.apply.apply(timer.setInterval, [ global, arguments ]); }; self.clearTimeout = function(id) { return Function.prototype.call.apply(timer.clearTimeout, [global, id]); }; self.clearInterval = function(id) { return Function.prototype.call.apply(timer.clearInterval, [global, id]); }; /** * Tick the Clock forward, running any enqueued timeouts along the way * @name Clock#tick * @since 1.3.0 * @function * @param {int} millis The number of milliseconds to tick. */ self.tick = function(millis) { if (installed) { delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); }); } else { throw new Error( 'Mock clock is not installed, use jasmine.clock().install()' ); } }; return self; function originalTimingFunctionsIntact() { return ( global.setTimeout === realTimingFunctions.setTimeout && global.clearTimeout === realTimingFunctions.clearTimeout && global.setInterval === realTimingFunctions.setInterval && global.clearInterval === realTimingFunctions.clearInterval ); } function replace(dest, source) { for (var prop in source) { dest[prop] = source[prop]; } } function setTimeout(fn, delay) { if (!NODE_JS) { return delayedFunctionScheduler.scheduleFunction( fn, delay, argSlice(arguments, 2) ); } var timeout = new FakeTimeout(); delayedFunctionScheduler.scheduleFunction( fn, delay, argSlice(arguments, 2), false, timeout ); return timeout; } function clearTimeout(id) { return delayedFunctionScheduler.removeFunctionWithId(id); } function setInterval(fn, interval) { if (!NODE_JS) { return delayedFunctionScheduler.scheduleFunction( fn, interval, argSlice(arguments, 2), true ); } var timeout = new FakeTimeout(); delayedFunctionScheduler.scheduleFunction( fn, interval, argSlice(arguments, 2), true, timeout ); return timeout; } function clearInterval(id) { return delayedFunctionScheduler.removeFunctionWithId(id); } function argSlice(argsObj, n) { return Array.prototype.slice.call(argsObj, n); } } /** * Mocks Node.js Timeout class */ function FakeTimeout() {} FakeTimeout.prototype.ref = function() { return this; }; FakeTimeout.prototype.unref = function() { return this; }; return Clock; }; jasmine-4.0.0/src/core/CompleteOnFirstErrorSkipPolicy.js000066400000000000000000000025201416413636100233200ustar00rootroot00000000000000getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.erroredFnIx_ = null; } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { let i; for ( i = lastRanFnIx + 1; i < this.queueableFns_.length && this.shouldSkip_(i); i++ ) {} return i; }; CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { this.erroredFnIx_ = fnIx; }; CompleteOnFirstErrorSkipPolicy.prototype.shouldSkip_ = function(fnIx) { if (this.erroredFnIx_ === null) { return false; } const fn = this.queueableFns_[fnIx]; const candidateSuite = fn.suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; const wasCleanupFn = fn.type === 'afterEach' || fn.type === 'afterAll' || fn.type === 'specCleanup'; return ( !wasCleanupFn || (candidateSuite && isDescendent(candidateSuite, errorSuite)) ); }; function isDescendent(candidate, ancestor) { if (!candidate.parentSuite) { return false; } else if (candidate.parentSuite === ancestor) { return true; } else { return isDescendent(candidate.parentSuite, ancestor); } } return CompleteOnFirstErrorSkipPolicy; }; jasmine-4.0.0/src/core/DelayedFunctionScheduler.js000066400000000000000000000113541416413636100221430ustar00rootroot00000000000000getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function DelayedFunctionScheduler() { var self = this; var scheduledLookup = []; var scheduledFunctions = {}; var currentTime = 0; var delayedFnCount = 0; var deletedKeys = []; self.tick = function(millis, tickDate) { millis = millis || 0; var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); }; self.scheduleFunction = function( funcToCall, millis, params, recurring, timeoutKey, runAtMillis ) { var f; if (typeof funcToCall === 'string') { /* jshint evil: true */ f = function() { return eval(funcToCall); }; /* jshint evil: false */ } else { f = funcToCall; } millis = millis || 0; timeoutKey = timeoutKey || ++delayedFnCount; runAtMillis = runAtMillis || currentTime + millis; var funcToSchedule = { runAtMillis: runAtMillis, funcToCall: f, recurring: recurring, params: params, timeoutKey: timeoutKey, millis: millis }; if (runAtMillis in scheduledFunctions) { scheduledFunctions[runAtMillis].push(funcToSchedule); } else { scheduledFunctions[runAtMillis] = [funcToSchedule]; scheduledLookup.push(runAtMillis); scheduledLookup.sort(function(a, b) { return a - b; }); } return timeoutKey; }; self.removeFunctionWithId = function(timeoutKey) { deletedKeys.push(timeoutKey); for (var runAtMillis in scheduledFunctions) { var funcs = scheduledFunctions[runAtMillis]; var i = indexOfFirstToPass(funcs, function(func) { return func.timeoutKey === timeoutKey; }); if (i > -1) { if (funcs.length === 1) { delete scheduledFunctions[runAtMillis]; deleteFromLookup(runAtMillis); } else { funcs.splice(i, 1); } // intervals get rescheduled when executed, so there's never more // than a single scheduled function with a given timeoutKey break; } } }; return self; function indexOfFirstToPass(array, testFn) { var index = -1; for (var i = 0; i < array.length; ++i) { if (testFn(array[i])) { index = i; break; } } return index; } function deleteFromLookup(key) { var value = Number(key); var i = indexOfFirstToPass(scheduledLookup, function(millis) { return millis === value; }); if (i > -1) { scheduledLookup.splice(i, 1); } } function reschedule(scheduledFn) { self.scheduleFunction( scheduledFn.funcToCall, scheduledFn.millis, scheduledFn.params, true, scheduledFn.timeoutKey, scheduledFn.runAtMillis + scheduledFn.millis ); } function forEachFunction(funcsToRun, callback) { for (var i = 0; i < funcsToRun.length; ++i) { callback(funcsToRun[i]); } } function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { if (endTime >= currentTime) { tickDate(endTime - currentTime); currentTime = endTime; } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); if (newCurrentTime >= currentTime) { tickDate(newCurrentTime - currentTime); currentTime = newCurrentTime; } var funcsToRun = scheduledFunctions[currentTime]; delete scheduledFunctions[currentTime]; forEachFunction(funcsToRun, function(funcToRun) { if (funcToRun.recurring) { reschedule(funcToRun); } }); forEachFunction(funcsToRun, function(funcToRun) { if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) { // skip a timeoutKey deleted whilst we were running return; } funcToRun.funcToCall.apply(null, funcToRun.params || []); }); deletedKeys = []; } while ( scheduledLookup.length > 0 && // checking first if we're out of time prevents setTimeout(0) // scheduled in a funcToRun from forcing an extra iteration currentTime !== endTime && scheduledLookup[0] <= endTime ); // ran out of functions to call, but still time left on the clock if (endTime >= currentTime) { tickDate(endTime - currentTime); currentTime = endTime; } } } return DelayedFunctionScheduler; }; jasmine-4.0.0/src/core/Deprecator.js000066400000000000000000000044521416413636100173200ustar00rootroot00000000000000getJasmineRequireObj().Deprecator = function(j$) { function Deprecator(topSuite) { this.topSuite_ = topSuite; this.verbose_ = false; this.toSuppress_ = []; } var verboseNote = 'Note: This message will be shown only once. Set the verboseDeprecations ' + 'config property to true to see every occurrence.'; Deprecator.prototype.verboseDeprecations = function(enabled) { this.verbose_ = enabled; }; // runnable is a spec or a suite. // deprecation is a string or an Error. // See Env#deprecated for a description of the options argument. Deprecator.prototype.addDeprecationWarning = function( runnable, deprecation, options ) { options = options || {}; if (!this.verbose_ && !j$.isError_(deprecation)) { if (this.toSuppress_.indexOf(deprecation) !== -1) { return; } this.toSuppress_.push(deprecation); } this.log_(runnable, deprecation, options); this.report_(runnable, deprecation, options); }; Deprecator.prototype.log_ = function(runnable, deprecation, options) { var context; if (j$.isError_(deprecation)) { console.error(deprecation); return; } if (runnable === this.topSuite_ || options.ignoreRunnable) { context = ''; } else if (runnable.children) { context = ' (in suite: ' + runnable.getFullName() + ')'; } else { context = ' (in spec: ' + runnable.getFullName() + ')'; } if (!options.omitStackTrace) { context += '\n' + this.stackTrace_(); } if (!this.verbose_) { context += '\n' + verboseNote; } console.error('DEPRECATION: ' + deprecation + context); }; Deprecator.prototype.stackTrace_ = function() { var formatter = new j$.ExceptionFormatter(); return formatter.stack(j$.util.errorWithStack()).replace(/^Error\n/m, ''); }; Deprecator.prototype.report_ = function(runnable, deprecation, options) { if (options.ignoreRunnable) { runnable = this.topSuite_; } if (j$.isError_(deprecation)) { runnable.addDeprecationWarning(deprecation); return; } if (!this.verbose_) { deprecation += '\n' + verboseNote; } runnable.addDeprecationWarning({ message: deprecation, omitStackTrace: options.omitStackTrace || false }); }; return Deprecator; }; jasmine-4.0.0/src/core/Env.js000066400000000000000000001266401416413636100157640ustar00rootroot00000000000000getJasmineRequireObj().Env = function(j$) { /** * @class Env * @since 2.0.0 * @classdesc The Jasmine environment.
* _Note:_ Do not construct this directly. You can obtain the Env instance by * calling {@link jasmine.getEnv}. * @hideconstructor */ function Env(options) { options = options || {}; var self = this; var global = options.global || j$.getGlobal(); var totalSpecsDefined = 0; var realSetTimeout = global.setTimeout; var realClearTimeout = global.clearTimeout; var clearStack = j$.getClearStack(global); this.clock = new j$.Clock( global, function() { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global) ); var runnableResources = {}; var currentSpec = null; var currentlyExecutingSuites = []; var currentDeclarationSuite = null; var hasFailures = false; /** * This represents the available options to configure Jasmine. * Options that are not provided will use their default values. * @see Env#configure * @interface Configuration * @since 3.3.0 */ var config = { /** * Whether to randomize spec execution order * @name Configuration#random * @since 3.3.0 * @type Boolean * @default true */ random: true, /** * Seed to use as the basis of randomization. * Null causes the seed to be determined randomly at the start of execution. * @name Configuration#seed * @since 3.3.0 * @type (number|string) * @default null */ seed: null, /** * Whether to stop execution of the suite after the first spec failure * @name Configuration#stopOnSpecFailure * @since 3.9.0 * @type Boolean * @default false */ stopOnSpecFailure: false, /** * Whether to fail the spec if it ran no expectations. By default * a spec that ran no expectations is reported as passed. Setting this * to true will report such spec as a failure. * @name Configuration#failSpecWithNoExpectations * @since 3.5.0 * @type Boolean * @default false */ failSpecWithNoExpectations: false, /** * Whether to cause specs to only have one expectation failure. * @name Configuration#stopSpecOnExpectationFailure * @since 3.3.0 * @type Boolean * @default false */ stopSpecOnExpectationFailure: false, /** * A function that takes a spec and returns true if it should be executed * or false if it should be skipped. * @callback SpecFilter * @param {Spec} spec - The spec that the filter is being applied to. * @return boolean */ /** * Function to use to filter specs * @name Configuration#specFilter * @since 3.3.0 * @type SpecFilter * @default A function that always returns true. */ specFilter: function() { return true; }, /** * Whether or not reporters should hide disabled specs from their output. * Currently only supported by Jasmine's HTMLReporter * @name Configuration#hideDisabled * @since 3.3.0 * @type Boolean * @default false */ hideDisabled: false, /** * Clean closures when a suite is done running (done by clearing the stored function reference). * This prevents memory leaks, but you won't be able to run jasmine multiple times. * @name Configuration#autoCleanClosures * @since 3.10.0 * @type boolean * @default true */ autoCleanClosures: true, /** * Whether or not to issue warnings for certain deprecated functionality * every time it's used. If not set or set to false, deprecation warnings * for methods that tend to be called frequently will be issued only once * or otherwise throttled to to prevent the suite output from being flooded * with warnings. * @name Configuration#verboseDeprecations * @since 3.6.0 * @type Boolean * @default false */ verboseDeprecations: false }; var currentSuite = function() { return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; }; var currentRunnable = function() { return currentSpec || currentSuite(); }; var globalErrors = null; var installGlobalErrors = function() { if (globalErrors) { return; } globalErrors = new j$.GlobalErrors(); globalErrors.install(); }; if (!options.suppressLoadErrors) { installGlobalErrors(); globalErrors.pushListener(function( message, filename, lineno, colNo, err ) { topSuite.result.failedExpectations.push({ passed: false, globalErrorType: 'load', message: message, stack: err && err.stack, filename: filename, lineno: lineno }); }); } /** * Configure your jasmine environment * @name Env#configure * @since 3.3.0 * @argument {Configuration} configuration * @function */ this.configure = function(configuration) { var booleanProps = [ 'random', 'failSpecWithNoExpectations', 'hideDisabled', 'stopOnSpecFailure', 'stopSpecOnExpectationFailure', 'autoCleanClosures' ]; booleanProps.forEach(function(prop) { if (typeof configuration[prop] !== 'undefined') { config[prop] = !!configuration[prop]; } }); if (configuration.specFilter) { config.specFilter = configuration.specFilter; } if (typeof configuration.seed !== 'undefined') { config.seed = configuration.seed; } if (configuration.hasOwnProperty('verboseDeprecations')) { config.verboseDeprecations = configuration.verboseDeprecations; deprecator.verboseDeprecations(config.verboseDeprecations); } }; /** * Get the current configuration for your jasmine environment * @name Env#configuration * @since 3.3.0 * @function * @returns {Configuration} */ this.configuration = function() { var result = {}; for (var property in config) { result[property] = config[property]; } return result; }; this.setDefaultSpyStrategy = function(defaultStrategyFn) { if (!currentRunnable()) { throw new Error( 'Default spy strategy must be set in a before function or a spec' ); } runnableResources[ currentRunnable().id ].defaultStrategyFn = defaultStrategyFn; }; this.addSpyStrategy = function(name, fn) { if (!currentRunnable()) { throw new Error( 'Custom spy strategies must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customSpyStrategies[name] = fn; }; this.addCustomEqualityTester = function(tester) { if (!currentRunnable()) { throw new Error( 'Custom Equalities must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customEqualityTesters.push( tester ); }; this.addMatchers = function(matchersToAdd) { if (!currentRunnable()) { throw new Error( 'Matchers must be added in a before function or a spec' ); } var customMatchers = runnableResources[currentRunnable().id].customMatchers; for (var matcherName in matchersToAdd) { customMatchers[matcherName] = matchersToAdd[matcherName]; } }; this.addAsyncMatchers = function(matchersToAdd) { if (!currentRunnable()) { throw new Error( 'Async Matchers must be added in a before function or a spec' ); } var customAsyncMatchers = runnableResources[currentRunnable().id].customAsyncMatchers; for (var matcherName in matchersToAdd) { customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; } }; this.addCustomObjectFormatter = function(formatter) { if (!currentRunnable()) { throw new Error( 'Custom object formatters must be added in a before function or a spec' ); } runnableResources[currentRunnable().id].customObjectFormatters.push( formatter ); }; j$.Expectation.addCoreMatchers(j$.matchers); j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers); var nextSpecId = 0; var getNextSpecId = function() { return 'spec' + nextSpecId++; }; var nextSuiteId = 0; var getNextSuiteId = function() { return 'suite' + nextSuiteId++; }; var makePrettyPrinter = function() { var customObjectFormatters = runnableResources[currentRunnable().id].customObjectFormatters; return j$.makePrettyPrinter(customObjectFormatters); }; var makeMatchersUtil = function() { const cr = currentRunnable(); if (cr) { const customEqualityTesters = runnableResources[cr.id].customEqualityTesters; return new j$.MatchersUtil({ customTesters: customEqualityTesters, pp: makePrettyPrinter() }); } else { return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ }); } }; var expectationFactory = function(actual, spec) { return j$.Expectation.factory({ matchersUtil: makeMatchersUtil(), customMatchers: runnableResources[spec.id].customMatchers, actual: actual, addExpectationResult: addExpectationResult }); function addExpectationResult(passed, result) { return spec.addExpectationResult(passed, result); } }; function recordLateError(error) { const result = expectationResultFactory({ error, passed: false, matcherName: '', expected: '', actual: '' }); result.globalErrorType = 'lateError'; topSuite.result.failedExpectations.push(result); } function recordLateExpectation(runable, runableType, result) { var delayedExpectationResult = {}; Object.keys(result).forEach(function(k) { delayedExpectationResult[k] = result[k]; }); delayedExpectationResult.passed = false; delayedExpectationResult.globalErrorType = 'lateExpectation'; delayedExpectationResult.message = runableType + ' "' + runable.getFullName() + '" ran a "' + result.matcherName + '" expectation after it finished.\n'; if (result.message) { delayedExpectationResult.message += 'Message: "' + result.message + '"\n'; } delayedExpectationResult.message += '1. Did you forget to return or await the result of expectAsync?\n' + '2. Was done() invoked before an async operation completed?\n' + '3. Did an expectation follow a call to done()?'; topSuite.result.failedExpectations.push(delayedExpectationResult); } var asyncExpectationFactory = function(actual, spec, runableType) { return j$.Expectation.asyncFactory({ matchersUtil: makeMatchersUtil(), customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, actual: actual, addExpectationResult: addExpectationResult }); function addExpectationResult(passed, result) { if (currentRunnable() !== spec) { recordLateExpectation(spec, runableType, result); } return spec.addExpectationResult(passed, result); } }; var suiteAsyncExpectationFactory = function(actual, suite) { return asyncExpectationFactory(actual, suite, 'Suite'); }; var specAsyncExpectationFactory = function(actual, suite) { return asyncExpectationFactory(actual, suite, 'Spec'); }; var defaultResourcesForRunnable = function(id, parentRunnableId) { var resources = { spies: [], customEqualityTesters: [], customMatchers: {}, customAsyncMatchers: {}, customSpyStrategies: {}, defaultStrategyFn: undefined, customObjectFormatters: [] }; if (runnableResources[parentRunnableId]) { resources.customEqualityTesters = j$.util.clone( runnableResources[parentRunnableId].customEqualityTesters ); resources.customMatchers = j$.util.clone( runnableResources[parentRunnableId].customMatchers ); resources.customAsyncMatchers = j$.util.clone( runnableResources[parentRunnableId].customAsyncMatchers ); resources.customObjectFormatters = j$.util.clone( runnableResources[parentRunnableId].customObjectFormatters ); resources.customSpyStrategies = j$.util.clone( runnableResources[parentRunnableId].customSpyStrategies ); resources.defaultStrategyFn = runnableResources[parentRunnableId].defaultStrategyFn; } runnableResources[id] = resources; }; var clearResourcesForRunnable = function(id) { spyRegistry.clearSpies(); delete runnableResources[id]; }; var beforeAndAfterFns = function(targetSuite) { return function() { var befores = [], afters = [], suite = targetSuite; while (suite) { befores = befores.concat(suite.beforeFns); afters = afters.concat(suite.afterFns); suite = suite.parentSuite; } return { befores: befores.reverse(), afters: afters }; }; }; var getSpecName = function(spec, suite) { var fullName = [spec.description], suiteFullName = suite.getFullName(); if (suiteFullName !== '') { fullName.unshift(suiteFullName); } return fullName.join(' '); }; // TODO: we may just be able to pass in the fn instead of wrapping here var buildExpectationResult = j$.buildExpectationResult, exceptionFormatter = new j$.ExceptionFormatter(), expectationResultFactory = function(attrs) { attrs.messageFormatter = exceptionFormatter.message; attrs.stackFormatter = exceptionFormatter.stack; return buildExpectationResult(attrs); }; /** * Causes a deprecation warning to be logged to the console and reported to * reporters. * * The optional second parameter is an object that can have either of the * following properties: * * omitStackTrace: Whether to omit the stack trace. Optional. Defaults to * false. This option is ignored if the deprecation is an Error. Set this * when the stack trace will not contain anything that helps the user find * the source of the deprecation. * * ignoreRunnable: Whether to log the deprecation on the root suite, ignoring * the spec or suite that's running when it happens. Optional. Defaults to * false. * * @name Env#deprecated * @since 2.99 * @function * @param {String|Error} deprecation The deprecation message * @param {Object} [options] Optional extra options, as described above */ this.deprecated = function(deprecation, options) { var runnable = currentRunnable() || topSuite; deprecator.addDeprecationWarning(runnable, deprecation, options); }; var queueRunnerFactory = function(options, args) { if (options.isLeaf) { // A spec options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; } else if (options.isReporter) { // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; } else { // A suite if (config.stopOnSpecFailure) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; } else { options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; } } options.clearStack = options.clearStack || clearStack; options.timeout = { setTimeout: realSetTimeout, clearTimeout: realClearTimeout }; options.fail = self.fail; options.globalErrors = globalErrors; options.onException = options.onException || function(e) { (currentRunnable() || topSuite).onException(e); }; options.deprecated = self.deprecated; new j$.QueueRunner(options).execute(args); }; var topSuite = new j$.Suite({ id: getNextSuiteId(), description: 'Jasmine__TopLevel__Suite', expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, autoCleanClosures: config.autoCleanClosures, onLateError: recordLateError }); var deprecator = new j$.Deprecator(topSuite); currentDeclarationSuite = topSuite; /** * Provides the root suite, through which all suites and specs can be * accessed. * @function * @name Env#topSuite * @return {Suite} the root suite * @since 2.0.0 */ this.topSuite = function() { return topSuite.metadata; }; /** * This represents the available reporter callback for an object passed to {@link Env#addReporter}. * @interface Reporter * @see custom_reporter */ var reporter = new j$.ReportDispatcher( [ /** * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts. * @function * @name Reporter#jasmineStarted * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'jasmineStarted', /** * When the entire suite has finished execution `jasmineDone` is called * @function * @name Reporter#jasmineDone * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'jasmineDone', /** * `suiteStarted` is invoked when a `describe` starts to run * @function * @name Reporter#suiteStarted * @param {SuiteResult} result Information about the individual {@link describe} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'suiteStarted', /** * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run * * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`. * @function * @name Reporter#suiteDone * @param {SuiteResult} result * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'suiteDone', /** * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions) * @function * @name Reporter#specStarted * @param {SpecResult} result Information about the individual {@link it} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'specStarted', /** * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run. * * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed. * @function * @name Reporter#specDone * @param {SpecResult} result * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @see async */ 'specDone' ], queueRunnerFactory, recordLateError ); /** * Executes the specs. * * If called with no parameters or with a falsy value as the first parameter, * all specs will be executed except those that are excluded by a * [spec filter]{@link Configuration#specFilter} or other mechanism. If the * first parameter is a list of spec/suite IDs, only those specs/suites will * be run. * * Both parameters are optional, but a completion callback is only valid as * the second parameter. To specify a completion callback but not a list of * specs/suites to run, pass null or undefined as the first parameter. The * completion callback is supported for backward compatibility. In most * cases it will be more convenient to use the returned promise instead. * * execute should not be called more than once unless the env has been * configured with `{autoCleanClosures: false}`. * * execute returns a promise. The promise will be resolved to the same * {@link JasmineDoneInfo|overall result} that's passed to a reporter's * `jasmineDone` method, even if the suite did not pass. To determine * whether the suite passed, check the value that the promise resolves to * or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { topSuite.reset(); } this._executedBefore = true; defaultResourcesForRunnable(topSuite.id); installGlobalErrors(); if (!runnablesToRun) { if (focusedRunnables.length) { runnablesToRun = focusedRunnables; } else { runnablesToRun = [topSuite.id]; } } var order = new j$.Order({ random: config.random, seed: config.seed }); var processor = new j$.TreeProcessor({ tree: topSuite, runnableIds: runnablesToRun, queueRunnerFactory: queueRunnerFactory, failSpecWithNoExpectations: config.failSpecWithNoExpectations, nodeStart: function(suite, next) { currentlyExecutingSuites.push(suite); defaultResourcesForRunnable(suite.id, suite.parentSuite.id); reporter.suiteStarted(suite.result, next); suite.startTimer(); }, nodeComplete: function(suite, result, next) { if (suite !== currentSuite()) { throw new Error('Tried to complete the wrong suite'); } clearResourcesForRunnable(suite.id); currentlyExecutingSuites.pop(); if (result.status === 'failed') { hasFailures = true; } suite.endTimer(); if (suite.hadBeforeAllFailure) { reportChildrenOfBeforeAllFailure(suite).then(function() { reporter.suiteDone(result, next); }); } else { reporter.suiteDone(result, next); } }, orderChildren: function(node) { return order.sort(node.children); }, excludeNode: function(spec) { return !config.specFilter(spec); } }); if (!processor.processTree().valid) { throw new Error( 'Invalid order: would cause a beforeAll or afterAll to be run multiple times' ); } var jasmineTimer = new j$.Timer(); jasmineTimer.start(); return new Promise(function(resolve) { runAll(function(jasmineDoneInfo) { if (onComplete) { onComplete(); } resolve(jasmineDoneInfo); }); }); function runAll(done) { /** * Information passed to the {@link Reporter#jasmineStarted} event. * @typedef JasmineStartedInfo * @property {Int} totalSpecsDefined - The total number of specs defined in this suite. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @since 2.0.0 */ reporter.jasmineStarted( { totalSpecsDefined: totalSpecsDefined, order: order }, function() { currentlyExecutingSuites.push(topSuite); processor.execute(function() { (async function() { if (topSuite.hadBeforeAllFailure) { await reportChildrenOfBeforeAllFailure(topSuite); } clearResourcesForRunnable(topSuite.id); currentlyExecutingSuites.pop(); var overallStatus, incompleteReason; if ( hasFailures || topSuite.result.failedExpectations.length > 0 ) { overallStatus = 'failed'; } else if (focusedRunnables.length > 0) { overallStatus = 'incomplete'; incompleteReason = 'fit() or fdescribe() was found'; } else if (totalSpecsDefined === 0) { overallStatus = 'incomplete'; incompleteReason = 'No specs found'; } else { overallStatus = 'passed'; } /** * Information passed to the {@link Reporter#jasmineDone} event. * @typedef JasmineDoneInfo * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. * @property {Int} totalTime - The total time (in ms) that it took to execute the suite * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. * @since 2.4.0 */ const jasmineDoneInfo = { overallStatus: overallStatus, totalTime: jasmineTimer.elapsed(), incompleteReason: incompleteReason, order: order, failedExpectations: topSuite.result.failedExpectations, deprecationWarnings: topSuite.result.deprecationWarnings }; reporter.jasmineDone(jasmineDoneInfo, function() { done(jasmineDoneInfo); }); })(); }); } ); } async function reportChildrenOfBeforeAllFailure(suite) { for (const child of suite.children) { if (child instanceof j$.Suite) { await new Promise(function(resolve) { reporter.suiteStarted(child.result, resolve); }); await reportChildrenOfBeforeAllFailure(child); // Marking the suite passed is consistent with how suites that // contain failed specs but no suite-level failures are reported. child.result.status = 'passed'; await new Promise(function(resolve) { reporter.suiteDone(child.result, resolve); }); } else { /* a spec */ await new Promise(function(resolve) { reporter.specStarted(child.result, resolve); }); child.addExpectationResult( false, { passed: false, message: 'Not run because a beforeAll function failed. The ' + 'beforeAll failure will be reported on the suite that ' + 'caused it.' }, true ); child.result.status = 'failed'; await new Promise(function(resolve) { reporter.specDone(child.result, resolve); }); } } } }; /** * Add a custom reporter to the Jasmine environment. * @name Env#addReporter * @since 2.0.0 * @function * @param {Reporter} reporterToAdd The reporter to be added. * @see custom_reporter */ this.addReporter = function(reporterToAdd) { reporter.addReporter(reporterToAdd); }; /** * Provide a fallback reporter if no other reporters have been specified. * @name Env#provideFallbackReporter * @since 2.5.0 * @function * @param {Reporter} reporterToAdd The reporter * @see custom_reporter */ this.provideFallbackReporter = function(reporterToAdd) { reporter.provideFallbackReporter(reporterToAdd); }; /** * Clear all registered reporters * @name Env#clearReporters * @since 2.5.2 * @function */ this.clearReporters = function() { reporter.clearReporters(); }; var spyFactory = new j$.SpyFactory( function getCustomStrategies() { var runnable = currentRunnable(); if (runnable) { return runnableResources[runnable.id].customSpyStrategies; } return {}; }, function getDefaultStrategyFn() { var runnable = currentRunnable(); if (runnable) { return runnableResources[runnable.id].defaultStrategyFn; } return undefined; }, makeMatchersUtil ); var spyRegistry = new j$.SpyRegistry({ currentSpies: function() { if (!currentRunnable()) { throw new Error( 'Spies must be created in a before function or a spec' ); } return runnableResources[currentRunnable().id].spies; }, createSpy: function(name, originalFn) { return self.createSpy(name, originalFn); } }); /** * Configures whether Jasmine should allow the same function to be spied on * more than once during the execution of a spec. By default, spying on * a function that is already a spy will cause an error. * @name Env#allowRespy * @function * @since 2.5.0 * @param {boolean} allow Whether to allow respying */ this.allowRespy = function(allow) { spyRegistry.allowRespy(allow); }; this.spyOn = function() { return spyRegistry.spyOn.apply(spyRegistry, arguments); }; this.spyOnProperty = function() { return spyRegistry.spyOnProperty.apply(spyRegistry, arguments); }; this.spyOnAllFunctions = function() { return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments); }; this.createSpy = function(name, originalFn) { if (arguments.length === 1 && j$.isFunction_(name)) { originalFn = name; name = originalFn.name; } return spyFactory.createSpy(name, originalFn); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { return spyFactory.createSpyObj(baseName, methodNames, propertyNames); }; var ensureIsFunction = function(fn, caller) { if (!j$.isFunction_(fn)) { throw new Error( caller + ' expects a function argument; received ' + j$.getType_(fn) ); } }; var ensureIsFunctionOrAsync = function(fn, caller) { if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) { throw new Error( caller + ' expects a function argument; received ' + j$.getType_(fn) ); } }; function ensureIsNotNested(method) { var runnable = currentRunnable(); if (runnable !== null && runnable !== undefined) { throw new Error( "'" + method + "' should only be used in 'describe' function" ); } } var suiteFactory = function(description) { var suite = new j$.Suite({ id: getNextSuiteId(), description: description, parentSuite: currentDeclarationSuite, timer: new j$.Timer(), expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, throwOnExpectationFailure: config.stopSpecOnExpectationFailure, autoCleanClosures: config.autoCleanClosures, onLateError: recordLateError }); return suite; }; this.describe = function(description, specDefinitions) { ensureIsNotNested('describe'); ensureIsFunction(specDefinitions, 'describe'); var suite = suiteFactory(description); if (specDefinitions.length > 0) { throw new Error('describe does not expect any arguments'); } if (currentDeclarationSuite.markedExcluding) { suite.exclude(); } addSpecsToSuite(suite, specDefinitions); if (suite.parentSuite && !suite.children.length) { throw new Error('describe with no children (describe() or it())'); } return suite.metadata; }; this.xdescribe = function(description, specDefinitions) { ensureIsNotNested('xdescribe'); ensureIsFunction(specDefinitions, 'xdescribe'); var suite = suiteFactory(description); suite.exclude(); addSpecsToSuite(suite, specDefinitions); return suite.metadata; }; var focusedRunnables = []; this.fdescribe = function(description, specDefinitions) { ensureIsNotNested('fdescribe'); ensureIsFunction(specDefinitions, 'fdescribe'); var suite = suiteFactory(description); suite.isFocused = true; focusedRunnables.push(suite.id); unfocusAncestor(); addSpecsToSuite(suite, specDefinitions); return suite.metadata; }; function addSpecsToSuite(suite, specDefinitions) { var parentSuite = currentDeclarationSuite; parentSuite.addChild(suite); currentDeclarationSuite = suite; var declarationError = null; try { specDefinitions(); } catch (e) { declarationError = e; } if (declarationError) { suite.onException(declarationError); } currentDeclarationSuite = parentSuite; } function findFocusedAncestor(suite) { while (suite) { if (suite.isFocused) { return suite.id; } suite = suite.parentSuite; } return null; } function unfocusAncestor() { var focusedAncestor = findFocusedAncestor(currentDeclarationSuite); if (focusedAncestor) { for (var i = 0; i < focusedRunnables.length; i++) { if (focusedRunnables[i] === focusedAncestor) { focusedRunnables.splice(i, 1); break; } } } } var specFactory = function(description, fn, suite, timeout) { totalSpecsDefined++; var spec = new j$.Spec({ id: getNextSpecId(), beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: expectationFactory, asyncExpectationFactory: specAsyncExpectationFactory, onLateError: recordLateError, resultCallback: specResultCallback, getSpecName: function(spec) { return getSpecName(spec, suite); }, onStart: specStarted, description: description, expectationResultFactory: expectationResultFactory, queueRunnerFactory: queueRunnerFactory, userContext: function() { return suite.clonedSharedUserContext(); }, queueableFn: { fn: fn, timeout: timeout || 0 }, throwOnExpectationFailure: config.stopSpecOnExpectationFailure, autoCleanClosures: config.autoCleanClosures, timer: new j$.Timer() }); return spec; function specResultCallback(result, next) { clearResourcesForRunnable(spec.id); currentSpec = null; if (result.status === 'failed') { hasFailures = true; } reporter.specDone(result, next); } function specStarted(spec, next) { currentSpec = spec; defaultResourcesForRunnable(spec.id, suite.id); reporter.specStarted(spec.result, next); } }; this.it_ = function(description, fn, timeout) { ensureIsNotNested('it'); // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'it'); } if (timeout) { j$.util.validateTimeout(timeout); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); if (currentDeclarationSuite.markedExcluding) { spec.exclude(); } currentDeclarationSuite.addChild(spec); return spec; }; this.it = function(description, fn, timeout) { const spec = this.it_(description, fn, timeout); return spec.metadata; }; this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } var spec = this.it_.apply(this, arguments); spec.exclude('Temporarily disabled with xit'); return spec.metadata; }; this.fit = function(description, fn, timeout) { ensureIsNotNested('fit'); ensureIsFunctionOrAsync(fn, 'fit'); if (timeout) { j$.util.validateTimeout(timeout); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); unfocusAncestor(); return spec.metadata; }; /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} * @name Env#setSpecProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ this.setSpecProperty = function(key, value) { if (!currentRunnable() || currentRunnable() == currentSuite()) { throw new Error( "'setSpecProperty' was used when there was no current spec" ); } currentRunnable().setSpecProperty(key, value); }; /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} * @name Env#setSuiteProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ this.setSuiteProperty = function(key, value) { if (!currentSuite()) { throw new Error( "'setSuiteProperty' was used when there was no current suite" ); } currentSuite().setSuiteProperty(key, value); }; this.debugLog = function(msg) { var maybeSpec = currentRunnable(); if (!maybeSpec || !maybeSpec.debugLog) { throw new Error("'debugLog' was called when there was no current spec"); } maybeSpec.debugLog(msg); }; this.expect = function(actual) { if (!currentRunnable()) { throw new Error( "'expect' was used when there was no current spec, this could be because an asynchronous test timed out" ); } return currentRunnable().expect(actual); }; this.expectAsync = function(actual) { if (!currentRunnable()) { throw new Error( "'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out" ); } return currentRunnable().expectAsync(actual); }; this.beforeEach = function(beforeEachFunction, timeout) { ensureIsNotNested('beforeEach'); ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, timeout: timeout || 0 }); }; this.beforeAll = function(beforeAllFunction, timeout) { ensureIsNotNested('beforeAll'); ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, timeout: timeout || 0 }); }; this.afterEach = function(afterEachFunction, timeout) { ensureIsNotNested('afterEach'); ensureIsFunctionOrAsync(afterEachFunction, 'afterEach'); if (timeout) { j$.util.validateTimeout(timeout); } afterEachFunction.isCleanup = true; currentDeclarationSuite.afterEach({ fn: afterEachFunction, timeout: timeout || 0 }); }; this.afterAll = function(afterAllFunction, timeout) { ensureIsNotNested('afterAll'); ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); if (timeout) { j$.util.validateTimeout(timeout); } currentDeclarationSuite.afterAll({ fn: afterAllFunction, timeout: timeout || 0 }); }; this.pending = function(message) { var fullMessage = j$.Spec.pendingSpecExceptionMessage; if (message) { fullMessage += message; } throw fullMessage; }; this.fail = function(error) { if (!currentRunnable()) { throw new Error( "'fail' was used when there was no current spec, this could be because an asynchronous test timed out" ); } var message = 'Failed'; if (error) { message += ': '; if (error.message) { message += error.message; } else if (j$.isString_(error)) { message += error; } else { // pretty print all kind of objects. This includes arrays. message += makePrettyPrinter()(error); } } currentRunnable().addExpectationResult(false, { matcherName: '', passed: false, expected: '', actual: '', message: message, error: error && error.message ? error : null }); if (config.stopSpecOnExpectationFailure) { throw new Error(message); } }; this.cleanup_ = function() { if (globalErrors) { globalErrors.uninstall(); } }; } return Env; }; jasmine-4.0.0/src/core/ExceptionFormatter.js000066400000000000000000000045731416413636100210560ustar00rootroot00000000000000getJasmineRequireObj().ExceptionFormatter = function(j$) { var ignoredProperties = [ 'name', 'message', 'stack', 'fileName', 'sourceURL', 'line', 'lineNumber', 'column', 'description', 'jasmineMessage' ]; function ExceptionFormatter(options) { var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile(); this.message = function(error) { var message = ''; if (error.jasmineMessage) { message += error.jasmineMessage; } else if (error.name && error.message) { message += error.name + ': ' + error.message; } else if (error.message) { message += error.message; } else { message += error.toString() + ' thrown'; } if (error.fileName || error.sourceURL) { message += ' in ' + (error.fileName || error.sourceURL); } if (error.line || error.lineNumber) { message += ' (line ' + (error.line || error.lineNumber) + ')'; } return message; }; this.stack = function(error, { omitMessage } = {}) { if (!error || !error.stack) { return null; } var stackTrace = new j$.StackTrace(error); var lines = filterJasmine(stackTrace); var result = ''; if (stackTrace.message && !omitMessage) { lines.unshift(stackTrace.message); } result += formatProperties(error); result += lines.join('\n'); return result; }; function filterJasmine(stackTrace) { var result = [], jasmineMarker = stackTrace.style === 'webkit' ? '' : ' at '; stackTrace.frames.forEach(function(frame) { if (frame.file !== jasmineFile) { result.push(frame.raw); } else if (result[result.length - 1] !== jasmineMarker) { result.push(jasmineMarker); } }); return result; } function formatProperties(error) { if (!(error instanceof Object)) { return; } var result = {}; var empty = true; for (var prop in error) { if (j$.util.arrayContains(ignoredProperties, prop)) { continue; } result[prop] = error[prop]; empty = false; } if (!empty) { return 'error properties: ' + j$.basicPrettyPrinter_(result) + '\n'; } return ''; } } return ExceptionFormatter; }; jasmine-4.0.0/src/core/Expectation.js000066400000000000000000000166201416413636100175130ustar00rootroot00000000000000getJasmineRequireObj().Expectation = function(j$) { /** * Matchers that come with Jasmine out of the box. * @namespace matchers */ function Expectation(options) { this.expector = new j$.Expector(options); var customMatchers = options.customMatchers || {}; for (var matcherName in customMatchers) { this[matcherName] = wrapSyncCompare( matcherName, customMatchers[matcherName] ); } } /** * Add some context for an {@link expect} * @function * @name matchers#withContext * @since 3.3.0 * @param {String} message - Additional context to show when the matcher fails * @return {matchers} */ Expectation.prototype.withContext = function withContext(message) { return addFilter(this, new ContextAddingFilter(message)); }; /** * Invert the matcher following this {@link expect} * @member * @name matchers#not * @since 1.3.0 * @type {matchers} * @example * expect(something).not.toBe(true); */ Object.defineProperty(Expectation.prototype, 'not', { get: function() { return addFilter(this, syncNegatingFilter); } }); /** * Asynchronous matchers that operate on an actual value which is a promise, * and return a promise. * * Most async matchers will wait indefinitely for the promise to be resolved * or rejected, resulting in a spec timeout if that never happens. If you * expect that the promise will already be resolved or rejected at the time * the matcher is called, you can use the {@link async-matchers#already} * modifier to get a faster failure with a more helpful message. * * Note: Specs must await the result of each async matcher, return the * promise returned by the matcher, or return a promise that's derived from * the one returned by the matcher. Otherwise the matcher will not be * evaluated before the spec completes. * * @example * // Good * await expectAsync(aPromise).toBeResolved(); * @example * // Good * return expectAsync(aPromise).toBeResolved(); * @example * // Good * return expectAsync(aPromise).toBeResolved() * .then(function() { * // more spec code * }); * @example * // Bad * expectAsync(aPromise).toBeResolved(); * @namespace async-matchers */ function AsyncExpectation(options) { this.expector = new j$.Expector(options); var customAsyncMatchers = options.customAsyncMatchers || {}; for (var matcherName in customAsyncMatchers) { this[matcherName] = wrapAsyncCompare( matcherName, customAsyncMatchers[matcherName] ); } } /** * Add some context for an {@link expectAsync} * @function * @name async-matchers#withContext * @since 3.3.0 * @param {String} message - Additional context to show when the async matcher fails * @return {async-matchers} */ AsyncExpectation.prototype.withContext = function withContext(message) { return addFilter(this, new ContextAddingFilter(message)); }; /** * Invert the matcher following this {@link expectAsync} * @member * @name async-matchers#not * @type {async-matchers} * @example * await expectAsync(myPromise).not.toBeResolved(); * @example * return expectAsync(myPromise).not.toBeResolved(); */ Object.defineProperty(AsyncExpectation.prototype, 'not', { get: function() { return addFilter(this, asyncNegatingFilter); } }); /** * Fail as soon as possible if the actual is pending. * Otherwise evaluate the matcher. * @member * @name async-matchers#already * @since 3.8.0 * @type {async-matchers} * @example * await expectAsync(myPromise).already.toBeResolved(); * @example * return expectAsync(myPromise).already.toBeResolved(); */ Object.defineProperty(AsyncExpectation.prototype, 'already', { get: function() { return addFilter(this, expectSettledPromiseFilter); } }); function wrapSyncCompare(name, matcherFactory) { return function() { var result = this.expector.compare(name, matcherFactory, arguments); this.expector.processResult(result); }; } function wrapAsyncCompare(name, matcherFactory) { return function() { var self = this; // Capture the call stack here, before we go async, so that it will contain // frames that are relevant to the user instead of just parts of Jasmine. var errorForStack = j$.util.errorWithStack(); return this.expector .compare(name, matcherFactory, arguments) .then(function(result) { self.expector.processResult(result, errorForStack); }); }; } function addCoreMatchers(prototype, matchers, wrapper) { for (var matcherName in matchers) { var matcher = matchers[matcherName]; prototype[matcherName] = wrapper(matcherName, matcher); } } function addFilter(source, filter) { var result = Object.create(source); result.expector = source.expector.addFilter(filter); return result; } function negatedFailureMessage(result, matcherName, args, matchersUtil) { if (result.message) { if (j$.isFunction_(result.message)) { return result.message(); } else { return result.message; } } args = args.slice(); args.unshift(true); args.unshift(matcherName); return matchersUtil.buildFailureMessage.apply(matchersUtil, args); } function negate(result) { result.pass = !result.pass; return result; } var syncNegatingFilter = { selectComparisonFunc: function(matcher) { function defaultNegativeCompare() { return negate(matcher.compare.apply(null, arguments)); } return matcher.negativeCompare || defaultNegativeCompare; }, buildFailureMessage: negatedFailureMessage }; var asyncNegatingFilter = { selectComparisonFunc: function(matcher) { function defaultNegativeCompare() { return matcher.compare.apply(this, arguments).then(negate); } return matcher.negativeCompare || defaultNegativeCompare; }, buildFailureMessage: negatedFailureMessage }; var expectSettledPromiseFilter = { selectComparisonFunc: function(matcher) { return function(actual) { var matcherArgs = arguments; return j$.isPending_(actual).then(function(isPending) { if (isPending) { return { pass: false, message: 'Expected a promise to be settled (via ' + 'expectAsync(...).already) but it was pending.' }; } else { return matcher.compare.apply(null, matcherArgs); } }); }; } }; function ContextAddingFilter(message) { this.message = message; } ContextAddingFilter.prototype.modifyFailureMessage = function(msg) { var nl = msg.indexOf('\n'); if (nl === -1) { return this.message + ': ' + msg; } else { return this.message + ':\n' + indent(msg); } }; function indent(s) { return s.replace(/^/gm, ' '); } return { factory: function(options) { return new Expectation(options || {}); }, addCoreMatchers: function(matchers) { addCoreMatchers(Expectation.prototype, matchers, wrapSyncCompare); }, asyncFactory: function(options) { return new AsyncExpectation(options || {}); }, addAsyncCoreMatchers: function(matchers) { addCoreMatchers(AsyncExpectation.prototype, matchers, wrapAsyncCompare); } }; }; jasmine-4.0.0/src/core/ExpectationFilterChain.js000066400000000000000000000024441416413636100216230ustar00rootroot00000000000000getJasmineRequireObj().ExpectationFilterChain = function() { function ExpectationFilterChain(maybeFilter, prev) { this.filter_ = maybeFilter; this.prev_ = prev; } ExpectationFilterChain.prototype.addFilter = function(filter) { return new ExpectationFilterChain(filter, this); }; ExpectationFilterChain.prototype.selectComparisonFunc = function(matcher) { return this.callFirst_('selectComparisonFunc', arguments).result; }; ExpectationFilterChain.prototype.buildFailureMessage = function( result, matcherName, args, matchersUtil ) { return this.callFirst_('buildFailureMessage', arguments).result; }; ExpectationFilterChain.prototype.modifyFailureMessage = function(msg) { var result = this.callFirst_('modifyFailureMessage', arguments).result; return result || msg; }; ExpectationFilterChain.prototype.callFirst_ = function(fname, args) { var prevResult; if (this.prev_) { prevResult = this.prev_.callFirst_(fname, args); if (prevResult.found) { return prevResult; } } if (this.filter_ && this.filter_[fname]) { return { found: true, result: this.filter_[fname].apply(this.filter_, args) }; } return { found: false }; }; return ExpectationFilterChain; }; jasmine-4.0.0/src/core/ExpectationResult.js000066400000000000000000000053361416413636100207140ustar00rootroot00000000000000//TODO: expectation result may make more sense as a presentation of an expectation. getJasmineRequireObj().buildExpectationResult = function(j$) { function buildExpectationResult(options) { var messageFormatter = options.messageFormatter || function() {}, stackFormatter = options.stackFormatter || function() {}; /** * @typedef Expectation * @property {String} matcherName - The name of the matcher that was executed for this expectation. * @property {String} message - The failure message for the expectation. * @property {String} stack - The stack trace for the failure if available. * @property {Boolean} passed - Whether the expectation passed or failed. * @property {Object} expected - If the expectation failed, what was the expected value. * @property {Object} actual - If the expectation failed, what actual value was produced. * @property {String|undefined} globalErrorType - The type of an error that * is reported on the top suite. Valid values are undefined, "afterAll", * "load", "lateExpectation", and "lateError". */ var result = { matcherName: options.matcherName, message: message(), stack: options.omitStackTrace ? '' : stack(), passed: options.passed }; if (!result.passed) { result.expected = options.expected; result.actual = options.actual; if (options.error && !j$.isString_(options.error)) { if ('code' in options.error) { result.code = options.error.code; } if ( options.error.code === 'ERR_ASSERTION' && options.expected === '' && options.actual === '' ) { result.expected = options.error.expected; result.actual = options.error.actual; result.matcherName = 'assert ' + options.error.operator; } } } return result; function message() { if (options.passed) { return 'Passed.'; } else if (options.message) { return options.message; } else if (options.error) { return messageFormatter(options.error); } return ''; } function stack() { if (options.passed) { return ''; } var error = options.error; if (!error) { if (options.errorForStack) { error = options.errorForStack; } else if (options.stack) { error = options; } else { try { throw new Error(message()); } catch (e) { error = e; } } } // Omit the message from the stack trace because it will be // included elsewhere. return stackFormatter(error, { omitMessage: true }); } } return buildExpectationResult; }; jasmine-4.0.0/src/core/Expector.js000066400000000000000000000050101416413636100170100ustar00rootroot00000000000000getJasmineRequireObj().Expector = function(j$) { function Expector(options) { this.matchersUtil = options.matchersUtil || { buildFailureMessage: function() {} }; this.actual = options.actual; this.addExpectationResult = options.addExpectationResult || function() {}; this.filters = new j$.ExpectationFilterChain(); } Expector.prototype.instantiateMatcher = function( matcherName, matcherFactory, args ) { this.matcherName = matcherName; this.args = Array.prototype.slice.call(args, 0); this.expected = this.args.slice(0); this.args.unshift(this.actual); var matcher = matcherFactory(this.matchersUtil); var comparisonFunc = this.filters.selectComparisonFunc(matcher); return comparisonFunc || matcher.compare; }; Expector.prototype.buildMessage = function(result) { var self = this; if (result.pass) { return ''; } var msg = this.filters.buildFailureMessage( result, this.matcherName, this.args, this.matchersUtil, defaultMessage ); return this.filters.modifyFailureMessage(msg || defaultMessage()); function defaultMessage() { if (!result.message) { var args = self.args.slice(); args.unshift(false); args.unshift(self.matcherName); return self.matchersUtil.buildFailureMessage.apply( self.matchersUtil, args ); } else if (j$.isFunction_(result.message)) { return result.message(); } else { return result.message; } } }; Expector.prototype.compare = function(matcherName, matcherFactory, args) { var matcherCompare = this.instantiateMatcher( matcherName, matcherFactory, args ); return matcherCompare.apply(null, this.args); }; Expector.prototype.addFilter = function(filter) { var result = Object.create(this); result.filters = this.filters.addFilter(filter); return result; }; Expector.prototype.processResult = function(result, errorForStack) { var message = this.buildMessage(result); if (this.expected.length === 1) { this.expected = this.expected[0]; } this.addExpectationResult(result.pass, { matcherName: this.matcherName, passed: result.pass, message: message, error: errorForStack ? undefined : result.error, errorForStack: errorForStack || undefined, actual: this.actual, expected: this.expected // TODO: this may need to be arrayified/sliced }); }; return Expector; }; jasmine-4.0.0/src/core/GlobalErrors.js000066400000000000000000000074341416413636100176300ustar00rootroot00000000000000getJasmineRequireObj().GlobalErrors = function(j$) { function GlobalErrors(global) { var handlers = []; global = global || j$.getGlobal(); var onerror = function onerror() { var handler = handlers[handlers.length - 1]; if (handler) { handler.apply(null, Array.prototype.slice.call(arguments, 0)); } else { throw arguments[0]; } }; this.originalHandlers = {}; this.jasmineHandlers = {}; this.installOne_ = function installOne_(errorType, jasmineMessage) { function taggedOnError(error) { var substituteMsg; if (j$.isError_(error)) { error.jasmineMessage = jasmineMessage + ': ' + error; } else { if (error) { substituteMsg = jasmineMessage + ': ' + error; } else { substituteMsg = jasmineMessage + ' with no error or message'; } if (errorType === 'unhandledRejection') { substituteMsg += '\n' + '(Tip: to get a useful stack trace, use ' + 'Promise.reject(new Error(...)) instead of Promise.reject(' + (error ? '...' : '') + ').)'; } error = new Error(substituteMsg); } var handler = handlers[handlers.length - 1]; if (handler) { handler(error); } else { throw error; } } this.originalHandlers[errorType] = global.process.listeners(errorType); this.jasmineHandlers[errorType] = taggedOnError; global.process.removeAllListeners(errorType); global.process.on(errorType, taggedOnError); this.uninstall = function uninstall() { var errorTypes = Object.keys(this.originalHandlers); for (var iType = 0; iType < errorTypes.length; iType++) { var errorType = errorTypes[iType]; global.process.removeListener( errorType, this.jasmineHandlers[errorType] ); for (var i = 0; i < this.originalHandlers[errorType].length; i++) { global.process.on(errorType, this.originalHandlers[errorType][i]); } delete this.originalHandlers[errorType]; delete this.jasmineHandlers[errorType]; } }; }; this.install = function install() { if ( global.process && global.process.listeners && j$.isFunction_(global.process.on) ) { this.installOne_('uncaughtException', 'Uncaught exception'); this.installOne_('unhandledRejection', 'Unhandled promise rejection'); } else { var originalHandler = global.onerror; global.onerror = onerror; var browserRejectionHandler = function browserRejectionHandler(event) { if (j$.isError_(event.reason)) { event.reason.jasmineMessage = 'Unhandled promise rejection: ' + event.reason; global.onerror(event.reason); } else { global.onerror('Unhandled promise rejection: ' + event.reason); } }; if (global.addEventListener) { global.addEventListener( 'unhandledrejection', browserRejectionHandler ); } this.uninstall = function uninstall() { global.onerror = originalHandler; if (global.removeEventListener) { global.removeEventListener( 'unhandledrejection', browserRejectionHandler ); } }; } }; this.pushListener = function pushListener(listener) { handlers.push(listener); }; this.popListener = function popListener(listener) { if (!listener) { throw new Error('popListener expects a listener'); } handlers.pop(); }; } return GlobalErrors; }; jasmine-4.0.0/src/core/JsApiReporter.js000066400000000000000000000063251416413636100177620ustar00rootroot00000000000000getJasmineRequireObj().JsApiReporter = function(j$) { /** * @name jsApiReporter * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object. * @class * @hideconstructor */ function JsApiReporter(options) { var timer = options.timer || new j$.Timer(), status = 'loaded'; this.started = false; this.finished = false; this.runDetails = {}; this.jasmineStarted = function() { this.started = true; status = 'started'; timer.start(); }; var executionTime; this.jasmineDone = function(runDetails) { this.finished = true; this.runDetails = runDetails; executionTime = timer.elapsed(); status = 'done'; }; /** * Get the current status for the Jasmine environment. * @name jsApiReporter#status * @since 2.0.0 * @function * @return {String} - One of `loaded`, `started`, or `done` */ this.status = function() { return status; }; var suites = [], suites_hash = {}; this.suiteStarted = function(result) { suites_hash[result.id] = result; }; this.suiteDone = function(result) { storeSuite(result); }; /** * Get the results for a set of suites. * * Retrievable in slices for easier serialization. * @name jsApiReporter#suiteResults * @since 2.1.0 * @function * @param {Number} index - The position in the suites list to start from. * @param {Number} length - Maximum number of suite results to return. * @return {SuiteResult[]} */ this.suiteResults = function(index, length) { return suites.slice(index, index + length); }; function storeSuite(result) { suites.push(result); suites_hash[result.id] = result; } /** * Get all of the suites in a single object, with their `id` as the key. * @name jsApiReporter#suites * @since 2.0.0 * @function * @return {Object} - Map of suite id to {@link SuiteResult} */ this.suites = function() { return suites_hash; }; var specs = []; this.specDone = function(result) { specs.push(result); }; /** * Get the results for a set of specs. * * Retrievable in slices for easier serialization. * @name jsApiReporter#specResults * @since 2.0.0 * @function * @param {Number} index - The position in the specs list to start from. * @param {Number} length - Maximum number of specs results to return. * @return {SpecResult[]} */ this.specResults = function(index, length) { return specs.slice(index, index + length); }; /** * Get all spec results. * @name jsApiReporter#specs * @since 2.0.0 * @function * @return {SpecResult[]} */ this.specs = function() { return specs; }; /** * Get the number of milliseconds it took for the full Jasmine suite to run. * @name jsApiReporter#executionTime * @since 2.0.0 * @function * @return {Number} */ this.executionTime = function() { return executionTime; }; } return JsApiReporter; }; jasmine-4.0.0/src/core/MockDate.js000066400000000000000000000050351416413636100167150ustar00rootroot00000000000000getJasmineRequireObj().MockDate = function(j$) { function MockDate(global) { var self = this; var currentTime = 0; if (!global || !global.Date) { self.install = function() {}; self.tick = function() {}; self.uninstall = function() {}; return self; } var GlobalDate = global.Date; self.install = function(mockDate) { if (mockDate instanceof GlobalDate) { currentTime = mockDate.getTime(); } else { if (!j$.util.isUndefined(mockDate)) { throw new Error( 'The argument to jasmine.clock().mockDate(), if specified, ' + 'should be a Date instance.' ); } currentTime = new GlobalDate().getTime(); } global.Date = FakeDate; }; self.tick = function(millis) { millis = millis || 0; currentTime = currentTime + millis; }; self.uninstall = function() { currentTime = 0; global.Date = GlobalDate; }; createDateProperties(); return self; function FakeDate() { switch (arguments.length) { case 0: return new GlobalDate(currentTime); case 1: return new GlobalDate(arguments[0]); case 2: return new GlobalDate(arguments[0], arguments[1]); case 3: return new GlobalDate(arguments[0], arguments[1], arguments[2]); case 4: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3] ); case 5: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4] ); case 6: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5] ); default: return new GlobalDate( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6] ); } } function createDateProperties() { FakeDate.prototype = GlobalDate.prototype; FakeDate.now = function() { return currentTime; }; FakeDate.toSource = GlobalDate.toSource; FakeDate.toString = GlobalDate.toString; FakeDate.parse = GlobalDate.parse; FakeDate.UTC = GlobalDate.UTC; } } return MockDate; }; jasmine-4.0.0/src/core/NeverSkipPolicy.js000066400000000000000000000004351416413636100203130ustar00rootroot00000000000000getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns) {} NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; return NeverSkipPolicy; }; jasmine-4.0.0/src/core/Order.js000066400000000000000000000023141416413636100162760ustar00rootroot00000000000000/*jshint bitwise: false*/ getJasmineRequireObj().Order = function() { function Order(options) { this.random = 'random' in options ? options.random : true; var seed = (this.seed = options.seed || generateSeed()); this.sort = this.random ? randomOrder : naturalOrder; function naturalOrder(items) { return items; } function randomOrder(items) { var copy = items.slice(); copy.sort(function(a, b) { return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id); }); return copy; } function generateSeed() { return String(Math.random()).slice(-5); } // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function // used to get a different output when the key changes slightly. // We use your return to sort the children randomly in a consistent way when // used in conjunction with a seed function jenkinsHash(key) { var hash, i; for (hash = i = 0; i < key.length; ++i) { hash += key.charCodeAt(i); hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash; } } return Order; }; jasmine-4.0.0/src/core/PrettyPrinter.js000066400000000000000000000244621416413636100200660ustar00rootroot00000000000000getJasmineRequireObj().makePrettyPrinter = function(j$) { function SinglePrettyPrintRun(customObjectFormatters, pp) { this.customObjectFormatters_ = customObjectFormatters; this.ppNestLevel_ = 0; this.seen = []; this.length = 0; this.stringParts = []; this.pp_ = pp; } function hasCustomToString(value) { // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g. // iframe, web worker) try { return ( j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && value.toString() !== Object.prototype.toString.call(value) ); } catch (e) { // The custom toString() threw. return true; } } SinglePrettyPrintRun.prototype.format = function(value) { this.ppNestLevel_++; try { var customFormatResult = this.applyCustomFormatters_(value); if (customFormatResult) { this.emitScalar(customFormatResult); } else if (j$.util.isUndefined(value)) { this.emitScalar('undefined'); } else if (value === null) { this.emitScalar('null'); } else if (value === 0 && 1 / value === -Infinity) { this.emitScalar('-0'); } else if (value === j$.getGlobal()) { this.emitScalar(''); } else if (value.jasmineToString) { this.emitScalar(value.jasmineToString(this.pp_)); } else if (typeof value === 'string') { this.emitString(value); } else if (j$.isSpy(value)) { this.emitScalar('spy on ' + value.and.identity); } else if (j$.isSpy(value.toString)) { this.emitScalar('spy on ' + value.toString.and.identity); } else if (value instanceof RegExp) { this.emitScalar(value.toString()); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (j$.isDomNode(value)) { if (value.tagName) { this.emitDomElement(value); } else { this.emitScalar('HTMLNode'); } } else if (value instanceof Date) { this.emitScalar('Date(' + value + ')'); } else if (j$.isSet(value)) { this.emitSet(value); } else if (j$.isMap(value)) { this.emitMap(value); } else if (j$.isTypedArray_(value)) { this.emitTypedArray(value); } else if ( value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value) ) { try { this.emitScalar(value.toString()); } catch (e) { this.emitScalar('has-invalid-toString-method'); } } else if (j$.util.arrayContains(this.seen, value)) { this.emitScalar( '' ); } else if (j$.isArray_(value) || j$.isA_('Object', value)) { this.seen.push(value); if (j$.isArray_(value)) { this.emitArray(value); } else { this.emitObject(value); } this.seen.pop(); } else { this.emitScalar(value.toString()); } } catch (e) { if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) { throw e; } } finally { this.ppNestLevel_--; } }; SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) { return customFormat(value, this.customObjectFormatters_); }; SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) { var objKeys = keys(obj, j$.isArray_(obj)); var isGetter = function isGetter(prop) {}; if (obj.__lookupGetter__) { isGetter = function isGetter(prop) { var getter = obj.__lookupGetter__(prop); return !j$.util.isUndefined(getter) && getter !== null; }; } var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); for (var i = 0; i < length; i++) { var property = objKeys[i]; fn(property, isGetter(property)); } return objKeys.length > length; }; SinglePrettyPrintRun.prototype.emitScalar = function(value) { this.append(value); }; SinglePrettyPrintRun.prototype.emitString = function(value) { this.append("'" + value + "'"); }; SinglePrettyPrintRun.prototype.emitArray = function(array) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Array'); return; } var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); this.append('[ '); for (var i = 0; i < length; i++) { if (i > 0) { this.append(', '); } this.format(array[i]); } if (array.length > length) { this.append(', ...'); } var self = this; var first = array.length === 0; var truncated = this.iterateObject(array, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.formatProperty(array, property, isGetter); }); if (truncated) { this.append(', ...'); } this.append(' ]'); }; SinglePrettyPrintRun.prototype.emitSet = function(set) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Set'); return; } this.append('Set( '); var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); var i = 0; set.forEach(function(value, key) { if (i >= size) { return; } if (i > 0) { this.append(', '); } this.format(value); i++; }, this); if (set.size > size) { this.append(', ...'); } this.append(' )'); }; SinglePrettyPrintRun.prototype.emitMap = function(map) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { this.append('Map'); return; } this.append('Map( '); var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); var i = 0; map.forEach(function(value, key) { if (i >= size) { return; } if (i > 0) { this.append(', '); } this.format([key, value]); i++; }, this); if (map.size > size) { this.append(', ...'); } this.append(' )'); }; SinglePrettyPrintRun.prototype.emitObject = function(obj) { var ctor = obj.constructor, constructorName; constructorName = typeof ctor === 'function' && obj instanceof ctor ? j$.fnNameFor(obj.constructor) : 'null'; this.append(constructorName); if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { return; } var self = this; this.append('({ '); var first = true; var truncated = this.iterateObject(obj, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.formatProperty(obj, property, isGetter); }); if (truncated) { this.append(', ...'); } this.append(' })'); }; SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) { var constructorName = j$.fnNameFor(arr.constructor), limitedArray = Array.prototype.slice.call( arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH ), itemsString = Array.prototype.join.call(limitedArray, ', '); if (limitedArray.length !== arr.length) { itemsString += ', ...'; } this.append(constructorName + ' [ ' + itemsString + ' ]'); }; SinglePrettyPrintRun.prototype.emitDomElement = function(el) { var tagName = el.tagName.toLowerCase(), attrs = el.attributes, i, len = attrs.length, out = '<' + tagName, attr; for (i = 0; i < len; i++) { attr = attrs[i]; out += ' ' + attr.name; if (attr.value !== '') { out += '="' + attr.value + '"'; } } out += '>'; if (el.childElementCount !== 0 || el.textContent !== '') { out += '...'; } this.append(out); }; SinglePrettyPrintRun.prototype.formatProperty = function( obj, property, isGetter ) { this.append(property); this.append(': '); if (isGetter) { this.append(''); } else { this.format(obj[property]); } }; SinglePrettyPrintRun.prototype.append = function(value) { // This check protects us from the rare case where an object has overriden // `toString()` with an invalid implementation (returning a non-string). if (typeof value !== 'string') { value = Object.prototype.toString.call(value); } var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length); this.length += result.value.length; this.stringParts.push(result.value); if (result.truncated) { throw new MaxCharsReachedError(); } }; function truncate(s, maxlen) { if (s.length <= maxlen) { return { value: s, truncated: false }; } s = s.substring(0, maxlen - 4) + ' ...'; return { value: s, truncated: true }; } function MaxCharsReachedError() { this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS + ' characters while pretty-printing a value'; } MaxCharsReachedError.prototype = new Error(); function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { if (j$.util.has(o, key)) { keys.push(key); } } return keys; })(obj); if (!isArray) { return allKeys; } if (allKeys.length === 0) { return allKeys; } var extraKeys = []; for (var i = 0; i < allKeys.length; i++) { if (!/^[0-9]+$/.test(allKeys[i])) { extraKeys.push(allKeys[i]); } } return extraKeys; } function customFormat(value, customObjectFormatters) { var i, result; for (i = 0; i < customObjectFormatters.length; i++) { result = customObjectFormatters[i](value); if (result !== undefined) { return result; } } } return function(customObjectFormatters) { customObjectFormatters = customObjectFormatters || []; var pp = function(value) { var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp); prettyPrinter.format(value); return prettyPrinter.stringParts.join(''); }; pp.customFormat_ = function(value) { return customFormat(value, customObjectFormatters); }; return pp; }; }; jasmine-4.0.0/src/core/QueueRunner.js000066400000000000000000000202041416413636100174770ustar00rootroot00000000000000getJasmineRequireObj().QueueRunner = function(j$) { var nextid = 1; function StopExecutionError() {} StopExecutionError.prototype = new Error(); j$.StopExecutionError = StopExecutionError; function once(fn, onTwice) { var called = false; return function(arg) { if (called) { if (onTwice) { onTwice(); } } else { called = true; // Direct call using single parameter, because cleanup/next does not need more fn(arg); } return null; }; } function fallbackOnMultipleDone() { console.error( new Error( "An asynchronous function called its 'done' " + 'callback more than once, in a QueueRunner without a onMultipleDone ' + 'handler.' ) ); } function emptyFn() {} function QueueRunner(attrs) { this.id_ = nextid++; this.queueableFns = attrs.queueableFns || []; this.onComplete = attrs.onComplete || emptyFn; this.clearStack = attrs.clearStack || function(fn) { fn(); }; this.onException = attrs.onException || emptyFn; this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone; this.userContext = attrs.userContext || new j$.UserContext(); this.timeout = attrs.timeout || { setTimeout: setTimeout, clearTimeout: clearTimeout }; this.fail = attrs.fail || emptyFn; this.globalErrors = attrs.globalErrors || { pushListener: emptyFn, popListener: emptyFn }; const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns); this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); } this.deprecated = attrs.deprecated; } QueueRunner.prototype.execute = function() { var self = this; this.handleFinalError = function(message, source, lineno, colno, error) { // Older browsers would send the error as the first parameter. HTML5 // specifies the the five parameters above. The error instance should // be preffered, otherwise the call stack would get lost. self.onException(error || message); }; this.globalErrors.pushListener(this.handleFinalError); this.run(0); }; QueueRunner.prototype.clearTimeout = function(timeoutId) { Function.prototype.apply.apply(this.timeout.clearTimeout, [ j$.getGlobal(), [timeoutId] ]); }; QueueRunner.prototype.setTimeout = function(fn, timeout) { return Function.prototype.apply.apply(this.timeout.setTimeout, [ j$.getGlobal(), [fn, timeout] ]); }; QueueRunner.prototype.attempt = function attempt(iterativeIndex) { var self = this, completedSynchronously = true, handleError = function handleError(error) { // TODO probably shouldn't next() right away here. // That makes debugging async failures much more confusing. onException(error); }, cleanup = once(function cleanup() { if (timeoutId !== void 0) { self.clearTimeout(timeoutId); } self.globalErrors.popListener(handleError); }), next = once( function next(err) { cleanup(); if (typeof err !== 'undefined') { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } self.recordError_(iterativeIndex); } function runNext() { self.run(self.nextFnIx_(iterativeIndex)); } if (completedSynchronously) { self.setTimeout(runNext); } else { runNext(); } }, function() { try { if (!timedOut) { self.onMultipleDone(); } } catch (error) { // Any error we catch here is probably due to a bug in Jasmine, // and it's not likely to end up anywhere useful if we let it // propagate. Log it so it can at least show up when debugging. console.error(error); } } ), timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, maybeThenable; next.fail = function nextFail() { self.fail.apply(null, arguments); self.recordError_(iterativeIndex); next(); }; self.globalErrors.pushListener(handleError); if (queueableFn.timeout !== undefined) { var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL; timeoutId = self.setTimeout(function() { timedOut = true; var error = new Error( 'Timeout - Async function did not complete within ' + timeoutInterval + 'ms ' + (queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') ); // TODO Need to decide what to do about a successful completion after a // timeout. That should probably not be a deprecation, and maybe not // an error in 4.0. (But a diagnostic of some sort might be helpful.) onException(error); next(); }, timeoutInterval); } try { if (queueableFn.fn.length === 0) { maybeThenable = queueableFn.fn.call(self.userContext); if (maybeThenable && j$.isFunction_(maybeThenable.then)) { maybeThenable.then(next, onPromiseRejection); completedSynchronously = false; return { completedSynchronously: false }; } } else { maybeThenable = queueableFn.fn.call(self.userContext, next); this.diagnoseConflictingAsync_(queueableFn.fn, maybeThenable); completedSynchronously = false; return { completedSynchronously: false }; } } catch (e) { onException(e); self.recordError_(iterativeIndex); } cleanup(); return { completedSynchronously: true }; function onException(e) { self.onException(e); self.recordError_(iterativeIndex); } function onPromiseRejection(e) { onException(e); next(); } }; QueueRunner.prototype.run = function(recursiveIndex) { var length = this.queueableFns.length, self = this, iterativeIndex; for ( iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex = this.nextFnIx_(iterativeIndex) ) { var result = this.attempt(iterativeIndex); if (!result.completedSynchronously) { return; } } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); } }); }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); } return result; }; QueueRunner.prototype.recordError_ = function(currentFnIx) { this.errored_ = true; this.skipPolicy_.fnErrored(currentFnIx); }; QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; if (retval && j$.isFunction_(retval.then)) { // Issue a warning that matches the user's code. // Omit the stack trace because there's almost certainly no user code // on the stack at this point. if (j$.isAsyncFunction_(fn)) { this.onException( 'An asynchronous before/it/after ' + 'function was defined with the async keyword but also took a ' + 'done callback. Either remove the done callback (recommended) or ' + 'remove the async keyword.' ); } else { this.onException( 'An asynchronous before/it/after ' + 'function took a done callback but also returned a promise. ' + 'Either remove the done callback (recommended) or change the ' + 'function to not return a promise.' ); } this.deprecated(msg, { omitStackTrace: true }); } }; return QueueRunner; }; jasmine-4.0.0/src/core/ReportDispatcher.js000066400000000000000000000037731416413636100205170ustar00rootroot00000000000000getJasmineRequireObj().ReportDispatcher = function(j$) { function ReportDispatcher(methods, queueRunnerFactory, onLateError) { var dispatchedMethods = methods || []; for (var i = 0; i < dispatchedMethods.length; i++) { var method = dispatchedMethods[i]; this[method] = (function(m) { return function() { dispatch(m, arguments); }; })(method); } var reporters = []; var fallbackReporter = null; this.addReporter = function(reporter) { reporters.push(reporter); }; this.provideFallbackReporter = function(reporter) { fallbackReporter = reporter; }; this.clearReporters = function() { reporters = []; }; return this; function dispatch(method, args) { if (reporters.length === 0 && fallbackReporter !== null) { reporters.push(fallbackReporter); } var onComplete = args[args.length - 1]; args = j$.util.argsToArray(args).splice(0, args.length - 1); var fns = []; for (var i = 0; i < reporters.length; i++) { var reporter = reporters[i]; addFn(fns, reporter, method, args); } queueRunnerFactory({ queueableFns: fns, onComplete: onComplete, isReporter: true, onMultipleDone: function() { onLateError( new Error( "An asynchronous reporter callback called its 'done' callback " + 'more than once.' ) ); } }); } function addFn(fns, reporter, method, args) { var fn = reporter[method]; if (!fn) { return; } var thisArgs = j$.util.cloneArgs(args); if (fn.length <= 1) { fns.push({ fn: function() { return fn.apply(reporter, thisArgs); } }); } else { fns.push({ fn: function(done) { return fn.apply(reporter, thisArgs.concat([done])); } }); } } } return ReportDispatcher; }; jasmine-4.0.0/src/core/SkipAfterBeforeAllErrorPolicy.js000066400000000000000000000024031416413636100230600ustar00rootroot00000000000000getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { function SkipAfterBeforeAllErrorPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.skipping_ = false; } SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { if (this.skipping_) { return this.nextAfterAllAfter_(lastRanFnIx); } else { return lastRanFnIx + 1; } }; SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { for ( i++; i < this.queueableFns_.length && this.queueableFns_[i].type !== 'afterAll'; i++ ) {} return i; }; SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { if (this.queueableFns_[fnIx].type === 'beforeAll') { this.skipping_ = true; // Failures need to be reported for each contained spec. But we can't do // that from here because reporting is async. This function isn't async // (and can't be without greatly complicating QueueRunner). Mark the // failure so that the code that reports the suite result (which is // already async) can detect the failure and report the specs. this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true; } }; return SkipAfterBeforeAllErrorPolicy; }; jasmine-4.0.0/src/core/Spec.js000066400000000000000000000247061416413636100161260ustar00rootroot00000000000000getJasmineRequireObj().Spec = function(j$) { /** * @interface Spec * @see Configuration#specFilter * @since 2.0.0 */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; /** * The unique ID of this spec. * @name Spec#id * @readonly * @type {string} * @since 2.0.0 */ this.id = attrs.id; /** * The description passed to the {@link it} that created this spec. * @name Spec#description * @readonly * @type {string} * @since 2.0.0 */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return { befores: [], afters: [] }; }; this.userContext = attrs.userContext || function() { return {}; }; this.onStart = attrs.onStart || function() {}; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; this.getSpecName = attrs.getSpecName || function() { return ''; }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; this.onLateError = attrs.onLateError || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.timer = attrs.timer || new j$.Timer(); if (!this.queueableFn.fn) { this.exclude(); } /** * @typedef SpecResult * @property {Int} id - The unique id of this spec. * @property {String} description - The description passed to the {@link it} that created this spec. * @property {String} fullName - The full description including all ancestors of this spec. * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. * @since 2.0.0 */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], deprecationWarnings: [], pendingReason: '', duration: null, properties: null, debugLogs: null }; } Spec.prototype.addExpectationResult = function(passed, data, isError) { var expectationResult = this.expectationResultFactory(data); if (passed) { this.result.passedExpectations.push(expectationResult); } else { this.result.failedExpectations.push(expectationResult); if (this.throwOnExpectationFailure && !isError) { throw new j$.errors.ExpectationFailed(); } } }; Spec.prototype.setSpecProperty = function(key, value) { this.result.properties = this.result.properties || {}; this.result.properties[key] = value; }; Spec.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; Spec.prototype.expectAsync = function(actual) { return this.asyncExpectationFactory(actual, this); }; Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) { var self = this; var onStart = { fn: function(done) { self.timer.start(); self.onStart(self, done); } }; var complete = { fn: function(done) { if (self.autoCleanClosures) { self.queueableFn.fn = null; } self.result.status = self.status(excluded, failSpecWithNoExp); self.result.duration = self.timer.elapsed(); if (self.result.status !== 'failed') { self.result.debugLogs = null; } self.resultCallback(self.result, done); }, type: 'specCleanup' }; var fns = this.beforeAndAfterFns(); var runnerConfig = { isLeaf: true, queueableFns: [...fns.befores, this.queueableFn, ...fns.afters], onException: function() { self.onException.apply(self, arguments); }, onMultipleDone: function() { // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. self.onLateError( new Error( 'An asynchronous spec, beforeEach, or afterEach function called its ' + "'done' callback more than once.\n(in spec: " + self.getFullName() + ')' ) ); }, onComplete: function() { if (self.result.status === 'failed') { onComplete(new j$.StopExecutionError('spec failed')); } else { onComplete(); } }, userContext: this.userContext(), runnableName: this.getFullName.bind(this) }; if (this.markedPending || excluded === true) { runnerConfig.queueableFns = []; } runnerConfig.queueableFns.unshift(onStart); runnerConfig.queueableFns.push(complete); this.queueRunnerFactory(runnerConfig); }; Spec.prototype.reset = function() { this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], deprecationWarnings: [], pendingReason: this.excludeMessage, duration: null, properties: null, debugLogs: null }; this.markedPending = this.markedExcluding; }; Spec.prototype.onException = function onException(e) { if (Spec.isPendingSpecException(e)) { this.pend(extractCustomPendingMessage(e)); return; } if (e instanceof j$.errors.ExpectationFailed) { return; } this.addExpectationResult( false, { matcherName: '', passed: false, expected: '', actual: '', error: e }, true ); }; /* * Marks state as pending * @param {string} [message] An optional reason message */ Spec.prototype.pend = function(message) { this.markedPending = true; if (message) { this.result.pendingReason = message; } }; /* * Like {@link Spec#pend}, but pending state will survive {@link Spec#reset} * Useful for fit, xit, where pending state remains. * @param {string} [message] An optional reason message */ Spec.prototype.exclude = function(message) { this.markedExcluding = true; if (this.message) { this.excludeMessage = message; } this.pend(message); }; Spec.prototype.getResult = function() { this.result.status = this.status(); return this.result; }; Spec.prototype.status = function(excluded, failSpecWithNoExpectations) { if (excluded === true) { return 'excluded'; } if (this.markedPending) { return 'pending'; } if ( this.result.failedExpectations.length > 0 || (failSpecWithNoExpectations && this.result.failedExpectations.length + this.result.passedExpectations.length === 0) ) { return 'failed'; } return 'passed'; }; /** * The full description including all ancestors of this spec. * @name Spec#getFullName * @function * @returns {string} * @since 2.0.0 */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; Spec.prototype.addDeprecationWarning = function(deprecation) { if (typeof deprecation === 'string') { deprecation = { message: deprecation }; } this.result.deprecationWarnings.push( this.expectationResultFactory(deprecation) ); }; Spec.prototype.debugLog = function(msg) { if (!this.result.debugLogs) { this.result.debugLogs = []; } /** * @typedef DebugLogEntry * @property {String} message - The message that was passed to {@link jasmine.debugLog}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ this.result.debugLogs.push({ message: msg, timestamp: this.timer.elapsed() }); }; var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length; return fullMessage.substr(boilerplateEnd); }; Spec.pendingSpecExceptionMessage = '=> marked Pending'; Spec.isPendingSpecException = function(e) { return !!( e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1 ); }; /** * @interface Spec * @see Configuration#specFilter */ Object.defineProperty(Spec.prototype, 'metadata', { get: function() { if (!this.metadata_) { this.metadata_ = { /** * The unique ID of this spec. * @name Spec#id * @readonly * @type {string} */ id: this.id, /** * The description passed to the {@link it} that created this spec. * @name Spec#description * @readonly * @type {string} */ description: this.description, /** * The full description including all ancestors of this spec. * @name Spec#getFullName * @function * @returns {string} */ getFullName: this.getFullName.bind(this) }; } return this.metadata_; } }); return Spec; }; jasmine-4.0.0/src/core/Spy.js000066400000000000000000000143311416413636100160000ustar00rootroot00000000000000getJasmineRequireObj().Spy = function(j$) { var nextOrder = (function() { var order = 0; return function() { return order++; }; })(); /** * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn}, * {@link spyOnProperty}, {@link jasmine.createSpy}, or * {@link jasmine.createSpyObj} instead. * @class Spy * @hideconstructor */ function Spy(name, matchersUtil, optionals) { const { originalFn, customStrategies, defaultStrategyFn } = optionals || {}; var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); }), strategyDispatcher = new SpyStrategyDispatcher( { name: name, fn: originalFn, getSpy: function() { return wrapper; }, customStrategies: customStrategies }, matchersUtil ), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { /** * @name Spy.callData * @property {object} object - `this` context for the invocation. * @property {number} invocationOrder - Order of the invocation. * @property {Array} args - The arguments passed for this invocation. * @property returnValue - The value that was returned from this invocation. */ var callData = { object: context, invocationOrder: nextOrder(), args: Array.prototype.slice.apply(args) }; callTracker.track(callData); var returnValue = strategyDispatcher.exec(context, args, invokeNew); callData.returnValue = returnValue; return returnValue; }; function makeFunc(length, fn) { switch (length) { case 1: return function wrap1(a) { return fn(this, arguments, this instanceof wrap1); }; case 2: return function wrap2(a, b) { return fn(this, arguments, this instanceof wrap2); }; case 3: return function wrap3(a, b, c) { return fn(this, arguments, this instanceof wrap3); }; case 4: return function wrap4(a, b, c, d) { return fn(this, arguments, this instanceof wrap4); }; case 5: return function wrap5(a, b, c, d, e) { return fn(this, arguments, this instanceof wrap5); }; case 6: return function wrap6(a, b, c, d, e, f) { return fn(this, arguments, this instanceof wrap6); }; case 7: return function wrap7(a, b, c, d, e, f, g) { return fn(this, arguments, this instanceof wrap7); }; case 8: return function wrap8(a, b, c, d, e, f, g, h) { return fn(this, arguments, this instanceof wrap8); }; case 9: return function wrap9(a, b, c, d, e, f, g, h, i) { return fn(this, arguments, this instanceof wrap9); }; default: return function wrap() { return fn(this, arguments, this instanceof wrap); }; } } for (var prop in originalFn) { if (prop === 'and' || prop === 'calls') { throw new Error( "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon" ); } wrapper[prop] = originalFn[prop]; } /** * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used * whenever the spy is called with arguments that don't match any strategy * created with {@link Spy#withArgs}. * @name Spy#and * @since 2.0.0 * @example * spyOn(someObj, 'func').and.returnValue(42); */ wrapper.and = strategyDispatcher.and; /** * Specifies a strategy to be used for calls to the spy that have the * specified arguments. * @name Spy#withArgs * @since 3.0.0 * @function * @param {...*} args - The arguments to match * @type {SpyStrategy} * @example * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42); * someObj.func(1, 2, 3); // returns 42 */ wrapper.withArgs = function() { return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments); }; wrapper.calls = callTracker; if (defaultStrategyFn) { defaultStrategyFn(wrapper.and); } return wrapper; } function SpyStrategyDispatcher(strategyArgs, matchersUtil) { var baseStrategy = new j$.SpyStrategy(strategyArgs); var argsStrategies = new StrategyDict(function() { return new j$.SpyStrategy(strategyArgs); }, matchersUtil); this.and = baseStrategy; this.exec = function(spy, args, invokeNew) { var strategy = argsStrategies.get(args); if (!strategy) { if (argsStrategies.any() && !baseStrategy.isConfigured()) { throw new Error( "Spy '" + strategyArgs.name + "' received a call with arguments " + j$.basicPrettyPrinter_(Array.prototype.slice.call(args)) + ' but all configured strategies specify other arguments.' ); } else { strategy = baseStrategy; } } return strategy.exec(spy, args, invokeNew); }; this.withArgs = function() { return { and: argsStrategies.getOrCreate(arguments) }; }; } function StrategyDict(strategyFactory, matchersUtil) { this.strategies = []; this.strategyFactory = strategyFactory; this.matchersUtil = matchersUtil; } StrategyDict.prototype.any = function() { return this.strategies.length > 0; }; StrategyDict.prototype.getOrCreate = function(args) { var strategy = this.get(args); if (!strategy) { strategy = this.strategyFactory(); this.strategies.push({ args: args, strategy: strategy }); } return strategy; }; StrategyDict.prototype.get = function(args) { var i; for (i = 0; i < this.strategies.length; i++) { if (this.matchersUtil.equals(args, this.strategies[i].args)) { return this.strategies[i].strategy; } } }; return Spy; }; jasmine-4.0.0/src/core/SpyFactory.js000066400000000000000000000043071416413636100173320ustar00rootroot00000000000000getJasmineRequireObj().SpyFactory = function(j$) { function SpyFactory( getCustomStrategies, getDefaultStrategyFn, getMatchersUtil ) { var self = this; this.createSpy = function(name, originalFn) { return j$.Spy(name, getMatchersUtil(), { originalFn, customStrategies: getCustomStrategies(), defaultStrategyFn: getDefaultStrategyFn() }); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName); if (baseNameIsCollection) { propertyNames = methodNames; methodNames = baseName; baseName = 'unknown'; } var obj = {}; var spy, descriptor; var methods = normalizeKeyValues(methodNames); for (var i = 0; i < methods.length; i++) { spy = obj[methods[i][0]] = self.createSpy( baseName + '.' + methods[i][0] ); if (methods[i].length > 1) { spy.and.returnValue(methods[i][1]); } } var properties = normalizeKeyValues(propertyNames); for (var i = 0; i < properties.length; i++) { descriptor = { enumerable: true, get: self.createSpy(baseName + '.' + properties[i][0] + '.get'), set: self.createSpy(baseName + '.' + properties[i][0] + '.set') }; if (properties[i].length > 1) { descriptor.get.and.returnValue(properties[i][1]); descriptor.set.and.returnValue(properties[i][1]); } Object.defineProperty(obj, properties[i][0], descriptor); } if (methods.length === 0 && properties.length === 0) { throw 'createSpyObj requires a non-empty array or object of method names to create spies for'; } return obj; }; } function normalizeKeyValues(object) { var result = []; if (j$.isArray_(object)) { for (var i = 0; i < object.length; i++) { result.push([object[i]]); } } else if (j$.isObject_(object)) { for (var key in object) { if (object.hasOwnProperty(key)) { result.push([key, object[key]]); } } } return result; } return SpyFactory; }; jasmine-4.0.0/src/core/SpyRegistry.js000066400000000000000000000151511416413636100175320ustar00rootroot00000000000000getJasmineRequireObj().SpyRegistry = function(j$) { var spyOnMsg = j$.formatErrorMsg('', 'spyOn(, )'); var spyOnPropertyMsg = j$.formatErrorMsg( '', 'spyOnProperty(, , [accessType])' ); function SpyRegistry(options) { options = options || {}; var global = options.global || j$.getGlobal(); var createSpy = options.createSpy; var currentSpies = options.currentSpies || function() { return []; }; this.allowRespy = function(allow) { this.respy = allow; }; this.spyOn = function(obj, methodName) { var getErrorMsg = spyOnMsg; if (j$.util.isUndefined(obj) || obj === null) { throw new Error( getErrorMsg( 'could not find an object to spy upon for ' + methodName + '()' ) ); } if (j$.util.isUndefined(methodName) || methodName === null) { throw new Error(getErrorMsg('No method name supplied')); } if (j$.util.isUndefined(obj[methodName])) { throw new Error(getErrorMsg(methodName + '() method does not exist')); } if (obj[methodName] && j$.isSpy(obj[methodName])) { if (this.respy) { return obj[methodName]; } else { throw new Error( getErrorMsg(methodName + ' has already been spied upon') ); } } var descriptor = Object.getOwnPropertyDescriptor(obj, methodName); if (descriptor && !(descriptor.writable || descriptor.set)) { throw new Error( getErrorMsg(methodName + ' is not declared writable or has no setter') ); } var originalMethod = obj[methodName], spiedMethod = createSpy(methodName, originalMethod), restoreStrategy; if ( Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror') ) { restoreStrategy = function() { obj[methodName] = originalMethod; }; } else { restoreStrategy = function() { if (!delete obj[methodName]) { obj[methodName] = originalMethod; } }; } currentSpies().push({ restoreObjectToOriginalState: restoreStrategy }); obj[methodName] = spiedMethod; return spiedMethod; }; this.spyOnProperty = function(obj, propertyName, accessType) { var getErrorMsg = spyOnPropertyMsg; accessType = accessType || 'get'; if (j$.util.isUndefined(obj)) { throw new Error( getErrorMsg( 'spyOn could not find an object to spy upon for ' + propertyName + '' ) ); } if (j$.util.isUndefined(propertyName)) { throw new Error(getErrorMsg('No property name supplied')); } var descriptor = j$.util.getPropertyDescriptor(obj, propertyName); if (!descriptor) { throw new Error(getErrorMsg(propertyName + ' property does not exist')); } if (!descriptor.configurable) { throw new Error( getErrorMsg(propertyName + ' is not declared configurable') ); } if (!descriptor[accessType]) { throw new Error( getErrorMsg( 'Property ' + propertyName + ' does not have access type ' + accessType ) ); } if (j$.isSpy(descriptor[accessType])) { if (this.respy) { return descriptor[accessType]; } else { throw new Error( getErrorMsg( propertyName + '#' + accessType + ' has already been spied upon' ) ); } } var originalDescriptor = j$.util.clone(descriptor), spy = createSpy(propertyName, descriptor[accessType]), restoreStrategy; if (Object.prototype.hasOwnProperty.call(obj, propertyName)) { restoreStrategy = function() { Object.defineProperty(obj, propertyName, originalDescriptor); }; } else { restoreStrategy = function() { delete obj[propertyName]; }; } currentSpies().push({ restoreObjectToOriginalState: restoreStrategy }); descriptor[accessType] = spy; Object.defineProperty(obj, propertyName, descriptor); return spy; }; this.spyOnAllFunctions = function(obj, includeNonEnumerable) { if (j$.util.isUndefined(obj)) { throw new Error( 'spyOnAllFunctions could not find an object to spy upon' ); } var pointer = obj, propsToSpyOn = [], properties, propertiesToSkip = []; while ( pointer && (!includeNonEnumerable || pointer !== Object.prototype) ) { properties = getProps(pointer, includeNonEnumerable); properties = properties.filter(function(prop) { return propertiesToSkip.indexOf(prop) === -1; }); propertiesToSkip = propertiesToSkip.concat(properties); propsToSpyOn = propsToSpyOn.concat( getSpyableFunctionProps(pointer, properties) ); pointer = Object.getPrototypeOf(pointer); } for (var i = 0; i < propsToSpyOn.length; i++) { this.spyOn(obj, propsToSpyOn[i]); } return obj; }; this.clearSpies = function() { var spies = currentSpies(); for (var i = spies.length - 1; i >= 0; i--) { var spyEntry = spies[i]; spyEntry.restoreObjectToOriginalState(); } }; } function getProps(obj, includeNonEnumerable) { var enumerableProperties = Object.keys(obj); if (!includeNonEnumerable) { return enumerableProperties; } return Object.getOwnPropertyNames(obj).filter(function(prop) { return ( prop !== 'constructor' || enumerableProperties.indexOf('constructor') > -1 ); }); } function getSpyableFunctionProps(obj, propertiesToCheck) { var props = [], prop; for (var i = 0; i < propertiesToCheck.length; i++) { prop = propertiesToCheck[i]; if ( Object.prototype.hasOwnProperty.call(obj, prop) && isSpyableProp(obj, prop) ) { props.push(prop); } } return props; } function isSpyableProp(obj, prop) { var value, descriptor; try { value = obj[prop]; } catch (e) { return false; } if (value instanceof Function) { descriptor = Object.getOwnPropertyDescriptor(obj, prop); return (descriptor.writable || descriptor.set) && descriptor.configurable; } return false; } return SpyRegistry; }; jasmine-4.0.0/src/core/SpyStrategy.js000066400000000000000000000107141416413636100175240ustar00rootroot00000000000000getJasmineRequireObj().SpyStrategy = function(j$) { /** * @interface SpyStrategy */ function SpyStrategy(options) { options = options || {}; var self = this; /** * Get the identifying information for the spy. * @name SpyStrategy#identity * @since 3.0.0 * @member * @type {String} */ this.identity = options.name || 'unknown'; this.originalFn = options.fn || function() {}; this.getSpy = options.getSpy || function() {}; this.plan = this._defaultPlan = function() {}; var k, cs = options.customStrategies || {}; for (k in cs) { if (j$.util.has(cs, k) && !this[k]) { this[k] = createCustomPlan(cs[k]); } } /** * Tell the spy to return a promise resolving to the specified value when invoked. * @name SpyStrategy#resolveTo * @since 3.5.0 * @function * @param {*} value The value to return. */ this.resolveTo = function(value) { self.plan = function() { return Promise.resolve(value); }; return self.getSpy(); }; /** * Tell the spy to return a promise rejecting with the specified value when invoked. * @name SpyStrategy#rejectWith * @since 3.5.0 * @function * @param {*} value The value to return. */ this.rejectWith = function(value) { self.plan = function() { return Promise.reject(value); }; return self.getSpy(); }; } function createCustomPlan(factory) { return function() { var plan = factory.apply(null, arguments); if (!j$.isFunction_(plan)) { throw new Error('Spy strategy must return a function'); } this.plan = plan; return this.getSpy(); }; } /** * Execute the current spy strategy. * @name SpyStrategy#exec * @since 2.0.0 * @function */ SpyStrategy.prototype.exec = function(context, args, invokeNew) { var contextArgs = [context].concat( args ? Array.prototype.slice.call(args) : [] ); var target = this.plan.bind.apply(this.plan, contextArgs); return invokeNew ? new target() : target(); }; /** * Tell the spy to call through to the real implementation when invoked. * @name SpyStrategy#callThrough * @since 2.0.0 * @function */ SpyStrategy.prototype.callThrough = function() { this.plan = this.originalFn; return this.getSpy(); }; /** * Tell the spy to return the value when invoked. * @name SpyStrategy#returnValue * @since 2.0.0 * @function * @param {*} value The value to return. */ SpyStrategy.prototype.returnValue = function(value) { this.plan = function() { return value; }; return this.getSpy(); }; /** * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked. * @name SpyStrategy#returnValues * @since 2.1.0 * @function * @param {...*} values - Values to be returned on subsequent calls to the spy. */ SpyStrategy.prototype.returnValues = function() { var values = Array.prototype.slice.call(arguments); this.plan = function() { return values.shift(); }; return this.getSpy(); }; /** * Tell the spy to throw an error when invoked. * @name SpyStrategy#throwError * @since 2.0.0 * @function * @param {Error|Object|String} something Thing to throw */ SpyStrategy.prototype.throwError = function(something) { var error = j$.isString_(something) ? new Error(something) : something; this.plan = function() { throw error; }; return this.getSpy(); }; /** * Tell the spy to call a fake implementation when invoked. * @name SpyStrategy#callFake * @since 2.0.0 * @function * @param {Function} fn The function to invoke with the passed parameters. */ SpyStrategy.prototype.callFake = function(fn) { if ( !( j$.isFunction_(fn) || j$.isAsyncFunction_(fn) || j$.isGeneratorFunction_(fn) ) ) { throw new Error( 'Argument passed to callFake should be a function, got ' + fn ); } this.plan = fn; return this.getSpy(); }; /** * Tell the spy to do nothing when invoked. This is the default. * @name SpyStrategy#stub * @since 2.0.0 * @function */ SpyStrategy.prototype.stub = function(fn) { this.plan = function() {}; return this.getSpy(); }; SpyStrategy.prototype.isConfigured = function() { return this.plan !== this._defaultPlan; }; return SpyStrategy; }; jasmine-4.0.0/src/core/StackTrace.js000066400000000000000000000060341416413636100172520ustar00rootroot00000000000000getJasmineRequireObj().StackTrace = function(j$) { function StackTrace(error) { var lines = error.stack.split('\n').filter(function(line) { return line !== ''; }); var extractResult = extractMessage(error.message, lines); if (extractResult) { this.message = extractResult.message; lines = extractResult.remainder; } var parseResult = tryParseFrames(lines); this.frames = parseResult.frames; this.style = parseResult.style; } var framePatterns = [ // Node, Chrome, Edge // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)" // Note that the "function name" can include a surprisingly large set of // characters, including angle brackets and square brackets. { re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, fnIx: 1, fileLineColIx: 2, style: 'v8' }, // NodeJS alternate form, often mixed in with the Chrome style // e.g. " at /some/path:4320:20 { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' }, // PhantomJS on OS X, Safari, Firefox // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27" // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27" { re: /^(?:(([^@\s]+)@)|@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' } ]; // regexes should capture the function name (if any) as group 1 // and the file, line, and column as group 2. function tryParseFrames(lines) { var style = null; var frames = lines.map(function(line) { var convertedLine = first(framePatterns, function(pattern) { var overallMatch = line.match(pattern.re), fileLineColMatch; if (!overallMatch) { return null; } fileLineColMatch = overallMatch[pattern.fileLineColIx].match( /^(.*):(\d+):\d+$/ ); if (!fileLineColMatch) { return null; } style = style || pattern.style; return { raw: line, file: fileLineColMatch[1], line: parseInt(fileLineColMatch[2], 10), func: overallMatch[pattern.fnIx] }; }); return convertedLine || { raw: line }; }); return { style: style, frames: frames }; } function first(items, fn) { var i, result; for (i = 0; i < items.length; i++) { result = fn(items[i]); if (result) { return result; } } } function extractMessage(message, stackLines) { var len = messagePrefixLength(message, stackLines); if (len > 0) { return { message: stackLines.slice(0, len).join('\n'), remainder: stackLines.slice(len) }; } } function messagePrefixLength(message, stackLines) { if (!stackLines[0].match(/^\w*Error/)) { return 0; } var messageLines = message.split('\n'); var i; for (i = 1; i < messageLines.length; i++) { if (messageLines[i] !== stackLines[i]) { return 0; } } return messageLines.length; } return StackTrace; }; jasmine-4.0.0/src/core/Suite.js000066400000000000000000000216071416413636100163220ustar00rootroot00000000000000getJasmineRequireObj().Suite = function(j$) { /** * @interface Suite * @see Env#topSuite * @since 2.0.0 */ function Suite(attrs) { this.env = attrs.env; /** * The unique ID of this suite. * @name Suite#id * @readonly * @type {string} * @since 2.0.0 */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; /** * The description passed to the {@link describe} that created this suite. * @name Suite#description * @readonly * @type {string} * @since 2.0.0 */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.expectationResultFactory = attrs.expectationResultFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.autoCleanClosures = attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; this.onLateError = attrs.onLateError; this.beforeFns = []; this.afterFns = []; this.beforeAllFns = []; this.afterAllFns = []; this.timer = attrs.timer || new j$.Timer(); /** * The suite's children. * @name Suite#children * @type {Array.<(Spec|Suite)>} * @since 2.0.0 */ this.children = []; this.reset(); } Suite.prototype.setSuiteProperty = function(key, value) { this.result.properties = this.result.properties || {}; this.result.properties[key] = value; }; Suite.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; Suite.prototype.expectAsync = function(actual) { return this.asyncExpectationFactory(actual, this); }; /** * The full description including all ancestors of this suite. * @name Suite#getFullName * @function * @returns {string} * @since 2.0.0 */ Suite.prototype.getFullName = function() { var fullName = []; for ( var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite ) { if (parentSuite.parentSuite) { fullName.unshift(parentSuite.description); } } return fullName.join(' '); }; /* * Mark the suite with "pending" status */ Suite.prototype.pend = function() { this.markedPending = true; }; /* * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset} * Useful for fdescribe, xdescribe, where pending state should remain. */ Suite.prototype.exclude = function() { this.pend(); this.markedExcluding = true; }; Suite.prototype.beforeEach = function(fn) { this.beforeFns.unshift({ ...fn, suite: this }); }; Suite.prototype.beforeAll = function(fn) { this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); }; Suite.prototype.afterEach = function(fn) { this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); }; Suite.prototype.afterAll = function(fn) { this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); }; Suite.prototype.startTimer = function() { this.timer.start(); }; Suite.prototype.endTimer = function() { this.result.duration = this.timer.elapsed(); }; function removeFns(queueableFns) { for (var i = 0; i < queueableFns.length; i++) { queueableFns[i].fn = null; } } Suite.prototype.cleanupBeforeAfter = function() { if (this.autoCleanClosures) { removeFns(this.beforeAllFns); removeFns(this.afterAllFns); removeFns(this.beforeFns); removeFns(this.afterFns); } }; Suite.prototype.reset = function() { /** * @typedef SuiteResult * @property {Int} id - The unique id of this suite. * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} * @since 2.0.0 */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], deprecationWarnings: [], duration: null, properties: null }; this.markedPending = this.markedExcluding; this.children.forEach(function(child) { child.reset(); }); }; Suite.prototype.addChild = function(child) { this.children.push(child); }; Suite.prototype.status = function() { if (this.markedPending) { return 'pending'; } if (this.result.failedExpectations.length > 0) { return 'failed'; } else { return 'passed'; } }; Suite.prototype.canBeReentered = function() { return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; }; Suite.prototype.getResult = function() { this.result.status = this.status(); return this.result; }; Suite.prototype.sharedUserContext = function() { if (!this.sharedContext) { this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext(); } return this.sharedContext; }; Suite.prototype.clonedSharedUserContext = function() { return j$.UserContext.fromExisting(this.sharedUserContext()); }; Suite.prototype.onException = function() { if (arguments[0] instanceof j$.errors.ExpectationFailed) { return; } var data = { matcherName: '', passed: false, expected: '', actual: '', error: arguments[0] }; var failedExpectation = this.expectationResultFactory(data); if (!this.parentSuite) { failedExpectation.globalErrorType = 'afterAll'; } this.result.failedExpectations.push(failedExpectation); }; Suite.prototype.onMultipleDone = function() { let msg; // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. if (this.parentSuite) { msg = "An asynchronous beforeAll or afterAll function called its 'done' " + 'callback more than once.\n' + '(in suite: ' + this.getFullName() + ')'; } else { msg = 'A top-level beforeAll or afterAll function called its ' + "'done' callback more than once."; } this.onLateError(new Error(msg)); }; Suite.prototype.addExpectationResult = function() { if (isFailure(arguments)) { var data = arguments[1]; this.result.failedExpectations.push(this.expectationResultFactory(data)); if (this.throwOnExpectationFailure) { throw new j$.errors.ExpectationFailed(); } } }; Suite.prototype.addDeprecationWarning = function(deprecation) { if (typeof deprecation === 'string') { deprecation = { message: deprecation }; } this.result.deprecationWarnings.push( this.expectationResultFactory(deprecation) ); }; Object.defineProperty(Suite.prototype, 'metadata', { get: function() { if (!this.metadata_) { this.metadata_ = new SuiteMetadata(this); } return this.metadata_; } }); /** * @interface Suite * @see Env#topSuite */ function SuiteMetadata(suite) { this.suite_ = suite; /** * The unique ID of this suite. * @name Suite#id * @readonly * @type {string} */ this.id = suite.id; /** * The parent of this suite, or null if this is the top suite. * @name Suite#parentSuite * @readonly * @type {Suite} */ this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; /** * The description passed to the {@link describe} that created this suite. * @name Suite#description * @readonly * @type {string} */ this.description = suite.description; } /** * The full description including all ancestors of this suite. * @name Suite#getFullName * @function * @returns {string} */ SuiteMetadata.prototype.getFullName = function() { return this.suite_.getFullName(); }; /** * The suite's children. * @name Suite#children * @type {Array.<(Spec|Suite)>} */ Object.defineProperty(SuiteMetadata.prototype, 'children', { get: function() { return this.suite_.children.map(child => child.metadata); } }); function isFailure(args) { return !args[0]; } return Suite; }; jasmine-4.0.0/src/core/Timer.js000066400000000000000000000006631416413636100163100ustar00rootroot00000000000000getJasmineRequireObj().Timer = function() { var defaultNow = (function(Date) { return function() { return new Date().getTime(); }; })(Date); function Timer(options) { options = options || {}; var now = options.now || defaultNow, startTime; this.start = function() { startTime = now(); }; this.elapsed = function() { return now() - startTime; }; } return Timer; }; jasmine-4.0.0/src/core/TreeProcessor.js000066400000000000000000000155301416413636100200260ustar00rootroot00000000000000getJasmineRequireObj().TreeProcessor = function() { function TreeProcessor(attrs) { var tree = attrs.tree, runnableIds = attrs.runnableIds, queueRunnerFactory = attrs.queueRunnerFactory, nodeStart = attrs.nodeStart || function() {}, nodeComplete = attrs.nodeComplete || function() {}, failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations, orderChildren = attrs.orderChildren || function(node) { return node.children; }, excludeNode = attrs.excludeNode || function(node) { return false; }, stats = { valid: true }, processed = false, defaultMin = Infinity, defaultMax = 1 - Infinity; this.processTree = function() { processNode(tree, true); processed = true; return stats; }; this.execute = function(done) { if (!processed) { this.processTree(); } if (!stats.valid) { throw 'invalid order'; } var childFns = wrapChildren(tree, 0); queueRunnerFactory({ queueableFns: childFns, userContext: tree.sharedUserContext(), onException: function() { tree.onException.apply(tree, arguments); }, onComplete: done, onMultipleDone: tree.onMultipleDone ? tree.onMultipleDone.bind(tree) : null }); }; function runnableIndex(id) { for (var i = 0; i < runnableIds.length; i++) { if (runnableIds[i] === id) { return i; } } } function processNode(node, parentExcluded) { var executableIndex = runnableIndex(node.id); if (executableIndex !== undefined) { parentExcluded = false; } if (!node.children) { var excluded = parentExcluded || excludeNode(node); stats[node.id] = { excluded: excluded, willExecute: !excluded && !node.markedPending, segments: [ { index: 0, owner: node, nodes: [node], min: startingMin(executableIndex), max: startingMax(executableIndex) } ] }; } else { var hasExecutableChild = false; var orderedChildren = orderChildren(node); for (var i = 0; i < orderedChildren.length; i++) { var child = orderedChildren[i]; processNode(child, parentExcluded); if (!stats.valid) { return; } var childStats = stats[child.id]; hasExecutableChild = hasExecutableChild || childStats.willExecute; } stats[node.id] = { excluded: parentExcluded, willExecute: hasExecutableChild }; segmentChildren(node, orderedChildren, stats[node.id], executableIndex); if (!node.canBeReentered() && stats[node.id].segments.length > 1) { stats = { valid: false }; } } } function startingMin(executableIndex) { return executableIndex === undefined ? defaultMin : executableIndex; } function startingMax(executableIndex) { return executableIndex === undefined ? defaultMax : executableIndex; } function segmentChildren( node, orderedChildren, nodeStats, executableIndex ) { var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) }, result = [currentSegment], lastMax = defaultMax, orderedChildSegments = orderChildSegments(orderedChildren); function isSegmentBoundary(minIndex) { return ( lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1 ); } for (var i = 0; i < orderedChildSegments.length; i++) { var childSegment = orderedChildSegments[i], maxIndex = childSegment.max, minIndex = childSegment.min; if (isSegmentBoundary(minIndex)) { currentSegment = { index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax }; result.push(currentSegment); } currentSegment.nodes.push(childSegment); currentSegment.min = Math.min(currentSegment.min, minIndex); currentSegment.max = Math.max(currentSegment.max, maxIndex); lastMax = maxIndex; } nodeStats.segments = result; } function orderChildSegments(children) { var specifiedOrder = [], unspecifiedOrder = []; for (var i = 0; i < children.length; i++) { var child = children[i], segments = stats[child.id].segments; for (var j = 0; j < segments.length; j++) { var seg = segments[j]; if (seg.min === defaultMin) { unspecifiedOrder.push(seg); } else { specifiedOrder.push(seg); } } } specifiedOrder.sort(function(a, b) { return a.min - b.min; }); return specifiedOrder.concat(unspecifiedOrder); } function executeNode(node, segmentNumber) { if (node.children) { return { fn: function(done) { var onStart = { fn: function(next) { nodeStart(node, next); } }; queueRunnerFactory({ onComplete: function() { var args = Array.prototype.slice.call(arguments, [0]); node.cleanupBeforeAfter(); nodeComplete(node, node.getResult(), function() { done.apply(undefined, args); }); }, queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)), userContext: node.sharedUserContext(), onException: function() { node.onException.apply(node, arguments); }, onMultipleDone: node.onMultipleDone ? node.onMultipleDone.bind(node) : null }); } }; } else { return { fn: function(done) { node.execute( done, stats[node.id].excluded, failSpecWithNoExpectations ); } }; } } function wrapChildren(node, segmentNumber) { var result = [], segmentChildren = stats[node.id].segments[segmentNumber].nodes; for (var i = 0; i < segmentChildren.length; i++) { result.push( executeNode(segmentChildren[i].owner, segmentChildren[i].index) ); } if (!stats[node.id].willExecute) { return result; } return node.beforeAllFns.concat(result).concat(node.afterAllFns); } } return TreeProcessor; }; jasmine-4.0.0/src/core/UserContext.js000066400000000000000000000005471416413636100175140ustar00rootroot00000000000000getJasmineRequireObj().UserContext = function(j$) { function UserContext() {} UserContext.fromExisting = function(oldContext) { var context = new UserContext(); for (var prop in oldContext) { if (oldContext.hasOwnProperty(prop)) { context[prop] = oldContext[prop]; } } return context; }; return UserContext; }; jasmine-4.0.0/src/core/asymmetric_equality/000077500000000000000000000000001416413636100207575ustar00rootroot00000000000000jasmine-4.0.0/src/core/asymmetric_equality/Any.js000066400000000000000000000024751416413636100220540ustar00rootroot00000000000000getJasmineRequireObj().Any = function(j$) { function Any(expectedObject) { if (typeof expectedObject === 'undefined') { throw new TypeError( 'jasmine.any() expects to be passed a constructor function. ' + 'Please pass one or use jasmine.anything() to match any object.' ); } this.expectedObject = expectedObject; } Any.prototype.asymmetricMatch = function(other) { if (this.expectedObject == String) { return typeof other == 'string' || other instanceof String; } if (this.expectedObject == Number) { return typeof other == 'number' || other instanceof Number; } if (this.expectedObject == Function) { return typeof other == 'function' || other instanceof Function; } if (this.expectedObject == Object) { return other !== null && typeof other == 'object'; } if (this.expectedObject == Boolean) { return typeof other == 'boolean'; } /* jshint -W122 */ /* global Symbol */ if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) { return typeof other == 'symbol'; } /* jshint +W122 */ return other instanceof this.expectedObject; }; Any.prototype.jasmineToString = function() { return ''; }; return Any; }; jasmine-4.0.0/src/core/asymmetric_equality/Anything.js000066400000000000000000000004651416413636100231030ustar00rootroot00000000000000getJasmineRequireObj().Anything = function(j$) { function Anything() {} Anything.prototype.asymmetricMatch = function(other) { return !j$.util.isUndefined(other) && other !== null; }; Anything.prototype.jasmineToString = function() { return ''; }; return Anything; }; jasmine-4.0.0/src/core/asymmetric_equality/ArrayContaining.js000066400000000000000000000021171416413636100244060ustar00rootroot00000000000000getJasmineRequireObj().ArrayContaining = function(j$) { function ArrayContaining(sample) { this.sample = sample; } ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isArray_(this.sample)) { throw new Error( 'You must provide an array to arrayContaining, not ' + j$.basicPrettyPrinter_(this.sample) + '.' ); } // If the actual parameter is not an array, we can fail immediately, since it couldn't // possibly be an "array containing" anything. However, we also want an empty sample // array to match anything, so we need to double-check we aren't in that case if (!j$.isArray_(other) && this.sample.length > 0) { return false; } for (var i = 0; i < this.sample.length; i++) { var item = this.sample[i]; if (!matchersUtil.contains(other, item)) { return false; } } return true; }; ArrayContaining.prototype.jasmineToString = function(pp) { return ''; }; return ArrayContaining; }; jasmine-4.0.0/src/core/asymmetric_equality/ArrayWithExactContents.js000066400000000000000000000015741416413636100257410ustar00rootroot00000000000000getJasmineRequireObj().ArrayWithExactContents = function(j$) { function ArrayWithExactContents(sample) { this.sample = sample; } ArrayWithExactContents.prototype.asymmetricMatch = function( other, matchersUtil ) { if (!j$.isArray_(this.sample)) { throw new Error( 'You must provide an array to arrayWithExactContents, not ' + j$.basicPrettyPrinter_(this.sample) + '.' ); } if (this.sample.length !== other.length) { return false; } for (var i = 0; i < this.sample.length; i++) { var item = this.sample[i]; if (!matchersUtil.contains(other, item)) { return false; } } return true; }; ArrayWithExactContents.prototype.jasmineToString = function(pp) { return ''; }; return ArrayWithExactContents; }; jasmine-4.0.0/src/core/asymmetric_equality/Empty.js000066400000000000000000000010321416413636100224070ustar00rootroot00000000000000getJasmineRequireObj().Empty = function(j$) { function Empty() {} Empty.prototype.asymmetricMatch = function(other) { if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) { return other.length === 0; } if (j$.isMap(other) || j$.isSet(other)) { return other.size === 0; } if (j$.isObject_(other)) { return Object.keys(other).length === 0; } return false; }; Empty.prototype.jasmineToString = function() { return ''; }; return Empty; }; jasmine-4.0.0/src/core/asymmetric_equality/Falsy.js000066400000000000000000000003741416413636100223770ustar00rootroot00000000000000getJasmineRequireObj().Falsy = function(j$) { function Falsy() {} Falsy.prototype.asymmetricMatch = function(other) { return !other; }; Falsy.prototype.jasmineToString = function() { return ''; }; return Falsy; }; jasmine-4.0.0/src/core/asymmetric_equality/MapContaining.js000066400000000000000000000020551416413636100240460ustar00rootroot00000000000000getJasmineRequireObj().MapContaining = function(j$) { function MapContaining(sample) { if (!j$.isMap(sample)) { throw new Error( 'You must provide a map to `mapContaining`, not ' + j$.basicPrettyPrinter_(sample) ); } this.sample = sample; } MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isMap(other)) return false; for (const [key, value] of this.sample) { // for each key/value pair in `sample` // there should be at least one pair in `other` whose key and value both match var hasMatch = false; for (const [oKey, oValue] of other) { if ( matchersUtil.equals(oKey, key) && matchersUtil.equals(oValue, value) ) { hasMatch = true; break; } } if (!hasMatch) { return false; } } return true; }; MapContaining.prototype.jasmineToString = function(pp) { return ''; }; return MapContaining; }; jasmine-4.0.0/src/core/asymmetric_equality/NotEmpty.js000066400000000000000000000010551416413636100230750ustar00rootroot00000000000000getJasmineRequireObj().NotEmpty = function(j$) { function NotEmpty() {} NotEmpty.prototype.asymmetricMatch = function(other) { if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) { return other.length !== 0; } if (j$.isMap(other) || j$.isSet(other)) { return other.size !== 0; } if (j$.isObject_(other)) { return Object.keys(other).length !== 0; } return false; }; NotEmpty.prototype.jasmineToString = function() { return ''; }; return NotEmpty; }; jasmine-4.0.0/src/core/asymmetric_equality/ObjectContaining.js000066400000000000000000000031441416413636100245370ustar00rootroot00000000000000getJasmineRequireObj().ObjectContaining = function(j$) { function ObjectContaining(sample) { this.sample = sample; } function hasProperty(obj, property) { if (!obj || typeof obj !== 'object') { return false; } if (Object.prototype.hasOwnProperty.call(obj, property)) { return true; } return hasProperty(Object.getPrototypeOf(obj), property); } ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (typeof this.sample !== 'object') { throw new Error( "You must provide an object to objectContaining, not '" + this.sample + "'." ); } if (typeof other !== 'object') { return false; } for (var property in this.sample) { if ( !hasProperty(other, property) || !matchersUtil.equals(this.sample[property], other[property]) ) { return false; } } return true; }; ObjectContaining.prototype.valuesForDiff_ = function(other, pp) { if (!j$.isObject_(other)) { return { self: this.jasmineToString(pp), other: other }; } var filteredOther = {}; Object.keys(this.sample).forEach(function(k) { // eq short-circuits comparison of objects that have different key sets, // so include all keys even if undefined. filteredOther[k] = other[k]; }); return { self: this.sample, other: filteredOther }; }; ObjectContaining.prototype.jasmineToString = function(pp) { return ''; }; return ObjectContaining; }; jasmine-4.0.0/src/core/asymmetric_equality/SetContaining.js000066400000000000000000000020601416413636100240600ustar00rootroot00000000000000getJasmineRequireObj().SetContaining = function(j$) { function SetContaining(sample) { if (!j$.isSet(sample)) { throw new Error( 'You must provide a set to `setContaining`, not ' + j$.basicPrettyPrinter_(sample) ); } this.sample = sample; } SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isSet(other)) return false; for (const item of this.sample) { // for each item in `sample` there should be at least one matching item in `other` // (not using `matchersUtil.contains` because it compares set members by reference, // not by deep value equality) var hasMatch = false; for (const oItem of other) { if (matchersUtil.equals(oItem, item)) { hasMatch = true; break; } } if (!hasMatch) { return false; } } return true; }; SetContaining.prototype.jasmineToString = function(pp) { return ''; }; return SetContaining; }; jasmine-4.0.0/src/core/asymmetric_equality/StringContaining.js000066400000000000000000000011751416413636100246010ustar00rootroot00000000000000getJasmineRequireObj().StringContaining = function(j$) { function StringContaining(expected) { if (!j$.isString_(expected)) { throw new Error('Expected is not a String'); } this.expected = expected; } StringContaining.prototype.asymmetricMatch = function(other) { if (!j$.isString_(other)) { // Arrays, etc. don't match no matter what their indexOf returns. return false; } return other.indexOf(this.expected) !== -1; }; StringContaining.prototype.jasmineToString = function() { return ''; }; return StringContaining; }; jasmine-4.0.0/src/core/asymmetric_equality/StringMatching.js000066400000000000000000000010241416413636100242330ustar00rootroot00000000000000getJasmineRequireObj().StringMatching = function(j$) { function StringMatching(expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { throw new Error('Expected is not a String or a RegExp'); } this.regexp = new RegExp(expected); } StringMatching.prototype.asymmetricMatch = function(other) { return this.regexp.test(other); }; StringMatching.prototype.jasmineToString = function() { return ''; }; return StringMatching; }; jasmine-4.0.0/src/core/asymmetric_equality/Truthy.js000066400000000000000000000004031416413636100226110ustar00rootroot00000000000000getJasmineRequireObj().Truthy = function(j$) { function Truthy() {} Truthy.prototype.asymmetricMatch = function(other) { return !!other; }; Truthy.prototype.jasmineToString = function() { return ''; }; return Truthy; }; jasmine-4.0.0/src/core/base.js000066400000000000000000000336231416413636100161440ustar00rootroot00000000000000getJasmineRequireObj().base = function(j$, jasmineGlobal) { j$.unimplementedMethod_ = function() { throw new Error('unimplemented method'); }; /** * Maximum object depth the pretty printer will print to. * Set this to a lower value to speed up pretty printing if you have large objects. * @name jasmine.MAX_PRETTY_PRINT_DEPTH * @default 8 * @since 1.3.0 */ j$.MAX_PRETTY_PRINT_DEPTH = 8; /** * Maximum number of array elements to display when pretty printing objects. * This will also limit the number of keys and values displayed for an object. * Elements past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH * @default 50 * @since 2.7.0 */ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50; /** * Maximum number of characters to display when pretty printing objects. * Characters past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_CHARS * @default 100 * @since 2.9.0 */ j$.MAX_PRETTY_PRINT_CHARS = 1000; /** * Default number of milliseconds Jasmine will wait for an asynchronous spec, * before, or after function to complete. This can be overridden on a case by * case basis by passing a time limit as the third argument to {@link it}, * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or * {@link afterAll}. The value must be no greater than the largest number of * milliseconds supported by setTimeout, which is usually 2147483647. * * While debugging tests, you may want to set this to a large number (or pass * a large number to one of the functions mentioned above) so that Jasmine * does not move on to after functions or the next spec while you're debugging. * @name jasmine.DEFAULT_TIMEOUT_INTERVAL * @default 5000 * @since 1.3.0 */ var DEFAULT_TIMEOUT_INTERVAL = 5000; Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', { get: function() { return DEFAULT_TIMEOUT_INTERVAL; }, set: function(newValue) { j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL'); DEFAULT_TIMEOUT_INTERVAL = newValue; } }); j$.getGlobal = function() { return jasmineGlobal; }; /** * Get the currently booted Jasmine Environment. * * @name jasmine.getEnv * @since 1.3.0 * @function * @return {Env} */ j$.getEnv = function(options) { var env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options)); //jasmine. singletons in here (setTimeout blah blah). return env; }; j$.isArray_ = function(value) { return j$.isA_('Array', value); }; j$.isObject_ = function(value) { return ( !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value) ); }; j$.isString_ = function(value) { return j$.isA_('String', value); }; j$.isNumber_ = function(value) { return j$.isA_('Number', value); }; j$.isFunction_ = function(value) { return j$.isA_('Function', value); }; j$.isAsyncFunction_ = function(value) { return j$.isA_('AsyncFunction', value); }; j$.isGeneratorFunction_ = function(value) { return j$.isA_('GeneratorFunction', value); }; j$.isTypedArray_ = function(value) { return ( j$.isA_('Float32Array', value) || j$.isA_('Float64Array', value) || j$.isA_('Int16Array', value) || j$.isA_('Int32Array', value) || j$.isA_('Int8Array', value) || j$.isA_('Uint16Array', value) || j$.isA_('Uint32Array', value) || j$.isA_('Uint8Array', value) || j$.isA_('Uint8ClampedArray', value) ); }; j$.isA_ = function(typeName, value) { return j$.getType_(value) === '[object ' + typeName + ']'; }; j$.isError_ = function(value) { if (!value) { return false; } if (value instanceof Error) { return true; } return typeof value.stack === 'string' && typeof value.message === 'string'; }; j$.isAsymmetricEqualityTester_ = function(obj) { return obj ? j$.isA_('Function', obj.asymmetricMatch) : false; }; j$.getType_ = function(value) { return Object.prototype.toString.apply(value); }; j$.isDomNode = function(obj) { // Node is a function, because constructors return typeof jasmineGlobal.Node !== 'undefined' ? obj instanceof jasmineGlobal.Node : obj !== null && typeof obj === 'object' && typeof obj.nodeType === 'number' && typeof obj.nodeName === 'string'; // return obj.nodeType > 0; }; j$.isMap = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.Map ); }; j$.isSet = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.Set ); }; j$.isWeakMap = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.WeakMap ); }; j$.isURL = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.URL ); }; j$.isIterable_ = function(value) { return value && !!value[Symbol.iterator]; }; j$.isDataView = function(obj) { return ( obj !== null && typeof obj !== 'undefined' && obj.constructor === jasmineGlobal.DataView ); }; j$.isPromise = function(obj) { return !!obj && obj.constructor === jasmineGlobal.Promise; }; j$.isPromiseLike = function(obj) { return !!obj && j$.isFunction_(obj.then); }; j$.fnNameFor = function(func) { if (func.name) { return func.name; } var matches = func.toString().match(/^\s*function\s*(\w+)\s*\(/) || func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/); return matches ? matches[1] : ''; }; j$.isPending_ = function(promise) { var sentinel = {}; return Promise.race([promise, Promise.resolve(sentinel)]).then( function(result) { return result === sentinel; }, function() { return false; } ); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is an instance of the specified class/constructor. * @name jasmine.any * @since 1.3.0 * @function * @param {Constructor} clazz - The constructor to check against. */ j$.any = function(clazz) { return new j$.Any(clazz); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is not `null` and not `undefined`. * @name jasmine.anything * @since 2.2.0 * @function */ j$.anything = function() { return new j$.Anything(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is `true` or anything truthy. * @name jasmine.truthy * @since 3.1.0 * @function */ j$.truthy = function() { return new j$.Truthy(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey. * @name jasmine.falsy * @since 3.1.0 * @function */ j$.falsy = function() { return new j$.Falsy(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is empty. * @name jasmine.empty * @since 3.1.0 * @function */ j$.empty = function() { return new j$.Empty(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared is not empty. * @name jasmine.notEmpty * @since 3.1.0 * @function */ j$.notEmpty = function() { return new j$.NotEmpty(); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value being compared contains at least the keys and values. * @name jasmine.objectContaining * @since 1.3.0 * @function * @param {Object} sample - The subset of properties that _must_ be in the actual. */ j$.objectContaining = function(sample) { return new j$.ObjectContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`. * @name jasmine.stringMatching * @since 2.2.0 * @function * @param {RegExp|String} expected */ j$.stringMatching = function(expected) { return new j$.StringMatching(expected); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is a `String` that contains the specified `String`. * @name jasmine.stringContaining * @since 3.10.0 * @function * @param {String} expected */ j$.stringContaining = function(expected) { return new j$.StringContaining(expected); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains at least the elements in the sample. * @name jasmine.arrayContaining * @since 2.2.0 * @function * @param {Array} sample */ j$.arrayContaining = function(sample) { return new j$.ArrayContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order. * @name jasmine.arrayWithExactContents * @since 2.8.0 * @function * @param {Array} sample */ j$.arrayWithExactContents = function(sample) { return new j$.ArrayWithExactContents(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if every key/value pair in the sample passes the deep equality comparison * with at least one key/value pair in the actual value being compared * @name jasmine.mapContaining * @since 3.5.0 * @function * @param {Map} sample - The subset of items that _must_ be in the actual. */ j$.mapContaining = function(sample) { return new j$.MapContaining(sample); }; /** * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if every item in the sample passes the deep equality comparison * with at least one item in the actual value being compared * @name jasmine.setContaining * @since 3.5.0 * @function * @param {Set} sample - The subset of items that _must_ be in the actual. */ j$.setContaining = function(sample) { return new j$.SetContaining(sample); }; /** * Determines whether the provided function is a Jasmine spy. * @name jasmine.isSpy * @since 2.0.0 * @function * @param {Function} putativeSpy - The function to check. * @return {Boolean} */ j$.isSpy = function(putativeSpy) { if (!putativeSpy) { return false; } return ( putativeSpy.and instanceof j$.SpyStrategy && putativeSpy.calls instanceof j$.CallTracker ); }; /** * Logs a message for use in debugging. If the spec fails, trace messages * will be included in the {@link SpecResult|result} passed to the * reporter's specDone method. * * This method should be called only when a spec (including any associated * beforeEach or afterEach functions) is running. * @function * @name jasmine.debugLog * @since 4.0.0 * @param {String} msg - The message to log */ j$.debugLog = function(msg) { j$.getEnv().debugLog(msg); }; }; jasmine-4.0.0/src/core/errors.js000066400000000000000000000003711416413636100165400ustar00rootroot00000000000000getJasmineRequireObj().errors = function() { function ExpectationFailed() {} ExpectationFailed.prototype = new Error(); ExpectationFailed.prototype.constructor = ExpectationFailed; return { ExpectationFailed: ExpectationFailed }; }; jasmine-4.0.0/src/core/formatErrorMsg.js000066400000000000000000000004421416413636100201740ustar00rootroot00000000000000getJasmineRequireObj().formatErrorMsg = function() { function generateErrorMsg(domain, usage) { var usageDefinition = usage ? '\nUsage: ' + usage : ''; return function errorMsg(msg) { return domain + ' : ' + msg + usageDefinition; }; } return generateErrorMsg; }; jasmine-4.0.0/src/core/matchers/000077500000000000000000000000001416413636100164735ustar00rootroot00000000000000jasmine-4.0.0/src/core/matchers/DiffBuilder.js000066400000000000000000000060661416413636100212200ustar00rootroot00000000000000getJasmineRequireObj().DiffBuilder = function(j$) { return function DiffBuilder(config) { var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(), mismatches = new j$.MismatchTree(), path = new j$.ObjectPath(), actualRoot = undefined, expectedRoot = undefined; return { setRoots: function(actual, expected) { actualRoot = actual; expectedRoot = expected; }, recordMismatch: function(formatter) { mismatches.add(path, formatter); }, getMessage: function() { var messages = []; mismatches.traverse(function(path, isLeaf, formatter) { var actualCustom, expectedCustom, useCustom, derefResult = dereferencePath( path, actualRoot, expectedRoot, prettyPrinter ), actual = derefResult.actual, expected = derefResult.expected; if (formatter) { messages.push(formatter(actual, expected, path, prettyPrinter)); return true; } actualCustom = prettyPrinter.customFormat_(actual); expectedCustom = prettyPrinter.customFormat_(expected); useCustom = !( j$.util.isUndefined(actualCustom) && j$.util.isUndefined(expectedCustom) ); if (useCustom) { messages.push( wrapPrettyPrinted(actualCustom, expectedCustom, path) ); return false; // don't recurse further } if (isLeaf) { messages.push( defaultFormatter(actual, expected, path, prettyPrinter) ); } return true; }); return messages.join('\n'); }, withPath: function(pathComponent, block) { var oldPath = path; path = path.add(pathComponent); block(); path = oldPath; } }; function defaultFormatter(actual, expected, path, prettyPrinter) { return wrapPrettyPrinted( prettyPrinter(actual), prettyPrinter(expected), path ); } function wrapPrettyPrinted(actual, expected, path) { return ( 'Expected ' + path + (path.depth() ? ' = ' : '') + actual + ' to equal ' + expected + '.' ); } }; function dereferencePath(objectPath, actual, expected, pp) { function handleAsymmetricExpected() { if ( j$.isAsymmetricEqualityTester_(expected) && j$.isFunction_(expected.valuesForDiff_) ) { var asymmetricResult = expected.valuesForDiff_(actual, pp); expected = asymmetricResult.self; actual = asymmetricResult.other; } } var i; handleAsymmetricExpected(); for (i = 0; i < objectPath.components.length; i++) { actual = actual[objectPath.components[i]]; expected = expected[objectPath.components[i]]; handleAsymmetricExpected(); } return { actual: actual, expected: expected }; } }; jasmine-4.0.0/src/core/matchers/MismatchTree.js000066400000000000000000000032021416413636100214130ustar00rootroot00000000000000getJasmineRequireObj().MismatchTree = function(j$) { /* To be able to apply custom object formatters at all possible levels of an object graph, DiffBuilder needs to be able to know not just where the mismatch occurred but also all ancestors of the mismatched value in both the expected and actual object graphs. MismatchTree maintains that context and provides it via the traverse method. */ function MismatchTree(path) { this.path = path || new j$.ObjectPath([]); this.formatter = undefined; this.children = []; this.isMismatch = false; } MismatchTree.prototype.add = function(path, formatter) { var key, child; if (path.depth() === 0) { this.formatter = formatter; this.isMismatch = true; } else { key = path.components[0]; path = path.shift(); child = this.child(key); if (!child) { child = new MismatchTree(this.path.add(key)); this.children.push(child); } child.add(path, formatter); } }; MismatchTree.prototype.traverse = function(visit) { var i, hasChildren = this.children.length > 0; if (this.isMismatch || hasChildren) { if (visit(this.path, !hasChildren, this.formatter)) { for (i = 0; i < this.children.length; i++) { this.children[i].traverse(visit); } } } }; MismatchTree.prototype.child = function(key) { var i, pathEls; for (i = 0; i < this.children.length; i++) { pathEls = this.children[i].path.components; if (pathEls[pathEls.length - 1] === key) { return this.children[i]; } } }; return MismatchTree; }; jasmine-4.0.0/src/core/matchers/NullDiffBuilder.js000066400000000000000000000003541416413636100220450ustar00rootroot00000000000000getJasmineRequireObj().NullDiffBuilder = function(j$) { return function() { return { withPath: function(_, block) { block(); }, setRoots: function() {}, recordMismatch: function() {} }; }; }; jasmine-4.0.0/src/core/matchers/ObjectPath.js000066400000000000000000000021611416413636100210540ustar00rootroot00000000000000getJasmineRequireObj().ObjectPath = function(j$) { function ObjectPath(components) { this.components = components || []; } ObjectPath.prototype.toString = function() { if (this.components.length) { return '$' + map(this.components, formatPropertyAccess).join(''); } else { return ''; } }; ObjectPath.prototype.add = function(component) { return new ObjectPath(this.components.concat([component])); }; ObjectPath.prototype.shift = function() { return new ObjectPath(this.components.slice(1)); }; ObjectPath.prototype.depth = function() { return this.components.length; }; function formatPropertyAccess(prop) { if (typeof prop === 'number') { return '[' + prop + ']'; } if (isValidIdentifier(prop)) { return '.' + prop; } return "['" + prop + "']"; } function map(array, fn) { var results = []; for (var i = 0; i < array.length; i++) { results.push(fn(array[i])); } return results; } function isValidIdentifier(string) { return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string); } return ObjectPath; }; jasmine-4.0.0/src/core/matchers/async/000077500000000000000000000000001416413636100176105ustar00rootroot00000000000000jasmine-4.0.0/src/core/matchers/async/toBePending.js000066400000000000000000000014161416413636100223460ustar00rootroot00000000000000getJasmineRequireObj().toBePending = function(j$) { /** * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected. * @function * @async * @name async-matchers#toBePending * @since 3.6 * @example * await expectAsync(aPromise).toBePending(); */ return function toBePending() { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBePending to be called on a promise.'); } var want = {}; return Promise.race([actual, Promise.resolve(want)]).then( function(got) { return { pass: want === got }; }, function() { return { pass: false }; } ); } }; }; }; jasmine-4.0.0/src/core/matchers/async/toBeRejected.js000066400000000000000000000013321416413636100225040ustar00rootroot00000000000000getJasmineRequireObj().toBeRejected = function(j$) { /** * Expect a promise to be rejected. * @function * @async * @name async-matchers#toBeRejected * @since 3.1.0 * @example * await expectAsync(aPromise).toBeRejected(); * @example * return expectAsync(aPromise).toBeRejected(); */ return function toBeRejected() { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBeRejected to be called on a promise.'); } return actual.then( function() { return { pass: false }; }, function() { return { pass: true }; } ); } }; }; }; jasmine-4.0.0/src/core/matchers/async/toBeRejectedWith.js000066400000000000000000000033511416413636100233430ustar00rootroot00000000000000getJasmineRequireObj().toBeRejectedWith = function(j$) { /** * Expect a promise to be rejected with a value equal to the expected, using deep equality comparison. * @function * @async * @name async-matchers#toBeRejectedWith * @since 3.3.0 * @param {Object} expected - Value that the promise is expected to be rejected with * @example * await expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); * @example * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); */ return function toBeRejectedWith(matchersUtil) { return { compare: function(actualPromise, expectedValue) { if (!j$.isPromiseLike(actualPromise)) { throw new Error( 'Expected toBeRejectedWith to be called on a promise.' ); } function prefix(passed) { return ( 'Expected a promise ' + (passed ? 'not ' : '') + 'to be rejected with ' + matchersUtil.pp(expectedValue) ); } return actualPromise.then( function() { return { pass: false, message: prefix(false) + ' but it was resolved.' }; }, function(actualValue) { if (matchersUtil.equals(actualValue, expectedValue)) { return { pass: true, message: prefix(true) + '.' }; } else { return { pass: false, message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' }; } } ); } }; }; }; jasmine-4.0.0/src/core/matchers/async/toBeRejectedWithError.js000066400000000000000000000064341416413636100243620ustar00rootroot00000000000000getJasmineRequireObj().toBeRejectedWithError = function(j$) { /** * Expect a promise to be rejected with a value matched to the expected * @function * @async * @name async-matchers#toBeRejectedWithError * @since 3.5.0 * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` * @example * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message'); * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/); * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError); * await expectAsync(aPromise).toBeRejectedWithError('Error message'); * return expectAsync(aPromise).toBeRejectedWithError(/Error message/); */ return function toBeRejectedWithError(matchersUtil) { return { compare: function(actualPromise, arg1, arg2) { if (!j$.isPromiseLike(actualPromise)) { throw new Error( 'Expected toBeRejectedWithError to be called on a promise.' ); } var expected = getExpectedFromArgs(arg1, arg2, matchersUtil); return actualPromise.then( function() { return { pass: false, message: 'Expected a promise to be rejected but it was resolved.' }; }, function(actualValue) { return matchError(actualValue, expected, matchersUtil); } ); } }; }; function matchError(actual, expected, matchersUtil) { if (!j$.isError_(actual)) { return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); } if (!(actual instanceof expected.error)) { return fail( expected, 'rejected with type ' + j$.fnNameFor(actual.constructor) ); } var actualMessage = actual.message; if ( actualMessage === expected.message || typeof expected.message === 'undefined' ) { return pass(expected); } if ( expected.message instanceof RegExp && expected.message.test(actualMessage) ) { return pass(expected); } return fail(expected, 'rejected with ' + matchersUtil.pp(actual)); } function pass(expected) { return { pass: true, message: 'Expected a promise not to be rejected with ' + expected.printValue + ', but it was.' }; } function fail(expected, message) { return { pass: false, message: 'Expected a promise to be rejected with ' + expected.printValue + ' but it was ' + message + '.' }; } function getExpectedFromArgs(arg1, arg2, matchersUtil) { var error, message; if (isErrorConstructor(arg1)) { error = arg1; message = arg2; } else { error = Error; message = arg1; } return { error: error, message: message, printValue: j$.fnNameFor(error) + (typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message)) }; } function isErrorConstructor(value) { return ( typeof value === 'function' && (value === Error || j$.isError_(value.prototype)) ); } }; jasmine-4.0.0/src/core/matchers/async/toBeResolved.js000066400000000000000000000016701416413636100225470ustar00rootroot00000000000000getJasmineRequireObj().toBeResolved = function(j$) { /** * Expect a promise to be resolved. * @function * @async * @name async-matchers#toBeResolved * @since 3.1.0 * @example * await expectAsync(aPromise).toBeResolved(); * @example * return expectAsync(aPromise).toBeResolved(); */ return function toBeResolved(matchersUtil) { return { compare: function(actual) { if (!j$.isPromiseLike(actual)) { throw new Error('Expected toBeResolved to be called on a promise.'); } return actual.then( function() { return { pass: true }; }, function(e) { return { pass: false, message: 'Expected a promise to be resolved but it was ' + 'rejected with ' + matchersUtil.pp(e) + '.' }; } ); } }; }; }; jasmine-4.0.0/src/core/matchers/async/toBeResolvedTo.js000066400000000000000000000034321416413636100230500ustar00rootroot00000000000000getJasmineRequireObj().toBeResolvedTo = function(j$) { /** * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison. * @function * @async * @name async-matchers#toBeResolvedTo * @since 3.1.0 * @param {Object} expected - Value that the promise is expected to resolve to * @example * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); * @example * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); */ return function toBeResolvedTo(matchersUtil) { return { compare: function(actualPromise, expectedValue) { if (!j$.isPromiseLike(actualPromise)) { throw new Error('Expected toBeResolvedTo to be called on a promise.'); } function prefix(passed) { return ( 'Expected a promise ' + (passed ? 'not ' : '') + 'to be resolved to ' + matchersUtil.pp(expectedValue) ); } return actualPromise.then( function(actualValue) { if (matchersUtil.equals(actualValue, expectedValue)) { return { pass: true, message: prefix(true) + '.' }; } else { return { pass: false, message: prefix(false) + ' but it was resolved to ' + matchersUtil.pp(actualValue) + '.' }; } }, function(e) { return { pass: false, message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(e) + '.' }; } ); } }; }; }; jasmine-4.0.0/src/core/matchers/matchersUtil.js000066400000000000000000000454021416413636100215020ustar00rootroot00000000000000getJasmineRequireObj().MatchersUtil = function(j$) { /** * @class MatchersUtil * @classdesc Utilities for use in implementing matchers.
* _Note:_ Do not construct this directly. Jasmine will construct one and * pass it to matchers and asymmetric equality testers. * @hideconstructor */ function MatchersUtil(options) { options = options || {}; this.customTesters_ = options.customTesters || []; /** * Formats a value for use in matcher failure messages and similar contexts, * taking into account the current set of custom value formatters. * @function * @name MatchersUtil#pp * @since 3.6.0 * @param {*} value The value to pretty-print * @return {string} The pretty-printed value */ this.pp = options.pp || function() {}; } /** * Determines whether `haystack` contains `needle`, using the same comparison * logic as {@link MatchersUtil#equals}. * @function * @name MatchersUtil#contains * @since 2.0.0 * @param {*} haystack The collection to search * @param {*} needle The value to search for * @returns {boolean} True if `needle` was found in `haystack` */ MatchersUtil.prototype.contains = function(haystack, needle) { if (!haystack) { return false; } if (j$.isSet(haystack)) { // Try .has() first. It should be faster in cases where // needle === something in haystack. Fall back to .equals() comparison // if that fails. if (haystack.has(needle)) { return true; } } if (j$.isIterable_(haystack) && !j$.isString_(haystack)) { // Arrays, Sets, etc. for (const candidate of haystack) { if (this.equals(candidate, needle)) { return true; } } return false; } if (haystack.indexOf) { // Mainly strings return haystack.indexOf(needle) >= 0; } if (j$.isNumber_(haystack.length)) { // Objects that are shaped like arrays but aren't iterable for (var i = 0; i < haystack.length; i++) { if (this.equals(haystack[i], needle)) { return true; } } } return false; }; MatchersUtil.prototype.buildFailureMessage = function() { var self = this; var args = Array.prototype.slice.call(arguments, 0), matcherName = args[0], isNot = args[1], actual = args[2], expected = args.slice(3), englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); var message = 'Expected ' + self.pp(actual) + (isNot ? ' not ' : ' ') + englishyPredicate; if (expected.length > 0) { for (var i = 0; i < expected.length; i++) { if (i > 0) { message += ','; } message += ' ' + self.pp(expected[i]); } } return message + '.'; }; MatchersUtil.prototype.asymmetricDiff_ = function( a, b, aStack, bStack, diffBuilder ) { if (j$.isFunction_(b.valuesForDiff_)) { var values = b.valuesForDiff_(a, this.pp); this.eq_(values.other, values.self, aStack, bStack, diffBuilder); } else { diffBuilder.recordMismatch(); } }; MatchersUtil.prototype.asymmetricMatch_ = function( a, b, aStack, bStack, diffBuilder ) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), asymmetricB = j$.isAsymmetricEqualityTester_(b), result; if (asymmetricA === asymmetricB) { return undefined; } if (asymmetricA) { result = a.asymmetricMatch(b, this); if (!result) { diffBuilder.recordMismatch(); } return result; } if (asymmetricB) { result = b.asymmetricMatch(a, this); if (!result) { this.asymmetricDiff_(a, b, aStack, bStack, diffBuilder); } return result; } }; /** * Determines whether two values are deeply equal to each other. * @function * @name MatchersUtil#equals * @since 2.0.0 * @param {*} a The first value to compare * @param {*} b The second value to compare * @returns {boolean} True if the values are equal */ MatchersUtil.prototype.equals = function(a, b, diffBuilder) { diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder.setRoots(a, b); return this.eq_(a, b, [], [], diffBuilder); }; // Equality function lovingly adapted from isEqual in // [Underscore](http://underscorejs.org) MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, diffBuilder) { var result = true, self = this, i; var asymmetricResult = this.asymmetricMatch_( a, b, aStack, bStack, diffBuilder ); if (!j$.util.isUndefined(asymmetricResult)) { return asymmetricResult; } for (i = 0; i < this.customTesters_.length; i++) { var customTesterResult = this.customTesters_[i](a, b); if (!j$.util.isUndefined(customTesterResult)) { if (!customTesterResult) { diffBuilder.recordMismatch(); } return customTesterResult; } } if (a instanceof Error && b instanceof Error) { result = a.message == b.message; if (!result) { diffBuilder.recordMismatch(); } return result; } // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) { result = a !== 0 || 1 / a == 1 / b; if (!result) { diffBuilder.recordMismatch(); } return result; } // A strict comparison is necessary because `null == undefined`. if (a === null || b === null) { result = a === b; if (!result) { diffBuilder.recordMismatch(); } return result; } var className = Object.prototype.toString.call(a); if (className != Object.prototype.toString.call(b)) { diffBuilder.recordMismatch(); return false; } switch (className) { // Strings, numbers, dates, and booleans are compared by value. case '[object String]': // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. result = a == String(b); if (!result) { diffBuilder.recordMismatch(); } return result; case '[object Number]': // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for // other numeric values. result = a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b; if (!result) { diffBuilder.recordMismatch(); } return result; case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. result = +a == +b; if (!result) { diffBuilder.recordMismatch(); } return result; case '[object ArrayBuffer]': // If we have an instance of ArrayBuffer the Uint8Array ctor // will be defined as well return self.eq_( new Uint8Array(a), new Uint8Array(b), aStack, bStack, diffBuilder ); // RegExps are compared by their source patterns and flags. case '[object RegExp]': return ( a.source == b.source && a.global == b.global && a.multiline == b.multiline && a.ignoreCase == b.ignoreCase ); } if (typeof a != 'object' || typeof b != 'object') { diffBuilder.recordMismatch(); return false; } var aIsDomNode = j$.isDomNode(a); var bIsDomNode = j$.isDomNode(b); if (aIsDomNode && bIsDomNode) { // At first try to use DOM3 method isEqualNode result = a.isEqualNode(b); if (!result) { diffBuilder.recordMismatch(); } return result; } if (aIsDomNode || bIsDomNode) { diffBuilder.recordMismatch(); return false; } var aIsPromise = j$.isPromise(a); var bIsPromise = j$.isPromise(b); if (aIsPromise && bIsPromise) { return a === b; } // Assume equality for cyclic structures. The algorithm for detecting cyclic // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. var length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of // unique nested structures. if (aStack[length] == a) { return bStack[length] == b; } } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); var size = 0; // Recursively compare objects and arrays. // Compare array lengths to determine if a deep comparison is necessary. if (className == '[object Array]') { var aLength = a.length; var bLength = b.length; diffBuilder.withPath('length', function() { if (aLength !== bLength) { diffBuilder.recordMismatch(); result = false; } }); for (i = 0; i < aLength || i < bLength; i++) { diffBuilder.withPath(i, function() { if (i >= bLength) { diffBuilder.recordMismatch( actualArrayIsLongerFormatter.bind(null, self.pp) ); result = false; } else { result = self.eq_( i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, diffBuilder ) && result; } }); } if (!result) { return false; } } else if (j$.isMap(a) && j$.isMap(b)) { if (a.size != b.size) { diffBuilder.recordMismatch(); return false; } var keysA = []; var keysB = []; a.forEach(function(valueA, keyA) { keysA.push(keyA); }); b.forEach(function(valueB, keyB) { keysB.push(keyB); }); // For both sets of keys, check they map to equal values in both maps. // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys. var mapKeys = [keysA, keysB]; var cmpKeys = [keysB, keysA]; var mapIter, mapKey, mapValueA, mapValueB; var cmpIter, cmpKey; for (i = 0; result && i < mapKeys.length; i++) { mapIter = mapKeys[i]; cmpIter = cmpKeys[i]; for (var j = 0; result && j < mapIter.length; j++) { mapKey = mapIter[j]; cmpKey = cmpIter[j]; mapValueA = a.get(mapKey); // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches, // otherwise explicitly look up the mapKey in the other Map since we want keys with unique // obj identity (that are otherwise equal) to not match. if ( j$.isAsymmetricEqualityTester_(mapKey) || (j$.isAsymmetricEqualityTester_(cmpKey) && this.eq_(mapKey, cmpKey, aStack, bStack, j$.NullDiffBuilder())) ) { mapValueB = b.get(cmpKey); } else { mapValueB = b.get(mapKey); } result = this.eq_( mapValueA, mapValueB, aStack, bStack, j$.NullDiffBuilder() ); } } if (!result) { diffBuilder.recordMismatch(); return false; } } else if (j$.isSet(a) && j$.isSet(b)) { if (a.size != b.size) { diffBuilder.recordMismatch(); return false; } var valuesA = []; a.forEach(function(valueA) { valuesA.push(valueA); }); var valuesB = []; b.forEach(function(valueB) { valuesB.push(valueB); }); // For both sets, check they are all contained in the other set var setPairs = [[valuesA, valuesB], [valuesB, valuesA]]; var stackPairs = [[aStack, bStack], [bStack, aStack]]; var baseValues, baseValue, baseStack; var otherValues, otherValue, otherStack; var found; var prevStackSize; for (i = 0; result && i < setPairs.length; i++) { baseValues = setPairs[i][0]; otherValues = setPairs[i][1]; baseStack = stackPairs[i][0]; otherStack = stackPairs[i][1]; // For each value in the base set... for (var k = 0; result && k < baseValues.length; k++) { baseValue = baseValues[k]; found = false; // ... test that it is present in the other set for (var l = 0; !found && l < otherValues.length; l++) { otherValue = otherValues[l]; prevStackSize = baseStack.length; // compare by value equality found = this.eq_( baseValue, otherValue, baseStack, otherStack, j$.NullDiffBuilder() ); if (!found && prevStackSize !== baseStack.length) { baseStack.splice(prevStackSize); otherStack.splice(prevStackSize); } } result = result && found; } } if (!result) { diffBuilder.recordMismatch(); return false; } } else if (j$.isURL(a) && j$.isURL(b)) { // URLs have no enumrable properties, so the default object comparison // would consider any two URLs to be equal. return a.toString() === b.toString(); } else { // Objects with different constructors are not equivalent, but `Object`s // or `Array`s from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if ( aCtor !== bCtor && isFunction(aCtor) && isFunction(bCtor) && a instanceof aCtor && b instanceof bCtor && !(aCtor instanceof aCtor && bCtor instanceof bCtor) ) { diffBuilder.recordMismatch( constructorsAreDifferentFormatter.bind(null, this.pp) ); return false; } } // Deep compare objects. var aKeys = keys(a, className == '[object Array]'), key; size = aKeys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. if (keys(b, className == '[object Array]').length !== size) { diffBuilder.recordMismatch( objectKeysAreDifferentFormatter.bind(null, this.pp) ); return false; } for (i = 0; i < size; i++) { key = aKeys[i]; // Deep compare each member if (!j$.util.has(b, key)) { diffBuilder.recordMismatch( objectKeysAreDifferentFormatter.bind(null, this.pp) ); result = false; continue; } diffBuilder.withPath(key, function() { if (!self.eq_(a[key], b[key], aStack, bStack, diffBuilder)) { result = false; } }); } if (!result) { return false; } // Remove the first object from the stack of traversed objects. aStack.pop(); bStack.pop(); return result; }; function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { if (j$.util.has(o, key)) { keys.push(key); } } return keys; })(obj); if (!isArray) { return allKeys; } if (allKeys.length === 0) { return allKeys; } var extraKeys = []; for (var i = 0; i < allKeys.length; i++) { if (!/^[0-9]+$/.test(allKeys[i])) { extraKeys.push(allKeys[i]); } } return extraKeys; } function isFunction(obj) { return typeof obj === 'function'; } function objectKeysAreDifferentFormatter(pp, actual, expected, path) { var missingProperties = j$.util.objectDifference(expected, actual), extraProperties = j$.util.objectDifference(actual, expected), missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), messages = []; if (!path.depth()) { path = 'object'; } if (missingPropertiesMessage.length) { messages.push( 'Expected ' + path + ' to have properties' + missingPropertiesMessage ); } if (extraPropertiesMessage.length) { messages.push( 'Expected ' + path + ' not to have properties' + extraPropertiesMessage ); } return messages.join('\n'); } function constructorsAreDifferentFormatter(pp, actual, expected, path) { if (!path.depth()) { path = 'object'; } return ( 'Expected ' + path + ' to be a kind of ' + j$.fnNameFor(expected.constructor) + ', but was ' + pp(actual) + '.' ); } function actualArrayIsLongerFormatter(pp, actual, expected, path) { return ( 'Unexpected ' + path + (path.depth() ? ' = ' : '') + pp(actual) + ' in array.' ); } function formatKeyValuePairs(pp, obj) { var formatted = ''; for (var key in obj) { formatted += '\n ' + key + ': ' + pp(obj[key]); } return formatted; } return MatchersUtil; }; /** * @interface AsymmetricEqualityTester * @classdesc An asymmetric equality tester is an object that can match multiple * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine * includes a number of built-in asymmetric equality testers, such as * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are * also supported. * * Asymmetric equality testers work with any matcher, including user-defined * custom matchers, that uses {@link MatchersUtil#equals} or * {@link MatchersUtil#contains}. * * @example * function numberDivisibleBy(divisor) { * return { * asymmetricMatch: function(n) { * return typeof n === 'number' && n % divisor === 0; * }, * jasmineToString: function() { * return ``; * } * }; * } * * var actual = { * n: 2, * otherFields: "don't care" * }; * * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)})); * @see custom_asymmetric_equality_testers * @since 2.0.0 */ /** * Determines whether a value matches this tester * @function * @name AsymmetricEqualityTester#asymmetricMatch * @param value {any} The value to test * @param matchersUtil {MatchersUtil} utilities for testing equality, etc * @return {Boolean} */ /** * Returns a string representation of this tester to use in matcher failure messages * @function * @name AsymmetricEqualityTester#jasmineToString * @param pp {function} Function that takes a value and returns a pretty-printed representation * @return {String} */ jasmine-4.0.0/src/core/matchers/nothing.js000066400000000000000000000005401416413636100204760ustar00rootroot00000000000000getJasmineRequireObj().nothing = function() { /** * {@link expect} nothing explicitly. * @function * @name matchers#nothing * @since 2.8.0 * @example * expect().nothing(); */ function nothing() { return { compare: function() { return { pass: true }; } }; } return nothing; }; jasmine-4.0.0/src/core/matchers/requireAsyncMatchers.js000066400000000000000000000006571416413636100232020ustar00rootroot00000000000000getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) { var availableMatchers = [ 'toBePending', 'toBeResolved', 'toBeRejected', 'toBeResolvedTo', 'toBeRejectedWith', 'toBeRejectedWithError' ], matchers = {}; for (var i = 0; i < availableMatchers.length; i++) { var name = availableMatchers[i]; matchers[name] = jRequire[name](j$); } return matchers; }; jasmine-4.0.0/src/core/matchers/requireMatchers.js000066400000000000000000000017361416413636100222030ustar00rootroot00000000000000getJasmineRequireObj().requireMatchers = function(jRequire, j$) { var availableMatchers = [ 'nothing', 'toBe', 'toBeCloseTo', 'toBeDefined', 'toBeInstanceOf', 'toBeFalse', 'toBeFalsy', 'toBeGreaterThan', 'toBeGreaterThanOrEqual', 'toBeLessThan', 'toBeLessThanOrEqual', 'toBeNaN', 'toBeNegativeInfinity', 'toBeNull', 'toBePositiveInfinity', 'toBeTrue', 'toBeTruthy', 'toBeUndefined', 'toContain', 'toEqual', 'toHaveSize', 'toHaveBeenCalled', 'toHaveBeenCalledBefore', 'toHaveBeenCalledOnceWith', 'toHaveBeenCalledTimes', 'toHaveBeenCalledWith', 'toHaveClass', 'toMatch', 'toThrow', 'toThrowError', 'toThrowMatching' ], matchers = {}; for (var i = 0; i < availableMatchers.length; i++) { var name = availableMatchers[i]; matchers[name] = jRequire[name](j$); } return matchers; }; jasmine-4.0.0/src/core/matchers/toBe.js000066400000000000000000000015411416413636100177230ustar00rootroot00000000000000getJasmineRequireObj().toBe = function(j$) { /** * {@link expect} the actual value to be `===` to the expected value. * @function * @name matchers#toBe * @since 1.3.0 * @param {Object} expected - The expected value to compare against. * @example * expect(thing).toBe(realThing); */ function toBe(matchersUtil) { var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().'; return { compare: function(actual, expected) { var result = { pass: actual === expected }; if (typeof expected === 'object') { result.message = matchersUtil.buildFailureMessage( 'toBe', result.pass, actual, expected ) + tip; } return result; } }; } return toBe; }; jasmine-4.0.0/src/core/matchers/toBeCloseTo.js000066400000000000000000000022411416413636100212120ustar00rootroot00000000000000getJasmineRequireObj().toBeCloseTo = function() { /** * {@link expect} the actual value to be within a specified precision of the expected value. * @function * @name matchers#toBeCloseTo * @since 1.3.0 * @param {Object} expected - The expected value to compare against. * @param {Number} [precision=2] - The number of decimal points to check. * @example * expect(number).toBeCloseTo(42.2, 3); */ function toBeCloseTo() { return { compare: function(actual, expected, precision) { if (precision !== 0) { precision = precision || 2; } if (expected === null || actual === null) { throw new Error( 'Cannot use toBeCloseTo with null. Arguments evaluated to: ' + 'expect(' + actual + ').toBeCloseTo(' + expected + ').' ); } var pow = Math.pow(10, precision + 1); var delta = Math.abs(expected - actual); var maxDelta = Math.pow(10, -precision) / 2; return { pass: Math.round(delta * pow) <= maxDelta * pow }; } }; } return toBeCloseTo; }; jasmine-4.0.0/src/core/matchers/toBeDefined.js000066400000000000000000000006531416413636100212050ustar00rootroot00000000000000getJasmineRequireObj().toBeDefined = function() { /** * {@link expect} the actual value to be defined. (Not `undefined`) * @function * @name matchers#toBeDefined * @since 1.3.0 * @example * expect(result).toBeDefined(); */ function toBeDefined() { return { compare: function(actual) { return { pass: void 0 !== actual }; } }; } return toBeDefined; }; jasmine-4.0.0/src/core/matchers/toBeFalse.js000066400000000000000000000006161416413636100207000ustar00rootroot00000000000000getJasmineRequireObj().toBeFalse = function() { /** * {@link expect} the actual value to be `false`. * @function * @name matchers#toBeFalse * @since 3.5.0 * @example * expect(result).toBeFalse(); */ function toBeFalse() { return { compare: function(actual) { return { pass: actual === false }; } }; } return toBeFalse; }; jasmine-4.0.0/src/core/matchers/toBeFalsy.js000066400000000000000000000006021416413636100207170ustar00rootroot00000000000000getJasmineRequireObj().toBeFalsy = function() { /** * {@link expect} the actual value to be falsy * @function * @name matchers#toBeFalsy * @since 2.0.0 * @example * expect(result).toBeFalsy(); */ function toBeFalsy() { return { compare: function(actual) { return { pass: !actual }; } }; } return toBeFalsy; }; jasmine-4.0.0/src/core/matchers/toBeGreaterThan.js000066400000000000000000000010161416413636100220450ustar00rootroot00000000000000getJasmineRequireObj().toBeGreaterThan = function() { /** * {@link expect} the actual value to be greater than the expected value. * @function * @name matchers#toBeGreaterThan * @since 2.0.0 * @param {Number} expected - The value to compare against. * @example * expect(result).toBeGreaterThan(3); */ function toBeGreaterThan() { return { compare: function(actual, expected) { return { pass: actual > expected }; } }; } return toBeGreaterThan; }; jasmine-4.0.0/src/core/matchers/toBeGreaterThanOrEqual.js000066400000000000000000000011101416413636100233310ustar00rootroot00000000000000getJasmineRequireObj().toBeGreaterThanOrEqual = function() { /** * {@link expect} the actual value to be greater than or equal to the expected value. * @function * @name matchers#toBeGreaterThanOrEqual * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeGreaterThanOrEqual(25); */ function toBeGreaterThanOrEqual() { return { compare: function(actual, expected) { return { pass: actual >= expected }; } }; } return toBeGreaterThanOrEqual; }; jasmine-4.0.0/src/core/matchers/toBeInstanceOf.js000066400000000000000000000033401416413636100216740ustar00rootroot00000000000000getJasmineRequireObj().toBeInstanceOf = function(j$) { var usageError = j$.formatErrorMsg( '', 'expect(value).toBeInstanceOf()' ); /** * {@link expect} the actual to be an instance of the expected class * @function * @name matchers#toBeInstanceOf * @since 3.5.0 * @param {Object} expected - The class or constructor function to check for * @example * expect('foo').toBeInstanceOf(String); * expect(3).toBeInstanceOf(Number); * expect(new Error()).toBeInstanceOf(Error); */ function toBeInstanceOf(matchersUtil) { return { compare: function(actual, expected) { var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : matchersUtil.pp(actual), expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), expectedMatcher, pass; try { expectedMatcher = new j$.Any(expected); pass = expectedMatcher.asymmetricMatch(actual); } catch (error) { throw new Error( usageError('Expected value is not a constructor function') ); } if (pass) { return { pass: true, message: 'Expected instance of ' + actualType + ' not to be an instance of ' + expectedType }; } else { return { pass: false, message: 'Expected instance of ' + actualType + ' to be an instance of ' + expectedType }; } } }; } return toBeInstanceOf; }; jasmine-4.0.0/src/core/matchers/toBeLessThan.js000066400000000000000000000010051416413636100213600ustar00rootroot00000000000000getJasmineRequireObj().toBeLessThan = function() { /** * {@link expect} the actual value to be less than the expected value. * @function * @name matchers#toBeLessThan * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeLessThan(0); */ function toBeLessThan() { return { compare: function(actual, expected) { return { pass: actual < expected }; } }; } return toBeLessThan; }; jasmine-4.0.0/src/core/matchers/toBeLessThanOrEqual.js000066400000000000000000000010671416413636100226610ustar00rootroot00000000000000getJasmineRequireObj().toBeLessThanOrEqual = function() { /** * {@link expect} the actual value to be less than or equal to the expected value. * @function * @name matchers#toBeLessThanOrEqual * @since 2.0.0 * @param {Number} expected - The expected value to compare against. * @example * expect(result).toBeLessThanOrEqual(123); */ function toBeLessThanOrEqual() { return { compare: function(actual, expected) { return { pass: actual <= expected }; } }; } return toBeLessThanOrEqual; }; jasmine-4.0.0/src/core/matchers/toBeNaN.js000066400000000000000000000012601416413636100203160ustar00rootroot00000000000000getJasmineRequireObj().toBeNaN = function(j$) { /** * {@link expect} the actual value to be `NaN` (Not a Number). * @function * @name matchers#toBeNaN * @since 1.3.0 * @example * expect(thing).toBeNaN(); */ function toBeNaN(matchersUtil) { return { compare: function(actual) { var result = { pass: actual !== actual }; if (result.pass) { result.message = 'Expected actual not to be NaN.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.'; }; } return result; } }; } return toBeNaN; }; jasmine-4.0.0/src/core/matchers/toBeNegativeInfinity.js000066400000000000000000000014221416413636100231160ustar00rootroot00000000000000getJasmineRequireObj().toBeNegativeInfinity = function(j$) { /** * {@link expect} the actual value to be `-Infinity` (-infinity). * @function * @name matchers#toBeNegativeInfinity * @since 2.6.0 * @example * expect(thing).toBeNegativeInfinity(); */ function toBeNegativeInfinity(matchersUtil) { return { compare: function(actual) { var result = { pass: actual === Number.NEGATIVE_INFINITY }; if (result.pass) { result.message = 'Expected actual not to be -Infinity.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.'; }; } return result; } }; } return toBeNegativeInfinity; }; jasmine-4.0.0/src/core/matchers/toBeNull.js000066400000000000000000000006071416413636100205600ustar00rootroot00000000000000getJasmineRequireObj().toBeNull = function() { /** * {@link expect} the actual value to be `null`. * @function * @name matchers#toBeNull * @since 1.3.0 * @example * expect(result).toBeNull(); */ function toBeNull() { return { compare: function(actual) { return { pass: actual === null }; } }; } return toBeNull; }; jasmine-4.0.0/src/core/matchers/toBePositiveInfinity.js000066400000000000000000000014161416413636100231610ustar00rootroot00000000000000getJasmineRequireObj().toBePositiveInfinity = function(j$) { /** * {@link expect} the actual value to be `Infinity` (infinity). * @function * @name matchers#toBePositiveInfinity * @since 2.6.0 * @example * expect(thing).toBePositiveInfinity(); */ function toBePositiveInfinity(matchersUtil) { return { compare: function(actual) { var result = { pass: actual === Number.POSITIVE_INFINITY }; if (result.pass) { result.message = 'Expected actual not to be Infinity.'; } else { result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.'; }; } return result; } }; } return toBePositiveInfinity; }; jasmine-4.0.0/src/core/matchers/toBeTrue.js000066400000000000000000000006071416413636100205650ustar00rootroot00000000000000getJasmineRequireObj().toBeTrue = function() { /** * {@link expect} the actual value to be `true`. * @function * @name matchers#toBeTrue * @since 3.5.0 * @example * expect(result).toBeTrue(); */ function toBeTrue() { return { compare: function(actual) { return { pass: actual === true }; } }; } return toBeTrue; }; jasmine-4.0.0/src/core/matchers/toBeTruthy.js000066400000000000000000000006111416413636100211400ustar00rootroot00000000000000getJasmineRequireObj().toBeTruthy = function() { /** * {@link expect} the actual value to be truthy. * @function * @name matchers#toBeTruthy * @since 2.0.0 * @example * expect(thing).toBeTruthy(); */ function toBeTruthy() { return { compare: function(actual) { return { pass: !!actual }; } }; } return toBeTruthy; }; jasmine-4.0.0/src/core/matchers/toBeUndefined.js000066400000000000000000000006471416413636100215530ustar00rootroot00000000000000getJasmineRequireObj().toBeUndefined = function() { /** * {@link expect} the actual value to be `undefined`. * @function * @name matchers#toBeUndefined * @since 1.3.0 * @example * expect(result).toBeUndefined(): */ function toBeUndefined() { return { compare: function(actual) { return { pass: void 0 === actual }; } }; } return toBeUndefined; }; jasmine-4.0.0/src/core/matchers/toContain.js000066400000000000000000000010621416413636100207660ustar00rootroot00000000000000getJasmineRequireObj().toContain = function() { /** * {@link expect} the actual value to contain a specific value. * @function * @name matchers#toContain * @since 2.0.0 * @param {Object} expected - The value to look for. * @example * expect(array).toContain(anElement); * expect(string).toContain(substring); */ function toContain(matchersUtil) { return { compare: function(actual, expected) { return { pass: matchersUtil.contains(actual, expected) }; } }; } return toContain; }; jasmine-4.0.0/src/core/matchers/toEqual.js000066400000000000000000000014531416413636100204460ustar00rootroot00000000000000getJasmineRequireObj().toEqual = function(j$) { /** * {@link expect} the actual value to be equal to the expected, using deep equality comparison. * @function * @name matchers#toEqual * @since 1.3.0 * @param {Object} expected - Expected value * @example * expect(bigObject).toEqual({"foo": ['bar', 'baz']}); */ function toEqual(matchersUtil) { return { compare: function(actual, expected) { var result = { pass: false }, diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp }); result.pass = matchersUtil.equals(actual, expected, diffBuilder); // TODO: only set error message if test fails result.message = diffBuilder.getMessage(); return result; } }; } return toEqual; }; jasmine-4.0.0/src/core/matchers/toHaveBeenCalled.js000066400000000000000000000022641416413636100221620ustar00rootroot00000000000000getJasmineRequireObj().toHaveBeenCalled = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalled()' ); /** * {@link expect} the actual (a {@link Spy}) to have been called. * @function * @name matchers#toHaveBeenCalled * @since 1.3.0 * @example * expect(mySpy).toHaveBeenCalled(); * expect(mySpy).not.toHaveBeenCalled(); */ function toHaveBeenCalled(matchersUtil) { return { compare: function(actual) { var result = {}; if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } if (arguments.length > 1) { throw new Error( getErrorMsg('Does not take arguments, use toHaveBeenCalledWith') ); } result.pass = actual.calls.any(); result.message = result.pass ? 'Expected spy ' + actual.and.identity + ' not to have been called.' : 'Expected spy ' + actual.and.identity + ' to have been called.'; return result; } }; } return toHaveBeenCalled; }; jasmine-4.0.0/src/core/matchers/toHaveBeenCalledBefore.js000066400000000000000000000057121416413636100233060ustar00rootroot00000000000000getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledBefore()' ); /** * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}. * @function * @name matchers#toHaveBeenCalledBefore * @since 2.6.0 * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}. * @example * expect(mySpy).toHaveBeenCalledBefore(otherSpy); */ function toHaveBeenCalledBefore(matchersUtil) { return { compare: function(firstSpy, latterSpy) { if (!j$.isSpy(firstSpy)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.' ) ); } if (!j$.isSpy(latterSpy)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.' ) ); } var result = { pass: false }; if (!firstSpy.calls.count()) { result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.'; return result; } if (!latterSpy.calls.count()) { result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.'; return result; } var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder; var first2ndSpyCall = latterSpy.calls.first().invocationOrder; result.pass = latest1stSpyCall < first2ndSpyCall; if (result.pass) { result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was'; } else { var first1stSpyCall = firstSpy.calls.first().invocationOrder; var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder; if (first1stSpyCall < first2ndSpyCall) { result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)'; } else if (latest2ndSpyCall > latest1stSpyCall) { result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)'; } else { result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity; } } return result; } }; } return toHaveBeenCalledBefore; }; jasmine-4.0.0/src/core/matchers/toHaveBeenCalledOnceWith.js000066400000000000000000000055601416413636100236250ustar00rootroot00000000000000getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledOnceWith(...arguments)' ); /** * {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments. * @function * @name matchers#toHaveBeenCalledOnceWith * @since 3.6.0 * @param {...Object} - The arguments to look for * @example * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2); */ function toHaveBeenCalledOnceWith(util) { return { compare: function() { var args = Array.prototype.slice.call(arguments, 0), actual = args[0], expectedArgs = args.slice(1); if (!j$.isSpy(actual)) { throw new Error( getErrorMsg('Expected a spy, but got ' + util.pp(actual) + '.') ); } var prettyPrintedCalls = actual.calls .allArgs() .map(function(argsForCall) { return ' ' + util.pp(argsForCall); }); if ( actual.calls.count() === 1 && util.contains(actual.calls.allArgs(), expectedArgs) ) { return { pass: true, message: 'Expected spy ' + actual.and.identity + ' to have been called 0 times, multiple times, or once, but with arguments different from:\n' + ' ' + util.pp(expectedArgs) + '\n' + 'But the actual call was:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' }; } function getDiffs() { return actual.calls.allArgs().map(function(argsForCall, callIx) { var diffBuilder = new j$.DiffBuilder(); util.equals(argsForCall, expectedArgs, diffBuilder); return diffBuilder.getMessage(); }); } function butString() { switch (actual.calls.count()) { case 0: return 'But it was never called.\n\n'; case 1: return ( 'But the actual call was:\n' + prettyPrintedCalls.join(',\n') + '.\n' + getDiffs().join('\n') + '\n\n' ); default: return ( 'But the actual calls were:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' ); } } return { pass: false, message: 'Expected spy ' + actual.and.identity + ' to have been called only once, and with given args:\n' + ' ' + util.pp(expectedArgs) + '\n' + butString() }; } }; } return toHaveBeenCalledOnceWith; }; jasmine-4.0.0/src/core/matchers/toHaveBeenCalledTimes.js000066400000000000000000000034541416413636100231660ustar00rootroot00000000000000getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledTimes()' ); /** * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times. * @function * @name matchers#toHaveBeenCalledTimes * @since 2.4.0 * @param {Number} expected - The number of invocations to look for. * @example * expect(mySpy).toHaveBeenCalledTimes(3); */ function toHaveBeenCalledTimes(matchersUtil) { return { compare: function(actual, expected) { if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } var args = Array.prototype.slice.call(arguments, 0), result = { pass: false }; if (!j$.isNumber_(expected)) { throw new Error( getErrorMsg( 'The expected times failed is a required argument and must be a number.' ) ); } actual = args[0]; var calls = actual.calls.count(); var timesMessage = expected === 1 ? 'once' : expected + ' times'; result.pass = calls === expected; result.message = result.pass ? 'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' : 'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.'; return result; } }; } return toHaveBeenCalledTimes; }; jasmine-4.0.0/src/core/matchers/toHaveBeenCalledWith.js000066400000000000000000000056321416413636100230200ustar00rootroot00000000000000getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toHaveBeenCalledWith(...arguments)' ); /** * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once. * @function * @name matchers#toHaveBeenCalledWith * @since 1.3.0 * @param {...Object} - The arguments to look for * @example * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2); */ function toHaveBeenCalledWith(matchersUtil) { return { compare: function() { var args = Array.prototype.slice.call(arguments, 0), actual = args[0], expectedArgs = args.slice(1), result = { pass: false }; if (!j$.isSpy(actual)) { throw new Error( getErrorMsg( 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.' ) ); } if (!actual.calls.any()) { result.message = function() { return ( 'Expected spy ' + actual.and.identity + ' to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\nbut it was never called.' ); }; return result; } if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) { result.pass = true; result.message = function() { return ( 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\nbut it was.' ); }; } else { result.message = function() { var prettyPrintedCalls = actual.calls .allArgs() .map(function(argsForCall) { return ' ' + matchersUtil.pp(argsForCall); }); var diffs = actual.calls .allArgs() .map(function(argsForCall, callIx) { var diffBuilder = new j$.DiffBuilder(); matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); return ( 'Call ' + callIx + ':\n' + diffBuilder.getMessage().replace(/^/gm, ' ') ); }); return ( 'Expected spy ' + actual.and.identity + ' to have been called with:\n' + ' ' + matchersUtil.pp(expectedArgs) + '\n' + '' + 'but actual calls were:\n' + prettyPrintedCalls.join(',\n') + '.\n\n' + diffs.join('\n') ); }; } return result; } }; } return toHaveBeenCalledWith; }; jasmine-4.0.0/src/core/matchers/toHaveClass.js000066400000000000000000000015651416413636100212540ustar00rootroot00000000000000getJasmineRequireObj().toHaveClass = function(j$) { /** * {@link expect} the actual value to be a DOM element that has the expected class * @function * @name matchers#toHaveClass * @since 3.0.0 * @param {Object} expected - The class name to test for * @example * var el = document.createElement('div'); * el.className = 'foo bar baz'; * expect(el).toHaveClass('bar'); */ function toHaveClass(matchersUtil) { return { compare: function(actual, expected) { if (!isElement(actual)) { throw new Error(matchersUtil.pp(actual) + ' is not a DOM element'); } return { pass: actual.classList.contains(expected) }; } }; } function isElement(maybeEl) { return ( maybeEl && maybeEl.classList && j$.isFunction_(maybeEl.classList.contains) ); } return toHaveClass; }; jasmine-4.0.0/src/core/matchers/toHaveSize.js000066400000000000000000000024151416413636100211140ustar00rootroot00000000000000getJasmineRequireObj().toHaveSize = function(j$) { /** * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size. * @function * @name matchers#toHaveSize * @since 3.6.0 * @param {Object} expected - Expected size * @example * array = [1,2]; * expect(array).toHaveSize(2); */ function toHaveSize() { return { compare: function(actual, expected) { var result = { pass: false }; if ( j$.isA_('WeakSet', actual) || j$.isWeakMap(actual) || j$.isDataView(actual) ) { throw new Error('Cannot get size of ' + actual + '.'); } if (j$.isSet(actual) || j$.isMap(actual)) { result.pass = actual.size === expected; } else if (isLength(actual.length)) { result.pass = actual.length === expected; } else { result.pass = Object.keys(actual).length === expected; } return result; } }; } var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; function isLength(value) { return ( typeof value == 'number' && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER ); } return toHaveSize; }; jasmine-4.0.0/src/core/matchers/toMatch.js000066400000000000000000000015521416413636100204330ustar00rootroot00000000000000getJasmineRequireObj().toMatch = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect().toMatch( || )' ); /** * {@link expect} the actual value to match a regular expression * @function * @name matchers#toMatch * @since 1.3.0 * @param {RegExp|String} expected - Value to look for in the string. * @example * expect("my string").toMatch(/string$/); * expect("other string").toMatch("her"); */ function toMatch() { return { compare: function(actual, expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { throw new Error(getErrorMsg('Expected is not a String or a RegExp')); } var regexp = new RegExp(expected); return { pass: regexp.test(actual) }; } }; } return toMatch; }; jasmine-4.0.0/src/core/matchers/toThrow.js000066400000000000000000000040041416413636100204750ustar00rootroot00000000000000getJasmineRequireObj().toThrow = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect(function() {}).toThrow()' ); /** * {@link expect} a function to `throw` something. * @function * @name matchers#toThrow * @since 2.0.0 * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked. * @example * expect(function() { return 'things'; }).toThrow('foo'); * expect(function() { return 'stuff'; }).toThrow(); */ function toThrow(matchersUtil) { return { compare: function(actual, expected) { var result = { pass: false }, threw = false, thrown; if (typeof actual != 'function') { throw new Error(getErrorMsg('Actual is not a Function')); } try { actual(); } catch (e) { threw = true; thrown = e; } if (!threw) { result.message = 'Expected function to throw an exception.'; return result; } if (arguments.length == 1) { result.pass = true; result.message = function() { return ( 'Expected function not to throw, but it threw ' + matchersUtil.pp(thrown) + '.' ); }; return result; } if (matchersUtil.equals(thrown, expected)) { result.pass = true; result.message = function() { return ( 'Expected function not to throw ' + matchersUtil.pp(expected) + '.' ); }; } else { result.message = function() { return ( 'Expected function to throw ' + matchersUtil.pp(expected) + ', but it threw ' + matchersUtil.pp(thrown) + '.' ); }; } return result; } }; } return toThrow; }; jasmine-4.0.0/src/core/matchers/toThrowError.js000066400000000000000000000125021416413636100215110ustar00rootroot00000000000000getJasmineRequireObj().toThrowError = function(j$) { var getErrorMsg = j$.formatErrorMsg( '', 'expect(function() {}).toThrowError(, )' ); /** * {@link expect} a function to `throw` an `Error`. * @function * @name matchers#toThrowError * @since 2.0.0 * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used. * @param {RegExp|String} [message] - The message that should be set on the thrown `Error` * @example * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message'); * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/); * expect(function() { return 'stuff'; }).toThrowError(MyCustomError); * expect(function() { return 'other'; }).toThrowError(/foo/); * expect(function() { return 'other'; }).toThrowError(); */ function toThrowError(matchersUtil) { return { compare: function(actual) { var errorMatcher = getMatcher.apply(null, arguments), thrown; if (typeof actual != 'function') { throw new Error(getErrorMsg('Actual is not a Function')); } try { actual(); return fail('Expected function to throw an Error.'); } catch (e) { thrown = e; } if (!j$.isError_(thrown)) { return fail(function() { return ( 'Expected function to throw an Error, but it threw ' + matchersUtil.pp(thrown) + '.' ); }); } return errorMatcher.match(thrown); } }; function getMatcher() { var expected, errorType; if (arguments[2]) { errorType = arguments[1]; expected = arguments[2]; if (!isAnErrorType(errorType)) { throw new Error(getErrorMsg('Expected error type is not an Error.')); } return exactMatcher(expected, errorType); } else if (arguments[1]) { expected = arguments[1]; if (isAnErrorType(arguments[1])) { return exactMatcher(null, arguments[1]); } else { return exactMatcher(arguments[1], null); } } else { return anyMatcher(); } } function anyMatcher() { return { match: function(error) { return pass( 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.' ); } }; } function exactMatcher(expected, errorType) { if (expected && !isStringOrRegExp(expected)) { if (errorType) { throw new Error( getErrorMsg('Expected error message is not a string or RegExp.') ); } else { throw new Error( getErrorMsg('Expected is not an Error, string, or RegExp.') ); } } function messageMatch(message) { if (typeof expected == 'string') { return expected == message; } else { return expected.test(message); } } var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception'; function thrownDescription(thrown) { var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception', thrownMessage = ''; if (expected) { thrownMessage = ' with message ' + matchersUtil.pp(thrown.message); } return thrownName + thrownMessage; } function messageDescription() { if (expected === null) { return ''; } else if (expected instanceof RegExp) { return ' with a message matching ' + matchersUtil.pp(expected); } else { return ' with message ' + matchersUtil.pp(expected); } } function matches(error) { return ( (errorType === null || error instanceof errorType) && (expected === null || messageMatch(error.message)) ); } return { match: function(thrown) { if (matches(thrown)) { return pass(function() { return ( 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.' ); }); } else { return fail(function() { return ( 'Expected function to throw ' + errorTypeDescription + messageDescription() + ', but it threw ' + thrownDescription(thrown) + '.' ); }); } } }; } function isStringOrRegExp(potential) { return potential instanceof RegExp || typeof potential == 'string'; } function isAnErrorType(type) { if (typeof type !== 'function') { return false; } var Surrogate = function() {}; Surrogate.prototype = type.prototype; return j$.isError_(new Surrogate()); } } function pass(message) { return { pass: true, message: message }; } function fail(message) { return { pass: false, message: message }; } return toThrowError; }; jasmine-4.0.0/src/core/matchers/toThrowMatching.js000066400000000000000000000041001416413636100221450ustar00rootroot00000000000000getJasmineRequireObj().toThrowMatching = function(j$) { var usageError = j$.formatErrorMsg( '', 'expect(function() {}).toThrowMatching()' ); /** * {@link expect} a function to `throw` something matching a predicate. * @function * @name matchers#toThrowMatching * @since 3.0.0 * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches. * @example * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; }); */ function toThrowMatching(matchersUtil) { return { compare: function(actual, predicate) { var thrown; if (typeof actual !== 'function') { throw new Error(usageError('Actual is not a Function')); } if (typeof predicate !== 'function') { throw new Error(usageError('Predicate is not a Function')); } try { actual(); return fail('Expected function to throw an exception.'); } catch (e) { thrown = e; } if (predicate(thrown)) { return pass( 'Expected function not to throw an exception matching a predicate.' ); } else { return fail(function() { return ( 'Expected function to throw an exception matching a predicate, ' + 'but it threw ' + thrownDescription(thrown) + '.' ); }); } } }; function thrownDescription(thrown) { if (thrown && thrown.constructor) { return ( j$.fnNameFor(thrown.constructor) + ' with message ' + matchersUtil.pp(thrown.message) ); } else { return matchersUtil.pp(thrown); } } } function pass(message) { return { pass: true, message: message }; } function fail(message) { return { pass: false, message: message }; } return toThrowMatching; }; jasmine-4.0.0/src/core/requireCore.js000066400000000000000000000070411416413636100175120ustar00rootroot00000000000000// eslint-disable-next-line no-unused-vars var getJasmineRequireObj = (function(jasmineGlobal) { var jasmineRequire; if ( typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined' ) { if (typeof global !== 'undefined') { jasmineGlobal = global; } else { jasmineGlobal = {}; } jasmineRequire = exports; } else { if ( typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]' ) { jasmineGlobal = window; } jasmineRequire = jasmineGlobal.jasmineRequire = {}; } function getJasmineRequire() { return jasmineRequire; } getJasmineRequire().core = function(jRequire) { var j$ = {}; jRequire.base(j$, jasmineGlobal); j$.util = jRequire.util(j$); j$.errors = jRequire.errors(); j$.formatErrorMsg = jRequire.formatErrorMsg(); j$.Any = jRequire.Any(j$); j$.Anything = jRequire.Anything(j$); j$.CallTracker = jRequire.CallTracker(j$); j$.MockDate = jRequire.MockDate(j$); j$.getClearStack = jRequire.clearStack(j$); j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Deprecator = jRequire.Deprecator(j$); j$.Env = jRequire.Env(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); j$.Expector = jRequire.Expector(j$); j$.Expectation = jRequire.Expectation(j$); j$.buildExpectationResult = jRequire.buildExpectationResult(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$); j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$); j$.basicPrettyPrinter_ = j$.makePrettyPrinter(); j$.MatchersUtil = jRequire.MatchersUtil(j$); j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); j$.MapContaining = jRequire.MapContaining(j$); j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( j$ ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ ); j$.ReportDispatcher = jRequire.ReportDispatcher(j$); j$.Spec = jRequire.Spec(j$); j$.Spy = jRequire.Spy(j$); j$.SpyFactory = jRequire.SpyFactory(j$); j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); j$.StringContaining = jRequire.StringContaining(j$); j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); j$.TreeProcessor = jRequire.TreeProcessor(); j$.version = jRequire.version(); j$.Order = jRequire.Order(); j$.DiffBuilder = jRequire.DiffBuilder(j$); j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$); j$.ObjectPath = jRequire.ObjectPath(j$); j$.MismatchTree = jRequire.MismatchTree(j$); j$.GlobalErrors = jRequire.GlobalErrors(j$); j$.Truthy = jRequire.Truthy(j$); j$.Falsy = jRequire.Falsy(j$); j$.Empty = jRequire.Empty(j$); j$.NotEmpty = jRequire.NotEmpty(j$); j$.matchers = jRequire.requireMatchers(jRequire, j$); j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$); return j$; }; return getJasmineRequire; })(this); jasmine-4.0.0/src/core/requireInterface.js000066400000000000000000000363701416413636100205310ustar00rootroot00000000000000getJasmineRequireObj().interface = function(jasmine, env) { var jasmineInterface = { /** * Callback passed to parts of the Jasmine base interface. * * By default Jasmine assumes this function completes synchronously. * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment. * @callback implementationCallback * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. */ /** * Create a group of specs (often called a suite). * * Calls to `describe` can be nested within other calls to compose your suite as a tree. * @name describe * @since 1.3.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ describe: function(description, specDefinitions) { return env.describe(description, specDefinitions); }, /** * A temporarily disabled [`describe`]{@link describe} * * Specs within an `xdescribe` will be marked pending and not executed * @name xdescribe * @since 1.3.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ xdescribe: function(description, specDefinitions) { return env.xdescribe(description, specDefinitions); }, /** * A focused [`describe`]{@link describe} * * If suites or specs are focused, only those that are focused will be executed * @see fit * @name fdescribe * @since 2.1.0 * @function * @global * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ fdescribe: function(description, specDefinitions) { return env.fdescribe(description, specDefinitions); }, /** * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code. * * A spec whose expectations all succeed will be passing and a spec with any failures will fail. * The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the * spec more readable by connecting the function name `it` and the argument `description` as a * complete sentence. * @name it * @since 1.3.0 * @function * @global * @param {String} description Textual description of what this spec is checking * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @see async */ it: function() { return env.it.apply(env, arguments); }, /** * A temporarily disabled [`it`]{@link it} * * The spec will report as `pending` and will not be executed. * @name xit * @since 1.3.0 * @function * @global * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed. */ xit: function() { return env.xit.apply(env, arguments); }, /** * A focused [`it`]{@link it} * * If suites or specs are focused, only those that are focused will be executed. * @name fit * @since 2.1.0 * @function * @global * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} testFunction Function that contains the code of your test. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @see async */ fit: function() { return env.fit.apply(env, arguments); }, /** * Run some shared setup before each of the specs in the {@link describe} in which it is called. * @name beforeEach * @since 1.3.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @see async */ beforeEach: function() { return env.beforeEach.apply(env, arguments); }, /** * Run some shared teardown after each of the specs in the {@link describe} in which it is called. * @name afterEach * @since 1.3.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @see async */ afterEach: function() { return env.afterEach.apply(env, arguments); }, /** * Run some shared setup once before all of the specs in the {@link describe} are run. * * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. * @name beforeAll * @since 2.1.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @see async */ beforeAll: function() { return env.beforeAll.apply(env, arguments); }, /** * Run some shared teardown once after all of the specs in the {@link describe} are run. * * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail. * @name afterAll * @since 2.1.0 * @function * @global * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @see async */ afterAll: function() { return env.afterAll.apply(env, arguments); }, /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult} * @name setSpecProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ setSpecProperty: function(key, value) { return env.setSpecProperty(key, value); }, /** * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult} * @name setSuiteProperty * @since 3.6.0 * @function * @param {String} key The name of the property * @param {*} value The value of the property */ setSuiteProperty: function(key, value) { return env.setSuiteProperty(key, value); }, /** * Create an expectation for a spec. * @name expect * @since 1.3.0 * @function * @global * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ expect: function(actual) { return env.expect(actual); }, /** * Create an asynchronous expectation for a spec. Note that the matchers * that are provided by an asynchronous expectation all return promises * which must be either returned from the spec or waited for using `await` * in order for Jasmine to associate them with the correct spec. * @name expectAsync * @since 3.3.0 * @function * @global * @param {Object} actual - Actual computed value to test expectations against. * @return {async-matchers} * @example * await expectAsync(somePromise).toBeResolved(); * @example * return expectAsync(somePromise).toBeResolved(); */ expectAsync: function(actual) { return env.expectAsync(actual); }, /** * Mark a spec as pending, expectation results will be ignored. * @name pending * @since 2.0.0 * @function * @global * @param {String} [message] - Reason the spec is pending. */ pending: function() { return env.pending.apply(env, arguments); }, /** * Explicitly mark a spec as failed. * @name fail * @since 2.1.0 * @function * @global * @param {String|Error} [error] - Reason for the failure. */ fail: function() { return env.fail.apply(env, arguments); }, /** * Install a spy onto an existing object. * @name spyOn * @since 1.3.0 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy}. * @param {String} methodName - The name of the method to replace with a {@link Spy}. * @returns {Spy} */ spyOn: function(obj, methodName) { return env.spyOn(obj, methodName); }, /** * Install a spy on a property installed with `Object.defineProperty` onto an existing object. * @name spyOnProperty * @since 2.6.0 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy} * @param {String} propertyName - The name of the property to replace with a {@link Spy}. * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on. * @returns {Spy} */ spyOnProperty: function(obj, methodName, accessType) { return env.spyOnProperty(obj, methodName, accessType); }, /** * Installs spies on all writable and configurable properties of an object. * @name spyOnAllFunctions * @since 3.2.1 * @function * @global * @param {Object} obj - The object upon which to install the {@link Spy}s * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties * @returns {Object} the spied object */ spyOnAllFunctions: function(obj, includeNonEnumerable) { return env.spyOnAllFunctions(obj, includeNonEnumerable); }, jsApiReporter: new jasmine.JsApiReporter({ timer: new jasmine.Timer() }), /** * @namespace jasmine */ jasmine: jasmine }; /** * Add a custom equality tester for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addCustomEqualityTester * @since 2.0.0 * @function * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise. * @see custom_equality */ jasmine.addCustomEqualityTester = function(tester) { env.addCustomEqualityTester(tester); }; /** * Add custom matchers for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addMatchers * @since 2.0.0 * @function * @param {Object} matchers - Keys from this object will be the new matcher names. * @see custom_matcher */ jasmine.addMatchers = function(matchers) { return env.addMatchers(matchers); }; /** * Add custom async matchers for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addAsyncMatchers * @since 3.5.0 * @function * @param {Object} matchers - Keys from this object will be the new async matcher names. * @see custom_matcher */ jasmine.addAsyncMatchers = function(matchers) { return env.addAsyncMatchers(matchers); }; /** * Add a custom object formatter for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addCustomObjectFormatter * @since 3.6.0 * @function * @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise. * @see custom_object_formatters */ jasmine.addCustomObjectFormatter = function(formatter) { return env.addCustomObjectFormatter(formatter); }; /** * Get the currently booted mock {Clock} for this Jasmine environment. * @name jasmine.clock * @since 2.0.0 * @function * @returns {Clock} */ jasmine.clock = function() { return env.clock; }; /** * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it. * @name jasmine.createSpy * @since 1.3.0 * @function * @param {String} [name] - Name to give the spy. This will be displayed in failure messages. * @param {Function} [originalFn] - Function to act as the real implementation. * @return {Spy} */ jasmine.createSpy = function(name, originalFn) { return env.createSpy(name, originalFn); }; /** * Create an object with multiple {@link Spy}s as its members. * @name jasmine.createSpyObj * @since 1.3.0 * @function * @param {String} [baseName] - Base name for the spies in the object. * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}. * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}. * @return {Object} */ jasmine.createSpyObj = function(baseName, methodNames, propertyNames) { return env.createSpyObj(baseName, methodNames, propertyNames); }; /** * Add a custom spy strategy for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.addSpyStrategy * @since 3.5.0 * @function * @param {String} name - The name of the strategy (i.e. what you call from `and`) * @param {Function} factory - Factory function that returns the plan to be executed. */ jasmine.addSpyStrategy = function(name, factory) { return env.addSpyStrategy(name, factory); }; /** * Set the default spy strategy for the current scope of specs. * * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}. * @name jasmine.setDefaultSpyStrategy * @function * @param {Function} defaultStrategyFn - a function that assigns a strategy * @example * beforeEach(function() { * jasmine.setDefaultSpyStrategy(and => and.returnValue(true)); * }); */ jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) { return env.setDefaultSpyStrategy(defaultStrategyFn); }; return jasmineInterface; }; jasmine-4.0.0/src/core/util.js000066400000000000000000000066551416413636100162140ustar00rootroot00000000000000getJasmineRequireObj().util = function(j$) { var util = {}; util.inherit = function(childClass, parentClass) { var Subclass = function() {}; Subclass.prototype = parentClass.prototype; childClass.prototype = new Subclass(); }; util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) { arrayOfArgs.push(args[i]); } return arrayOfArgs; }; util.isUndefined = function(obj) { return obj === void 0; }; util.arrayContains = function(array, search) { var i = array.length; while (i--) { if (array[i] === search) { return true; } } return false; }; util.clone = function(obj) { if (Object.prototype.toString.apply(obj) === '[object Array]') { return obj.slice(); } var cloned = {}; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { cloned[prop] = obj[prop]; } } return cloned; }; util.cloneArgs = function(args) { var clonedArgs = []; var argsAsArray = j$.util.argsToArray(args); for (var i = 0; i < argsAsArray.length; i++) { var str = Object.prototype.toString.apply(argsAsArray[i]), primitives = /^\[object (Boolean|String|RegExp|Number)/; // All falsey values are either primitives, `null`, or `undefined. if (!argsAsArray[i] || str.match(primitives)) { clonedArgs.push(argsAsArray[i]); } else { clonedArgs.push(j$.util.clone(argsAsArray[i])); } } return clonedArgs; }; util.getPropertyDescriptor = function(obj, methodName) { var descriptor, proto = obj; do { descriptor = Object.getOwnPropertyDescriptor(proto, methodName); proto = Object.getPrototypeOf(proto); } while (!descriptor && proto); return descriptor; }; util.objectDifference = function(obj, toRemove) { var diff = {}; for (var key in obj) { if (util.has(obj, key) && !util.has(toRemove, key)) { diff[key] = obj[key]; } } return diff; }; util.has = function(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); }; util.errorWithStack = function errorWithStack() { // Don't throw and catch. That makes it harder for users to debug their // code with exception breakpoints, and it's unnecessary since all // supported environments populate new Error().stack return new Error(); }; function callerFile() { var trace = new j$.StackTrace(util.errorWithStack()); return trace.frames[2].file; } util.jasmineFile = (function() { var result; return function() { if (!result) { result = callerFile(); } return result; }; })(); function StopIteration() {} StopIteration.prototype = Object.create(Error.prototype); StopIteration.prototype.constructor = StopIteration; util.validateTimeout = function(timeout, msgPrefix) { // Timeouts are implemented with setTimeout, which only supports a limited // range of values. The limit is unspecified, as is the behavior when it's // exceeded. But on all currently supported JS runtimes, setTimeout calls // the callback immediately when the timeout is greater than 2147483647 // (the maximum value of a signed 32 bit integer). var max = 2147483647; if (timeout > max) { throw new Error( (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max ); } }; return util; }; jasmine-4.0.0/src/html/000077500000000000000000000000001416413636100147015ustar00rootroot00000000000000jasmine-4.0.0/src/html/HtmlReporter.js000066400000000000000000000570461416413636100177020ustar00rootroot00000000000000jasmineRequire.HtmlReporter = function(j$) { function ResultsStateBuilder() { this.topResults = new j$.ResultsNode({}, '', null); this.currentParent = this.topResults; this.specsExecuted = 0; this.failureCount = 0; this.pendingSpecCount = 0; } ResultsStateBuilder.prototype.suiteStarted = function(result) { this.currentParent.addChild(result, 'suite'); this.currentParent = this.currentParent.last(); }; ResultsStateBuilder.prototype.suiteDone = function(result) { this.currentParent.updateResult(result); if (this.currentParent !== this.topResults) { this.currentParent = this.currentParent.parent; } if (result.status === 'failed') { this.failureCount++; } }; ResultsStateBuilder.prototype.specStarted = function(result) {}; ResultsStateBuilder.prototype.specDone = function(result) { this.currentParent.addChild(result, 'spec'); if (result.status !== 'excluded') { this.specsExecuted++; } if (result.status === 'failed') { this.failureCount++; } if (result.status == 'pending') { this.pendingSpecCount++; } }; ResultsStateBuilder.prototype.jasmineDone = function(result) { if (result.failedExpectations) { this.failureCount += result.failedExpectations.length; } }; function HtmlReporter(options) { var config = function() { return (options.env && options.env.configuration()) || {}; }, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, navigateWithNewParam = options.navigateWithNewParam || function() {}, addToExistingQueryString = options.addToExistingQueryString || defaultQueryString, filterSpecs = options.filterSpecs, htmlReporterMain, symbols, deprecationWarnings = []; this.initialize = function() { clearPrior(); htmlReporterMain = createDom( 'div', { className: 'jasmine_html-reporter' }, createDom( 'div', { className: 'jasmine-banner' }, createDom('a', { className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank' }), createDom('span', { className: 'jasmine-version' }, j$.version) ), createDom('ul', { className: 'jasmine-symbol-summary' }), createDom('div', { className: 'jasmine-alert' }), createDom( 'div', { className: 'jasmine-results' }, createDom('div', { className: 'jasmine-failures' }) ) ); getContainer().appendChild(htmlReporterMain); }; var totalSpecsDefined; this.jasmineStarted = function(options) { totalSpecsDefined = options.totalSpecsDefined || 0; }; var summary = createDom('div', { className: 'jasmine-summary' }); var stateBuilder = new ResultsStateBuilder(); this.suiteStarted = function(result) { stateBuilder.suiteStarted(result); }; this.suiteDone = function(result) { stateBuilder.suiteDone(result); if (result.status === 'failed') { failures.push(failureDom(result)); } addDeprecationWarnings(result, 'suite'); }; this.specStarted = function(result) { stateBuilder.specStarted(result); }; var failures = []; this.specDone = function(result) { stateBuilder.specDone(result); if (noExpectations(result)) { var noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; if (result.status === 'failed') { console.error(noSpecMsg); } else { console.warn(noSpecMsg); } } if (!symbols) { symbols = find('.jasmine-symbol-summary'); } symbols.appendChild( createDom('li', { className: this.displaySpecInCorrectFormat(result), id: 'spec_' + result.id, title: result.fullName }) ); if (result.status === 'failed') { failures.push(failureDom(result)); } addDeprecationWarnings(result, 'spec'); }; this.displaySpecInCorrectFormat = function(result) { return noExpectations(result) && result.status === 'passed' ? 'jasmine-empty' : this.resultStatus(result.status); }; this.resultStatus = function(status) { if (status === 'excluded') { return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; } return 'jasmine-' + status; }; this.jasmineDone = function(doneResult) { stateBuilder.jasmineDone(doneResult); var banner = find('.jasmine-banner'); var alert = find('.jasmine-alert'); var order = doneResult && doneResult.order; var i; alert.appendChild( createDom( 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's' ) ); banner.appendChild(optionsMenu(config())); if (stateBuilder.specsExecuted < totalSpecsDefined) { var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 var skippedLink = (window.location.pathname || '') + addToExistingQueryString('spec', ''); alert.appendChild( createDom( 'span', { className: 'jasmine-bar jasmine-skipped' }, createDom( 'a', { href: skippedLink, title: 'Run all specs' }, skippedMessage ) ) ); } var statusBarMessage = ''; var statusBarClassName = 'jasmine-overall-result jasmine-bar '; var globalFailures = (doneResult && doneResult.failedExpectations) || []; var failed = stateBuilder.failureCount + globalFailures.length > 0; if (totalSpecsDefined > 0 || failed) { statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount); if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); } } if (doneResult.overallStatus === 'passed') { statusBarClassName += ' jasmine-passed '; } else if (doneResult.overallStatus === 'incomplete') { statusBarClassName += ' jasmine-incomplete '; statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage; } else { statusBarClassName += ' jasmine-failed '; } var seedBar; if (order && order.random) { seedBar = createDom( 'span', { className: 'jasmine-seed-bar' }, ', randomized with seed ', createDom( 'a', { title: 'randomized with seed ' + order.seed, href: seedHref(order.seed) }, order.seed ) ); } alert.appendChild( createDom( 'span', { className: statusBarClassName }, statusBarMessage, seedBar ) ); var errorBarClassName = 'jasmine-bar jasmine-errored'; var afterAllMessagePrefix = 'AfterAll '; for (i = 0; i < globalFailures.length; i++) { alert.appendChild( createDom( 'span', { className: errorBarClassName }, globalFailureMessage(globalFailures[i]) ) ); } function globalFailureMessage(failure) { if (failure.globalErrorType === 'load') { var prefix = 'Error during loading: ' + failure.message; if (failure.filename) { return ( prefix + ' in ' + failure.filename + ' line ' + failure.lineno ); } else { return prefix; } } else if (failure.globalErrorType === 'afterAll') { return afterAllMessagePrefix + failure.message; } else { return failure.message; } } addDeprecationWarnings(doneResult); for (i = 0; i < deprecationWarnings.length; i++) { var children = [], context; switch (deprecationWarnings[i].runnableType) { case 'spec': context = '(in spec: ' + deprecationWarnings[i].runnableName + ')'; break; case 'suite': context = '(in suite: ' + deprecationWarnings[i].runnableName + ')'; break; default: context = ''; } deprecationWarnings[i].message.split('\n').forEach(function(line) { children.push(line); children.push(createDom('br')); }); children[0] = 'DEPRECATION: ' + children[0]; children.push(context); if (deprecationWarnings[i].stack) { children.push(createExpander(deprecationWarnings[i].stack)); } alert.appendChild( createDom( 'span', { className: 'jasmine-bar jasmine-warning' }, children ) ); } var results = find('.jasmine-results'); results.appendChild(summary); summaryList(stateBuilder.topResults, summary); if (failures.length) { alert.appendChild( createDom( 'span', { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, createDom('span', {}, 'Spec List | '), createDom( 'a', { className: 'jasmine-failures-menu', href: '#' }, 'Failures' ) ) ); alert.appendChild( createDom( 'span', { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, createDom( 'a', { className: 'jasmine-spec-list-menu', href: '#' }, 'Spec List' ), createDom('span', {}, ' | Failures ') ) ); find('.jasmine-failures-menu').onclick = function() { setMenuModeTo('jasmine-failure-list'); return false; }; find('.jasmine-spec-list-menu').onclick = function() { setMenuModeTo('jasmine-spec-list'); return false; }; setMenuModeTo('jasmine-failure-list'); var failureNode = find('.jasmine-failures'); for (i = 0; i < failures.length; i++) { failureNode.appendChild(failures[i]); } } }; return this; function failureDom(result) { var failure = createDom( 'div', { className: 'jasmine-spec-detail jasmine-failed' }, failureDescription(result, stateBuilder.currentParent), createDom('div', { className: 'jasmine-messages' }) ); var messages = failure.childNodes[1]; for (var i = 0; i < result.failedExpectations.length; i++) { var expectation = result.failedExpectations[i]; messages.appendChild( createDom( 'div', { className: 'jasmine-result-message' }, expectation.message ) ); messages.appendChild( createDom( 'div', { className: 'jasmine-stack-trace' }, expectation.stack ) ); } if (result.failedExpectations.length === 0) { messages.appendChild( createDom( 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations' ) ); } if (result.debugLogs) { messages.appendChild(debugLogTable(result.debugLogs)); } return failure; } function debugLogTable(debugLogs) { var tbody = createDom('tbody'); debugLogs.forEach(function(entry) { tbody.appendChild( createDom( 'tr', {}, createDom('td', {}, entry.timestamp.toString()), createDom('td', {}, entry.message) ) ); }); return createDom( 'div', { className: 'jasmine-debug-log' }, createDom( 'div', { className: 'jasmine-debug-log-header' }, 'Debug logs' ), createDom( 'table', {}, createDom( 'thead', {}, createDom( 'tr', {}, createDom('th', {}, 'Time (ms)'), createDom('th', {}, 'Message') ) ), tbody ) ); } function summaryList(resultsTree, domParent) { var specListNode; for (var i = 0; i < resultsTree.children.length; i++) { var resultNode = resultsTree.children[i]; if (filterSpecs && !hasActiveSpec(resultNode)) { continue; } if (resultNode.type === 'suite') { var suiteListNode = createDom( 'ul', { className: 'jasmine-suite', id: 'suite-' + resultNode.result.id }, createDom( 'li', { className: 'jasmine-suite-detail jasmine-' + resultNode.result.status }, createDom( 'a', { href: specHref(resultNode.result) }, resultNode.result.description ) ) ); summaryList(resultNode, suiteListNode); domParent.appendChild(suiteListNode); } if (resultNode.type === 'spec') { if (domParent.getAttribute('class') !== 'jasmine-specs') { specListNode = createDom('ul', { className: 'jasmine-specs' }); domParent.appendChild(specListNode); } var specDescription = resultNode.result.description; if (noExpectations(resultNode.result)) { specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; } if ( resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '' ) { specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason; } specListNode.appendChild( createDom( 'li', { className: 'jasmine-' + resultNode.result.status, id: 'spec-' + resultNode.result.id }, createDom( 'a', { href: specHref(resultNode.result) }, specDescription ) ) ); } } } function optionsMenu(config) { var optionsMenuDom = createDom( 'div', { className: 'jasmine-run-options' }, createDom('span', { className: 'jasmine-trigger' }, 'Options'), createDom( 'div', { className: 'jasmine-payload' }, createDom( 'div', { className: 'jasmine-stop-on-failure' }, createDom('input', { className: 'jasmine-fail-fast', id: 'jasmine-fail-fast', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-fail-fast' }, 'stop execution on spec failure' ) ), createDom( 'div', { className: 'jasmine-throw-failures' }, createDom('input', { className: 'jasmine-throw', id: 'jasmine-throw-failures', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-throw-failures' }, 'stop spec on expectation failure' ) ), createDom( 'div', { className: 'jasmine-random-order' }, createDom('input', { className: 'jasmine-random', id: 'jasmine-random-order', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-random-order' }, 'run tests in random order' ) ), createDom( 'div', { className: 'jasmine-hide-disabled' }, createDom('input', { className: 'jasmine-disabled', id: 'jasmine-hide-disabled', type: 'checkbox' }), createDom( 'label', { className: 'jasmine-label', for: 'jasmine-hide-disabled' }, 'hide disabled tests' ) ) ) ); var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); failFastCheckbox.checked = config.stopOnSpecFailure; failFastCheckbox.onclick = function() { navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure); }; var throwCheckbox = optionsMenuDom.querySelector( '#jasmine-throw-failures' ); throwCheckbox.checked = config.stopSpecOnExpectationFailure; throwCheckbox.onclick = function() { navigateWithNewParam( 'stopSpecOnExpectationFailure', !config.stopSpecOnExpectationFailure ); }; var randomCheckbox = optionsMenuDom.querySelector( '#jasmine-random-order' ); randomCheckbox.checked = config.random; randomCheckbox.onclick = function() { navigateWithNewParam('random', !config.random); }; var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled'); hideDisabled.checked = config.hideDisabled; hideDisabled.onclick = function() { navigateWithNewParam('hideDisabled', !config.hideDisabled); }; var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), isOpen = /\bjasmine-open\b/; optionsTrigger.onclick = function() { if (isOpen.test(optionsPayload.className)) { optionsPayload.className = optionsPayload.className.replace( isOpen, '' ); } else { optionsPayload.className += ' jasmine-open'; } }; return optionsMenuDom; } function failureDescription(result, suite) { var wrapper = createDom( 'div', { className: 'jasmine-description' }, createDom( 'a', { title: result.description, href: specHref(result) }, result.description ) ); var suiteLink; while (suite && suite.parent) { wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild); suiteLink = createDom( 'a', { href: suiteHref(suite) }, suite.result.description ); wrapper.insertBefore(suiteLink, wrapper.firstChild); suite = suite.parent; } return wrapper; } function suiteHref(suite) { var els = []; while (suite && suite.parent) { els.unshift(suite.result.description); suite = suite.parent; } // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('spec', els.join(' ')) ); } function addDeprecationWarnings(result, runnableType) { if (result && result.deprecationWarnings) { for (var i = 0; i < result.deprecationWarnings.length; i++) { var warning = result.deprecationWarnings[i].message; deprecationWarnings.push({ message: warning, stack: result.deprecationWarnings[i].stack, runnableName: result.fullName, runnableType: runnableType }); } } } function createExpander(stackTrace) { var expandLink = createDom('a', { href: '#' }, 'Show stack trace'); var root = createDom( 'div', { className: 'jasmine-expander' }, expandLink, createDom( 'div', { className: 'jasmine-expander-contents jasmine-stack-trace' }, stackTrace ) ); expandLink.addEventListener('click', function(e) { e.preventDefault(); if (root.classList.contains('jasmine-expanded')) { root.classList.remove('jasmine-expanded'); expandLink.textContent = 'Show stack trace'; } else { root.classList.add('jasmine-expanded'); expandLink.textContent = 'Hide stack trace'; } }); return root; } function find(selector) { return getContainer().querySelector('.jasmine_html-reporter ' + selector); } function clearPrior() { // return the reporter var oldReporter = find(''); if (oldReporter) { getContainer().removeChild(oldReporter); } } function createDom(type, attrs, childrenArrayOrVarArgs) { var el = createElement(type), children, i; if (j$.isArray_(childrenArrayOrVarArgs)) { children = childrenArrayOrVarArgs; } else { children = []; for (i = 2; i < arguments.length; i++) { children.push(arguments[i]); } } for (i = 0; i < children.length; i++) { var child = children[i]; if (typeof child === 'string') { el.appendChild(createTextNode(child)); } else { if (child) { el.appendChild(child); } } } for (var attr in attrs) { if (attr == 'className') { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } return el; } function pluralize(singular, count) { var word = count == 1 ? singular : singular + 's'; return '' + count + ' ' + word; } function specHref(result) { // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('spec', result.fullName) ); } function seedHref(seed) { // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906 return ( (window.location.pathname || '') + addToExistingQueryString('seed', seed) ); } function defaultQueryString(key, value) { return '?' + key + '=' + value; } function setMenuModeTo(mode) { htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); } function noExpectations(result) { var allExpectations = result.failedExpectations.length + result.passedExpectations.length; return ( allExpectations === 0 && (result.status === 'passed' || result.status === 'failed') ); } function hasActiveSpec(resultNode) { if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') { return true; } if (resultNode.type == 'suite') { for (var i = 0, j = resultNode.children.length; i < j; i++) { if (hasActiveSpec(resultNode.children[i])) { return true; } } } } } return HtmlReporter; }; jasmine-4.0.0/src/html/HtmlSpecFilter.js000066400000000000000000000006221416413636100201240ustar00rootroot00000000000000jasmineRequire.HtmlSpecFilter = function() { function HtmlSpecFilter(options) { var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); var filterPattern = new RegExp(filterString); this.matches = function(specName) { return filterPattern.test(specName); }; } return HtmlSpecFilter; }; jasmine-4.0.0/src/html/QueryString.js000066400000000000000000000025671416413636100175450ustar00rootroot00000000000000jasmineRequire.QueryString = function() { function QueryString(options) { this.navigateWithNewParam = function(key, value) { options.getWindowLocation().search = this.fullStringWithNewParam( key, value ); }; this.fullStringWithNewParam = function(key, value) { var paramMap = queryStringToParamMap(); paramMap[key] = value; return toQueryString(paramMap); }; this.getParam = function(key) { return queryStringToParamMap()[key]; }; return this; function toQueryString(paramMap) { var qStrPairs = []; for (var prop in paramMap) { qStrPairs.push( encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]) ); } return '?' + qStrPairs.join('&'); } function queryStringToParamMap() { var paramStr = options.getWindowLocation().search.substring(1), params = [], paramMap = {}; if (paramStr.length > 0) { params = paramStr.split('&'); for (var i = 0; i < params.length; i++) { var p = params[i].split('='); var value = decodeURIComponent(p[1]); if (value === 'true' || value === 'false') { value = JSON.parse(value); } paramMap[decodeURIComponent(p[0])] = value; } } return paramMap; } } return QueryString; }; jasmine-4.0.0/src/html/ResultsNode.js000066400000000000000000000007701416413636100175120ustar00rootroot00000000000000jasmineRequire.ResultsNode = function() { function ResultsNode(result, type, parent) { this.result = result; this.type = type; this.parent = parent; this.children = []; this.addChild = function(result, type) { this.children.push(new ResultsNode(result, type, this)); }; this.last = function() { return this.children[this.children.length - 1]; }; this.updateResult = function(result) { this.result = result; }; } return ResultsNode; }; jasmine-4.0.0/src/html/_HTMLReporter.scss000066400000000000000000000174201416413636100202300ustar00rootroot00000000000000@use "sass:math"; $line-height: 14px; $margin-unit: 14px; $faint-text-color: #aaa; $light-text-color: #666; $text-color: #333; $page-background-color: #eee; $passing-color: #007069; $failing-color: #ca3a11; $pending-color: #ba9d37; $empty-color: #eff543; $neutral-color: #bababa; $jasmine-color: #8a4182; $passing-mark: "\02022"; $failing-mark: "\d7"; $pending-mark: "*"; $space: "\0020"; $font-size: 11px; $large-font-size: 14px; body { overflow-y: scroll; } .jasmine_html-reporter { width: 100%; background-color: $page-background-color; padding: 5px; margin: -8px; font-size: $font-size; font-family: Monaco, "Lucida Console", monospace; line-height: $line-height; color: $text-color; a { text-decoration: none; &:hover { text-decoration: underline; } } p, h1, h2, h3, h4, h5, h6 { margin: 0; line-height: $line-height; } .jasmine-banner, .jasmine-symbol-summary, .jasmine-summary, .jasmine-result-message, .jasmine-spec .jasmine-description, .jasmine-spec-detail .jasmine-description, .jasmine-alert .jasmine-bar, .jasmine-stack-trace { padding-left: $margin-unit - 5px; padding-right: $margin-unit - 5px; } .jasmine-banner { position: relative; } .jasmine-banner .jasmine-title { background: url('../../images/jasmine-horizontal.png') no-repeat; background: url('../../images/jasmine-horizontal.svg') no-repeat, none; -moz-background-size: 100%; -o-background-size: 100%; -webkit-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; } .jasmine-banner .jasmine-version { margin-left: $margin-unit; position: relative; top: 6px; } // This div is available for testing elements that must be added to the DOM. // We position it out of view, so it doesn't obstruct the runner. #jasmine_content { position: fixed; right: 100%; } .jasmine-version { color: $faint-text-color; } //--- Banner ---// .jasmine-banner { margin-top: $line-height; } .jasmine-duration { color: #fff; float: right; line-height: $line-height * 2; padding-right: 9px; } //--- Symbol summary ---// .jasmine-symbol-summary { overflow: hidden; margin: $line-height 0; li { display: inline-block; height: math.div($line-height, 2) + 3; width: $line-height; font-size: 16px; &.jasmine-passed { font-size: 14px; &:before { color: $passing-color; content: $passing-mark; } } &.jasmine-failed { line-height: math.div($line-height, 2) + 2; &:before { color: $failing-color; content: $failing-mark; font-weight: bold; margin-left: -1px; } } &.jasmine-excluded { font-size: 14px; &:before { color: $neutral-color; content: $passing-mark; } } &.jasmine-excluded-no-display { font-size: 14px; display: none; } &.jasmine-pending { line-height: 17px; &:before { color: $pending-color; content: $pending-mark; } } &.jasmine-empty { font-size: 14px; &:before { color: $pending-color; content: $passing-mark; } } } } .jasmine-run-options { float: right; margin-right: 5px; border: 1px solid $jasmine-color; color: $jasmine-color; position: relative; line-height: 20px; .jasmine-trigger { cursor: pointer; padding: 8px 16px; } .jasmine-payload { position: absolute; display: none; right: -1px; border: 1px solid $jasmine-color; background-color: $page-background-color; white-space: nowrap; padding: 4px 8px; &.jasmine-open { display: block; } } } //--- Alerts: status bars ---// .jasmine-bar { line-height: $line-height * 2; font-size: $large-font-size; display: block; color: #eee; &.jasmine-failed, &.jasmine-errored { background-color: $failing-color; border-bottom: 1px solid $page-background-color; } &.jasmine-passed { background-color: $passing-color; } &.jasmine-incomplete { background-color: $neutral-color; } &.jasmine-skipped { background-color: $neutral-color; } &.jasmine-warning { margin-top: $margin-unit; margin-bottom: $margin-unit; background-color: $pending-color; color: $text-color; } &.jasmine-menu { background-color: #fff; color: $faint-text-color; a { color: $text-color; } } a { color: white; } } // simplify toggle control between the two menu bars &.jasmine-spec-list { .jasmine-bar.jasmine-menu.jasmine-failure-list, .jasmine-results .jasmine-failures { display: none; } } &.jasmine-failure-list { .jasmine-bar.jasmine-menu.jasmine-spec-list, .jasmine-summary { display: none; } } //--- Results ---// .jasmine-results { margin-top: $line-height; } //--- Results summary: Suites and Specs names/links ---// .jasmine-summary { margin-top: $margin-unit; ul { list-style-type: none; margin-left: $margin-unit; padding-top: 0; padding-left: 0; &.jasmine-suite { margin-top: math.div($margin-unit, 2); margin-bottom: math.div($margin-unit, 2) } } li { &.jasmine-passed a { color: $passing-color; } &.jasmine-failed a { color: $failing-color; } &.jasmine-empty a { color: $pending-color; } &.jasmine-pending a { color: $pending-color; } &.jasmine-excluded a { color: $neutral-color; } } } .jasmine-specs { li { &.jasmine-passed a:before { content: $passing-mark + $space; } &.jasmine-failed a:before { content: $failing-mark + $space; } &.jasmine-empty a:before { content: $pending-mark + $space; } &.jasmine-pending a:before { content: $passing-mark + $space; } &.jasmine-excluded a:before { content: $passing-mark + $space; } } } .jasmine-description + .jasmine-suite { margin-top: 0; } .jasmine-suite { margin-top: $margin-unit; a { color: $text-color; } } //--- Failure details ---// .jasmine-failures { .jasmine-spec-detail { margin-bottom: $line-height * 2; .jasmine-description { background-color: $failing-color; color: white; a { color: white; } } } } .jasmine-result-message { padding-top: $line-height; color: $text-color; white-space: pre-wrap; } .jasmine-result-message span.jasmine-result { display: block; } .jasmine-stack-trace { margin: 5px 0 0 0; max-height: $line-height * 16; overflow: auto; line-height: 18px; color: $light-text-color; border: 1px solid #ddd; background: white; white-space: pre; } .jasmine-expander { a { display: block; margin-left: $margin-unit; color: blue; text-decoration: underline; } } .jasmine-expander-contents { display: none; } .jasmine-expanded { padding-bottom: 10px; } .jasmine-expanded .jasmine-expander-contents { display: block; margin-left: $margin-unit; padding: 5px; } .jasmine-debug-log { margin: 5px 0 0 0; padding: 5px; color: $light-text-color; border: 1px solid #ddd; background: white; table { border-spacing: 0; } table, th, td { border: 1px solid #ddd; } } } jasmine-4.0.0/src/html/jasmine.scss000066400000000000000000000000301416413636100172150ustar00rootroot00000000000000@import "HTMLReporter"; jasmine-4.0.0/src/html/requireHtml.js000066400000000000000000000004761416413636100175470ustar00rootroot00000000000000var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); jasmineRequire.html = function(j$) { j$.ResultsNode = jasmineRequire.ResultsNode(); j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); j$.QueryString = jasmineRequire.QueryString(); j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); }; jasmine-4.0.0/src/templates/000077500000000000000000000000001416413636100157335ustar00rootroot00000000000000jasmine-4.0.0/src/templates/example_project_jasmine_tags.html.erb000066400000000000000000000004351416413636100252770ustar00rootroot00000000000000 jasmine-4.0.0/src/templates/version.js.erb000066400000000000000000000003171416413636100205260ustar00rootroot00000000000000 jasmine.version_= { "major": <%= major %>, "minor": <%= minor %>, "build": <%= build %>, "revision": <%= revision %><%= %Q{,\n "release_candidate": #{release_candidate}} if release_candidate %> }; jasmine-4.0.0/src/version.js000066400000000000000000000001141416413636100157540ustar00rootroot00000000000000getJasmineRequireObj().version = function() { return '<%= version %>'; };