From 6ab04b79e8f70b5f3e6a6d0d0f8874e72d73070e Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Wed, 21 Feb 2018 10:43:34 +0200 Subject: [PATCH] add versioned documentation to the website (#5541) * add versioned documentation to the website * add changelog for versioned documentation * exclude versioned docs from specific lint rules * use id attribute instead of name for in page anchors and remove redundant anchors * re-create docs for v22.3 with latest changes from master --- .eslintrc.js | 5 +- CHANGELOG.md | 2 + website/package.json | 3 +- website/pages/en/versions.js | 104 ++ website/versioned_docs/version-22.3/CLI.md | 328 +++++ .../version-22.3/Configuration.md | 1085 +++++++++++++++++ .../version-22.3/Es6ClassMocks.md | 392 ++++++ .../versioned_docs/version-22.3/ExpectAPI.md | 1060 ++++++++++++++++ .../version-22.3/GettingStarted.md | 156 +++ .../versioned_docs/version-22.3/GlobalAPI.md | 413 +++++++ .../version-22.3/JestObjectAPI.md | 484 ++++++++ .../version-22.3/JestPlatform.md | 197 +++ .../version-22.3/ManualMocks.md | 157 +++ .../version-22.3/MigrationGuide.md | 48 + .../version-22.3/MockFunctionAPI.md | 328 +++++ .../version-22.3/MockFunctions.md | 279 +++++ .../versioned_docs/version-22.3/MongoDB.md | 128 ++ .../version-22.3/MoreResources.md | 39 + .../versioned_docs/version-22.3/Puppeteer.md | 103 ++ .../version-22.3/SetupAndTeardown.md | 222 ++++ .../version-22.3/SnapshotTesting.md | 236 ++++ .../version-22.3/TestingAsyncCode.md | 160 +++ .../version-22.3/TestingFrameworks.md | 39 + .../versioned_docs/version-22.3/TimerMocks.md | 182 +++ .../version-22.3/Troubleshooting.md | 317 +++++ .../version-22.3/TutorialAsync.md | 190 +++ .../version-22.3/TutorialReact.md | 337 +++++ .../version-22.3/TutorialReactNative.md | 273 +++++ .../version-22.3/TutorialjQuery.md | 80 ++ .../version-22.3/UsingMatchers.md | 175 +++ .../versioned_docs/version-22.3/Webpack.md | 281 +++++ .../version-22.3-sidebars.json | 38 + website/versions.json | 3 + 33 files changed, 7842 insertions(+), 2 deletions(-) create mode 100644 website/pages/en/versions.js create mode 100644 website/versioned_docs/version-22.3/CLI.md create mode 100644 website/versioned_docs/version-22.3/Configuration.md create mode 100644 website/versioned_docs/version-22.3/Es6ClassMocks.md create mode 100644 website/versioned_docs/version-22.3/ExpectAPI.md create mode 100644 website/versioned_docs/version-22.3/GettingStarted.md create mode 100644 website/versioned_docs/version-22.3/GlobalAPI.md create mode 100644 website/versioned_docs/version-22.3/JestObjectAPI.md create mode 100644 website/versioned_docs/version-22.3/JestPlatform.md create mode 100644 website/versioned_docs/version-22.3/ManualMocks.md create mode 100644 website/versioned_docs/version-22.3/MigrationGuide.md create mode 100644 website/versioned_docs/version-22.3/MockFunctionAPI.md create mode 100644 website/versioned_docs/version-22.3/MockFunctions.md create mode 100644 website/versioned_docs/version-22.3/MongoDB.md create mode 100644 website/versioned_docs/version-22.3/MoreResources.md create mode 100644 website/versioned_docs/version-22.3/Puppeteer.md create mode 100644 website/versioned_docs/version-22.3/SetupAndTeardown.md create mode 100644 website/versioned_docs/version-22.3/SnapshotTesting.md create mode 100644 website/versioned_docs/version-22.3/TestingAsyncCode.md create mode 100644 website/versioned_docs/version-22.3/TestingFrameworks.md create mode 100644 website/versioned_docs/version-22.3/TimerMocks.md create mode 100644 website/versioned_docs/version-22.3/Troubleshooting.md create mode 100644 website/versioned_docs/version-22.3/TutorialAsync.md create mode 100644 website/versioned_docs/version-22.3/TutorialReact.md create mode 100644 website/versioned_docs/version-22.3/TutorialReactNative.md create mode 100644 website/versioned_docs/version-22.3/TutorialjQuery.md create mode 100644 website/versioned_docs/version-22.3/UsingMatchers.md create mode 100644 website/versioned_docs/version-22.3/Webpack.md create mode 100644 website/versioned_sidebars/version-22.3-sidebars.json create mode 100644 website/versions.json diff --git a/.eslintrc.js b/.eslintrc.js index 0f2ac2d49772..acf53a21d60e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -56,7 +56,10 @@ module.exports = { }, }, { - excludedFiles: 'integration-tests/__tests__/**/*', + excludedFiles: [ + 'integration-tests/__tests__/**/*', + 'website/versioned_docs/**/*.md', + ], files: [ 'examples/**/*', 'scripts/**/*', diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e44b199c6e..6797f1f012af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,8 @@ ([#5523](https://github.com/facebook/jest/pull/5523)) * `[jest-cli]` Support multiple glob patterns for `collectCoverageFrom` ([#5537](https://github.com/facebook/jest/pull/5537)) +* `[docs]` Add versioned documentation to the website + ([#5541](https://github.com/facebook/jest/pull/5541)) ### Chore & Maintenance diff --git a/website/package.json b/website/package.json index 6c19201dac04..4f807e996e66 100644 --- a/website/package.json +++ b/website/package.json @@ -7,7 +7,8 @@ "build": "docusaurus-build", "gh-pages": "docusaurus-publish", "examples": "docusaurus-examples", - "crowdin-upload": "crowdin --config ../crowdin.yaml upload sources --auto-update -b master", + "crowdin-upload": + "crowdin --config ../crowdin.yaml upload sources --auto-update -b master", "crowdin-download": "crowdin --config ../crowdin.yaml download -b master", "publish-gh-pages": "docusaurus-publish", "write-translations": "docusaurus-write-translations", diff --git a/website/pages/en/versions.js b/website/pages/en/versions.js new file mode 100644 index 000000000000..691b2681b7a9 --- /dev/null +++ b/website/pages/en/versions.js @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +const CompLibrary = require('../../core/CompLibrary'); +const Container = CompLibrary.Container; + +const CWD = process.cwd(); + +const siteConfig = require(CWD + '/siteConfig.js'); +const versions = require(CWD + '/versions.json'); + +class Versions extends React.Component { + render() { + const latestVersion = versions[0]; + return ( +
+ +
+
+

{siteConfig.title + ' Versions'}

+
+

Current version (Stable)

+

Latest stable version of Jest

+ + + + + + + + +
{latestVersion} + + Documentation + + + + Release Notes + +
+

Latest version

+

+ Here you can find the latest unreleased documentation and code. +

+ + + + + + + + +
master + + Documentation + + + Source Code +
+

Past Versions

+

+ Here you can find documentation for previous versions of Jest. +

+ + + {versions.map( + version => + version !== latestVersion && ( + + + + + ) + )} + +
{version} + + Documentation + +
+
+
+
+ ); + } +} + +module.exports = Versions; diff --git a/website/versioned_docs/version-22.3/CLI.md b/website/versioned_docs/version-22.3/CLI.md new file mode 100644 index 000000000000..340a8342dc5e --- /dev/null +++ b/website/versioned_docs/version-22.3/CLI.md @@ -0,0 +1,328 @@ +--- +id: version-22.3-cli +title: Jest CLI Options +original_id: cli +--- + +The `jest` command line runner has a number of useful options. You can run +`jest --help` to view all available options. Many of the options shown below can +also be used together to run tests exactly the way you want. Every one of Jest's +[Configuration](Configuration.md) options can also be specified through the CLI. + +Here is a brief overview: + +## Running from the command line + +Run all tests (default): + +```bash +jest +``` + +Run only the tests that were specified with a pattern or filename: + +```bash +jest my-test #or +jest path/to/my-test.js +``` + +Run tests related to changed files based on hg/git (uncommitted files): + +```bash +jest -o +``` + +Run tests related to `path/to/fileA.js` and `path/to/fileB.js`: + +```bash +jest --findRelatedTests path/to/fileA.js path/to/fileB.js +``` + +Run tests that match this spec name (match against the name in `describe` or +`test`, basically). + +```bash +jest -t name-of-spec +``` + +Run watch mode: + +```bash +jest --watch #runs jest -o by default +jest --watchAll #runs all tests +``` + +Watch mode also enables to specify the name or path to a file to focus on a +specific set of tests. + +## Using with npm scripts + +If you run Jest via `npm test`, you can still use the command line arguments by +inserting a `--` between `npm test` and the Jest arguments. Instead of: + +```bash +jest -u -t="ColorPicker" +``` + +you can use: + +```bash +npm test -- -u -t="ColorPicker" +``` + +CLI options take precedence over values from the +[Configuration](Configuration.md). + +## Options + + + +--- + +## Reference + +### `jest ` + +When you run `jest` with an argument, that argument is treated as a regular +expression to match against files in your project. It is possible to run test +suites by providing a pattern. Only the files that the pattern matches will be +picked up and executed. Depending on your terminal, you may need to quote this +argument: `jest "my.*(complex)?pattern"`. On Windows, you will need to use `/` +as a path separator or escape `\` as `\\`. + +### `--bail` + +Alias: `-b`. Exit the test suite immediately upon the first failing test suite. + +### `--cache` + +Whether to use the cache. Defaults to true. Disable the cache using +`--no-cache`. _Note: the cache should only be disabled if you are experiencing +caching related problems. On average, disabling the cache makes Jest at least +two times slower._ + +If you want to inspect the cache, use `--showConfig` and look at the +`cacheDirectory` value. If you need to clear the cache, use `--clearCache`. + +### `--changedFilesWithAncestor` + +Runs tests related to the current changes and the changes made in the last +commit. Behaves similarly to `--onlyChanged`. + +### `--changedSince` + +##### available in Jest **22.2.0+** + +Runs tests related the changes since the provided branch. If the current branch +has diverged from the given branch, then only changes made locally will be +tested. Behaves similarly to `--onlyChanged`. + +### `--ci` + +When this option is provided, Jest will assume it is running in a CI +environment. This changes the behavior when a new snapshot is encountered. +Instead of the regular behavior of storing a new snapshot automatically, it will +fail the test and require Jest to be run with `--updateSnapshot`. + +### `--clearCache` + +##### available in Jest **22.0.0+** + +Deletes the Jest cache directory and then exits without running tests. Will +delete `cacheDirectory` if the option is passed, or Jest's default cache +directory. The default cache directory can be found by calling +`jest --showConfig`. _Note: clearing the cache will reduce performance._ + +### `--collectCoverageFrom=` + +An array of glob patterns relative to matching the files that coverage +info needs to be collected from. + +### `--colors` + +Forces test results output highlighting even if stdout is not a TTY. + +### `--config=` + +Alias: `-c`. The path to a Jest config file specifying how to find and execute +tests. If no `rootDir` is set in the config, the current directory is assumed to +be the rootDir for the project. This can also be a JSON-encoded value which Jest +will use as configuration. + +### `--coverage` + +Indicates that test coverage information should be collected and reported in the +output. + +### `--debug` + +Print debugging info about your Jest config. + +### `--env=` + +The test environment used for all tests. This can point to any file or node +module. Examples: `jsdom`, `node` or `path/to/my-environment.js`. + +### `--expand` + +Alias: `-e`. Use this flag to show full diffs and errors instead of a patch. + +### `--findRelatedTests ` + +Find and run the tests that cover a space separated list of source files that +were passed in as arguments. Useful for pre-commit hook integration to run the +minimal amount of tests necessary. + +### `--forceExit` + +Force Jest to exit after all tests have completed running. This is useful when +resources set up by test code cannot be adequately cleaned up. _Note: This +feature is an escape-hatch. If Jest doesn't exit at the end of a test run, it +means external resources are still being held on to or timers are still pending +in your code. It is advised to tear down external resources after each test to +make sure Jest can shut down cleanly._ + +### `--help` + +Show the help information, similar to this page. + +### `--json` + +Prints the test results in JSON. This mode will send all other test output and +user messages to stderr. + +### `--outputFile=` + +Write test results to a file when the `--json` option is also specified. + +### `--lastCommit` + +Run all tests affected by file changes in the last commit made. Behaves +similarly to `--onlyChanged`. + +### `--listTests` + +Lists all tests as JSON that Jest will run given the arguments, and exits. This +can be used together with `--findRelatedTests` to know which tests Jest will +run. + +### `--logHeapUsage` + +Logs the heap usage after every test. Useful to debug memory leaks. Use together +with `--runInBand` and `--expose-gc` in node. + +### `--maxWorkers=` + +Alias: `-w`. Specifies the maximum number of workers the worker-pool will spawn +for running tests. This defaults to the number of the cores available on your +machine. It may be useful to adjust this in resource limited environments like +CIs but the default should be adequate for most use-cases. + +### `--noStackTrace` + +Disables stack trace in test results output. + +### `--notify` + +Activates notifications for test results. Good for when you don't want your +consciousness to be able to focus on anything except JavaScript testing. + +### `--onlyChanged` + +Alias: `-o`. Attempts to identify which tests to run based on which files have +changed in the current repository. Only works if you're running tests in a +git/hg repository at the moment and requires a static dependency graph (ie. no +dynamic requires). + +### `--passWithNoTests` + +Allows the test suite to pass when no files are found. + +### `--projects ... ` + +Run tests from one or more projects. + +### `--runInBand` + +Alias: `-i`. Run all tests serially in the current process, rather than creating +a worker pool of child processes that run tests. This can be useful for +debugging. + +### `--setupTestFrameworkScriptFile=` + +The path to a module that runs some code to configure or set up the testing +framework before each test. Beware that files imported by the setup script will +not be mocked during testing. + +### `--showConfig` + +Print your Jest config and then exits. + +### `--silent` + +Prevent tests from printing messages through the console. + +### `--testNamePattern=` + +Alias: `-t`. Run only tests and test suites with a name that matches the regex. +For example, suppose you want to run only tests related to authorization which +will have names like `"GET /api/posts with auth"`, then you can use +`jest -t=auth`. + +### `--testLocationInResults` + +Adds a `location` field to test results. Useful if you want to report the +location of a test in a reporter. + +Note that `column` is 0-indexed while `line` is not. + +```json +{ + "column": 4, + "line": 5 +} +``` + +### `--testPathPattern=` + +A regexp pattern string that is matched against all tests paths before executing +the test. On Windows, you will need to use `/` as a path separator or escape `\` +as `\\`. + +### `--testRunner=` + +Lets you specify a custom test runner. + +### `--updateSnapshot` + +Alias: `-u`. Use this flag to re-record every snapshot that fails during this +test run. Can be used together with a test suite pattern or with +`--testNamePattern` to re-record snapshots. + +### `--useStderr` + +Divert all output to stderr. + +### `--verbose` + +Display individual test results with the test suite hierarchy. + +### `--version` + +Alias: `-v`. Print the version and exit. + +### `--watch` + +Watch files for changes and rerun tests related to changed files. If you want to +re-run all tests when a file has changed, use the `--watchAll` option instead. + +### `--watchAll` + +Watch files for changes and rerun all tests when something changes. If you want +to re-run only the tests that depend on the changed files, use the `--watch` +option. + +### `--watchman` + +Whether to use watchman for file crawling. Defaults to true. Disable using +`--no-watchman`. diff --git a/website/versioned_docs/version-22.3/Configuration.md b/website/versioned_docs/version-22.3/Configuration.md new file mode 100644 index 000000000000..5aee81f35f2f --- /dev/null +++ b/website/versioned_docs/version-22.3/Configuration.md @@ -0,0 +1,1085 @@ +--- +id: version-22.3-configuration +title: Configuring Jest +original_id: configuration +--- + +Jest's configuration can be defined in the `package.json` file of your project, +or through a `jest.config.js` file or through the `--config ` +option. If you'd like to use your `package.json` to store Jest's config, the +"jest" key should be used on the top level so Jest will know how to find your +settings: + +```json +{ + "name": "my-project", + "jest": { + "verbose": true + } +} +``` + +Or through JavaScript: + +```js +// jest.config.js +module.exports = { + verbose: true, +}; +``` + +Please keep in mind that the resulting configuration must be JSON-serializable. + +When using the `--config` option, the JSON file must not contain a "jest" key: + +```json +{ + "bail": true, + "verbose": true +} +``` + +## Options + +These options let you control Jest's behavior in your `package.json` file. The +Jest philosophy is to work great by default, but sometimes you just need more +configuration power. + + + +--- + +## Reference + +### `automock` [boolean] + +Default: `false` + +This option is disabled by default. If you are introducing Jest to a large +organization with an existing codebase but few tests, enabling this option can +be helpful to introduce unit tests gradually. Modules can be explicitly +auto-mocked using `jest.mock(moduleName)`. + +_Note: Core modules, like `fs`, are not mocked by default. They can be mocked +explicitly, like `jest.mock('fs')`._ + +_Note: Automocking has a performance cost most noticeable in large projects. See +[here](troubleshooting.html#tests-are-slow-when-leveraging-automocking) for +details and a workaround._ + +### `browser` [boolean] + +Default: `false` + +Respect Browserify's +[`"browser"` field](https://github.com/substack/browserify-handbook#browser-field) +in `package.json` when resolving modules. Some modules export different versions +based on whether they are operating in Node or a browser. + +### `bail` [boolean] + +Default: `false` + +By default, Jest runs all tests and produces all errors into the console upon +completion. The bail config option can be used here to have Jest stop running +tests after the first failure. + +### `cacheDirectory` [string] + +Default: `"/tmp/"` + +The directory where Jest should store its cached dependency information. + +Jest attempts to scan your dependency tree once (up-front) and cache it in order +to ease some of the filesystem raking that needs to happen while running tests. +This config option lets you customize where Jest stores that cache data on disk. + +### `collectCoverage` [boolean] + +Default: `false` + +Indicates whether the coverage information should be collected while executing +the test. Because this retrofits all executed files with coverage collection +statements, it may significantly slow down your tests. + +### `collectCoverageFrom` [array] + +Default: `undefined` + +An array of [glob patterns](https://github.com/jonschlinkert/micromatch) +indicating a set of files for which coverage information should be collected. If +a file matches the specified glob pattern, coverage information will be +collected for it even if no tests exist for this file and it's never required in +the test suite. + +Example: + +```json +{ + "collectCoverageFrom": [ + "**/*.{js,jsx}", + "!**/node_modules/**", + "!**/vendor/**" + ] +} +``` + +This will collect coverage information for all the files inside the project's +`rootDir`, except the ones that match `**/node_modules/**` or `**/vendor/**`. + +_Note: This option requires `collectCoverage` to be set to true or Jest to be +invoked with `--coverage`._ + +### `coverageDirectory` [string] + +Default: `undefined` + +The directory where Jest should output its coverage files. + +### `coveragePathIgnorePatterns` [array] + +Default: `["/node_modules/"]` + +An array of regexp pattern strings that are matched against all file paths +before executing the test. If the file path matches any of the patterns, +coverage information will be skipped. + +These pattern strings match against the full path. Use the `` string +token to include the path to your project's root directory to prevent it from +accidentally ignoring all of your files in different environments that may have +different root directories. Example: +`["/build/", "/node_modules/"]`. + +### `coverageReporters` [array] + +Default: `["json", "lcov", "text"]` + +A list of reporter names that Jest uses when writing coverage reports. Any +[istanbul reporter](https://github.com/gotwarlost/istanbul/tree/master/lib/report) +can be used. + +_Note: Setting this option overwrites the default values. Add `"text"` or +`"text-summary"` to see a coverage summary in the console output._ + +### `coverageThreshold` [object] + +Default: `undefined` + +This will be used to configure minimum threshold enforcement for coverage +results. Thresholds can be specified as `global`, as a +[glob](https://github.com/isaacs/node-glob#glob-primer), and as a directory or +file path. If thresholds aren't met, jest will fail. Thresholds specified as a +positive number are taken to be the minimum percentage required. Thresholds +specified as a negative number represent the maximum number of uncovered +entities allowed. + +For example, with the following configuration jest will fail if there is less +than 80% branch, line, and function coverage, or if there are more than 10 +uncovered statements: + +```json +{ + ... + "jest": { + "coverageThreshold": { + "global": { + "branches": 80, + "functions": 80, + "lines": 80, + "statements": -10 + } + } + } +} +``` + +If globs or paths are specified alongside `global`, coverage data for matching +paths will be subtracted from overall coverage and thresholds will be applied +independently. Thresholds for globs are applied to all files matching the glob. +If the file specified by path is not found, error is returned. + +For example, with the following configuration: + +```json +{ + ... + "jest": { + "coverageThreshold": { + "global": { + "branches": 50, + "functions": 50, + "lines": 50, + "statements": 50 + }, + "./src/components/": { + "branches": 40, + "statements": 40 + }, + "./src/reducers/**/*.js": { + "statements": 90, + }, + "./src/api/very-important-module.js": { + "branches": 100, + "functions": 100, + "lines": 100, + "statements": 100 + } + } + } +} +``` + +Jest will fail if: + +* The `./src/components` directory has less than 40% branch or statement + coverage. +* One of the files matching the `./src/reducers/**/*.js` glob has less than 90% + statement coverage. +* The `./src/api/very-important-module.js` file has less than 100% coverage. +* Every remaining file combined has less than 50% coverage (`global`). + +### `forceCoverageMatch` [array] + +Default: `['']` + +Test files are normally ignored from collecting code coverage. With this option, +you can overwrite this behavior and include otherwise ignored files in code +coverage. + +For example, if you have tests in source files named with `.t.js` extension as +following: + +```javascript +// sum.t.js + +export function sum(a, b) { + return a + b; +} + +if (process.env.NODE_ENV === 'test') { + test('sum', () => { + expect(sum(1, 2)).toBe(3); + }); +} +``` + +You can collect coverage from those files with setting `forceCoverageMatch`. + +```json +{ + ... + "jest": { + "forceCoverageMatch": ["**/*.t.js"] + } +} +``` + +### `globals` [object] + +Default: `{}` + +A set of global variables that need to be available in all test environments. + +For example, the following would create a global `__DEV__` variable set to +`true` in all test environments: + +```json +{ + ... + "jest": { + "globals": { + "__DEV__": true + } + } +} +``` + +Note that, if you specify a global reference value (like an object or array) +here, and some code mutates that value in the midst of running a test, that +mutation will _not_ be persisted across test runs for other test files. In +addition the `globals` object must be json-serializable, so it can't be used to +specify global functions. For that you should use `setupFiles`. + +### `globalSetup` [string] + +Default: `undefined` + +This option allows the use of a custom global setup module which exports an +async function that is triggered once before all test suites. + +### `globalTeardown` [string] + +Default: `undefined` + +This option allows the use of a custom global teardown module which exports an +async function that is triggered once after all test suites. + +### `moduleFileExtensions` [array] + +Default: `["js", "json", "jsx", "node"]` + +An array of file extensions your modules use. If you require modules without +specifying a file extension, these are the extensions Jest will look for. + +If you are using TypeScript this should be `["js", "jsx", "json", "ts", "tsx"]`, +check [ts-jest's documentation](https://github.com/kulshekhar/ts-jest). + +### `moduleDirectories` [array] + +Default: `["node_modules"]` + +An array of directory names to be searched recursively up from the requiring +module's location. Setting this option will _override_ the default, if you wish +to still search `node_modules` for packages include it along with any other +options: `["node_modules", "bower_components"]` + +### `moduleNameMapper` [object] + +Default: `null` + +A map from regular expressions to module names that allow to stub out resources, +like images or styles with a single module. + +Modules that are mapped to an alias are unmocked by default, regardless of +whether automocking is enabled or not. + +Use `` string token to refer to [`rootDir`](#rootdir-string) value if +you want to use file paths. + +Additionally, you can substitute captured regex groups using numbered +backreferences. + +Example: + +```json +{ + "moduleNameMapper": { + "^image![a-zA-Z0-9$_-]+$": "GlobalImageStub", + "^[./a-zA-Z0-9$_-]+\\.png$": "/RelativeImageStub.js", + "module_name_(.*)": "/substituted_module_$1.js" + } +} +``` + +The order in which the mappings are defined matters. Patterns are checked one by +one until one fits. The most specific rule should be listed first. + +_Note: If you provide module name without boundaries `^$` it may cause hard to +spot errors. E.g. `relay` will replace all modules which contain `relay` as a +substring in its name: `relay`, `react-relay` and `graphql-relay` will all be +pointed to your stub._ + +### `modulePathIgnorePatterns` [array] + +Default: `[]` + +An array of regexp pattern strings that are matched against all module paths +before those paths are to be considered 'visible' to the module loader. If a +given module's path matches any of the patterns, it will not be `require()`-able +in the test environment. + +These pattern strings match against the full path. Use the `` string +token to include the path to your project's root directory to prevent it from +accidentally ignoring all of your files in different environments that may have +different root directories. Example: `["/build/"]`. + +### `modulePaths` [array] + +Default: `[]` + +An alternative API to setting the `NODE_PATH` env variable, `modulePaths` is an +array of absolute paths to additional locations to search when resolving +modules. Use the `` string token to include the path to your project's +root directory. Example: `["/app/"]`. + +### `notify` [boolean] + +Default: `false` + +Activates notifications for test results. + +### `notifyMode` [string] + +Default: `always` + +Specifies notification mode. Requires `notify: true`. + +#### Modes + +* `always`: always send a notification. +* `failure`: send a notification when tests fail. +* `success`: send a notification when tests pass. +* `change`: send a notification when the status changed. +* `success-change`: send a notification when tests pass or once when it fails. +* `failure-success`: send a notification when tests fails or once when it + passes. + +### `preset` [string] + +Default: `undefined` + +A preset that is used as a base for Jest's configuration. A preset should point +to an npm module that exports a `jest-preset.json` module on its top level. + +### `projects` [array] + +Default: `undefined` + +When the `projects` configuration is provided with an array of paths or glob +patterns, Jest will run tests in all of the specified projects at the same time. +This is great for monorepos or when working on multiple projects at the same +time. + +```json +{ + "projects": ["", "/examples/*"] +} +``` + +This example configuration will run Jest in the root directory as well as in +every folder in the examples directory. You can have an unlimited amount of +projects running in the same Jest instance. + +The projects feature can also be used to run multiple configurations or multiple +[runners](#runner-string). For this purpose you can pass an array of +configuration objects. For example, to run both tests and ESLint (via +[jest-runner-eslint](https://github.com/jest-community/jest-runner-eslint)) in +the same invocation of Jest: + +```json +{ + "projects": [ + { + "displayName": "test" + }, + { + "displayName": "lint", + "runner": "jest-runner-eslint", + "testMatch": ["/**/*.js"] + } + ] +} +``` + +### `clearMocks` [boolean] + +Default: `false` + +Automatically clear mock calls and instances between every test. Equivalent to +calling `jest.clearAllMocks()` between each test. This does not remove any mock +implementation that may have been provided. + +### `reporters` [array] + +Default: `undefined` + +##### available in Jest **20.0.0+** + +Use this configuration option to add custom reporters to Jest. A custom reporter +is a class that implements `onRunStart`, `onTestStart`, `onTestResult`, +`onRunComplete` methods that will be called when any of those events occurs. + +If custom reporters are specified, the default Jest reporters will be +overridden. To keep default reporters, `default` can be passed as a module name. + +This will override default reporters: + +```json +{ + "reporters": ["/my-custom-reporter.js"] +} +``` + +This will use custom reporter in addition to default reporters that Jest +provides: + +```json +{ + "reporters": ["default", "/my-custom-reporter.js"] +} +``` + +Additionally, custom reporters can be configured by passing an `options` object +as a second argument: + +```json +{ + "reporters": [ + "default", + ["/my-custom-reporter.js", {"banana": "yes", "pineapple": "no"}] + ] +} +``` + +Custom reporter modules must define a class that takes a `GlobalConfig` and +reporter options as constructor arguments: + +Example reporter: + +```js +// my-custom-reporter.js +class MyCustomReporter { + constructor(globalConfig, options) { + this._globalConfig = globalConfig; + this._options = options; + } + + onRunComplete(contexts, results) { + console.log('Custom reporter output:'); + console.log('GlobalConfig: ', this._globalConfig); + console.log('Options: ', this._options); + } +} + +module.exports = MyCustomReporter; +``` + +Custom reporters can also force Jest to exit with non-0 code by returning an +Error from `getLastError()` methods + +```js +class MyCustomReporter { + // ... + getLastError() { + if (this._shouldFail) { + return new Error('my-custom-reporter.js reported an error'); + } + } +} +``` + +For the full list of methods and argument types see `Reporter` type in +[types/TestRunner.js](https://github.com/facebook/jest/blob/master/types/TestRunner.js) + +### `resetMocks` [boolean] + +Default: `false` + +Automatically reset mock state between every test. Equivalent to calling +`jest.resetAllMocks()` between each test. This will lead to any mocks having +their fake implementations removed but does not restore their initial +implementation. + +### `resetModules` [boolean] + +Default: `false` + +If enabled, the module registry for every test file will be reset before running +each individual test. This is useful to isolate modules for every test so that +local module state doesn't conflict between tests. This can be done +programmatically using [`jest.resetModules()`](#jest-resetmodules). + +### `resolver` [string] + +Default: `undefined` + +##### available in Jest **20.0.0+** + +This option allows the use of a custom resolver. This resolver must be a node +module that exports a function expecting a string as the first argument for the +path to resolve and an object with the following structure as the second +argument: + +```json +{ + "basedir": string, + "browser": bool, + "extensions": [string], + "moduleDirectory": [string], + "paths": [string], + "rootDir": [string] +} +``` + +The function should either return a path to the module that should be resolved +or throw an error if the module can't be found. + +### `restoreMocks` [boolean] + +Default: `false` + +Automatically restore mock state between every test. Equivalent to calling +`jest.restoreAllMocks()` between each test. This will lead to any mocks having +their fake implementations removed and restores their initial implementation. + +### `rootDir` [string] + +Default: The root of the directory containing your jest's [config file](#) _or_ +the `package.json` _or_ the [`pwd`](http://en.wikipedia.org/wiki/Pwd) if no +`package.json` is found + +The root directory that Jest should scan for tests and modules within. If you +put your Jest config inside your `package.json` and want the root directory to +be the root of your repo, the value for this config param will default to the +directory of the `package.json`. + +Oftentimes, you'll want to set this to `'src'` or `'lib'`, corresponding to +where in your repository the code is stored. + +_Note that using `''` as a string token in any other path-based config +settings will refer back to this value. So, for example, if you want your +[`setupFiles`](#setupfiles-array) config entry to point at the `env-setup.js` +file at the root of your project, you could set its value to +`["/env-setup.js"]`._ + +### `roots` [array] + +Default: `[""]` + +A list of paths to directories that Jest should use to search for files in. + +There are times where you only want Jest to search in a single sub-directory +(such as cases where you have a `src/` directory in your repo), but prevent it +from accessing the rest of the repo. + +_Note: While `rootDir` is mostly used as a token to be re-used in other +configuration options, `roots` is used by the internals of Jest to locate **test +files and source files**. This applies also when searching for manual mocks for +modules from `node_modules` (`__mocks__` will need to live in one of the +`roots`)._ + +_Note: By default, `roots` has a single entry `` but there are cases +where you may want to have multiple roots within one project, for example +`roots: ["/src/", "/tests/"]`._ + +### `runner` [string] + +##### available in Jest **21.0.0+** + +Default: `"jest-runner"` + +This option allows you to use a custom runner instead of Jest's default test +runner. Examples of runners include: + +* [`jest-runner-eslint`](https://github.com/jest-community/jest-runner-eslint) +* [`jest-runner-mocha`](https://github.com/rogeliog/jest-runner-mocha) +* [`jest-runner-tsc`](https://github.com/azz/jest-runner-tsc) +* [`jest-runner-prettier`](https://github.com/keplersj/jest-runner-prettier) + +To write a test-runner, export a class with which accepts `globalConfig` in the +constructor, and has a `runTests` method with the signature: + +```ts +async runTests( + tests: Array, + watcher: TestWatcher, + onStart: OnTestStart, + onResult: OnTestSuccess, + onFailure: OnTestFailure, + options: TestRunnerOptions, +): Promise +``` + +### `setupFiles` [array] + +Default: `[]` + +The paths to modules that run some code to configure or set up the testing +environment before each test. Since every test runs in its own environment, +these scripts will be executed in the testing environment immediately before +executing the test code itself. + +It's worth noting that this code will execute _before_ +[`setupTestFrameworkScriptFile`](#setuptestframeworkscriptfile-string). + +### `setupTestFrameworkScriptFile` [string] + +Default: `undefined` + +The path to a module that runs some code to configure or set up the testing +framework before each test. Since [`setupFiles`](#setupfiles-array) executes +before the test framework is installed in the environment, this script file +presents you the opportunity of running some code immediately after the test +framework has been installed in the environment. + +For example, Jest ships with several plug-ins to `jasmine` that work by +monkey-patching the jasmine API. If you wanted to add even more jasmine plugins +to the mix (or if you wanted some custom, project-wide matchers for example), +you could do so in this module. + +### `snapshotSerializers` [array] + +Default: `[]` + +A list of paths to snapshot serializer modules Jest should use for snapshot +testing. + +Jest has default serializers for built-in JavaScript types, HTML elements (Jest +20.0.0+), ImmutableJS (Jest 20.0.0+) and for React elements. See +[snapshot test tutorial](TutorialReactNative.md#snapshot-test) for more +information. + +Example serializer module: + +```js +// my-serializer-module +module.exports = { + print(val, serialize, indent) { + return 'Pretty foo: ' + serialize(val.foo); + }, + + test(val) { + return val && val.hasOwnProperty('foo'); + }, +}; +``` + +`serialize` is a function that serializes a value using existing plugins. + +To use `my-serializer-module` as a serializer, configuration would be as +follows: + +```json +{ + ... + "jest": { + "snapshotSerializers": ["my-serializer-module"] + } +} +``` + +Finally tests would look as follows: + +```js +test(() => { + const bar = { + foo: { + x: 1, + y: 2, + }, + }; + + expect(bar).toMatchSnapshot(); +}); +``` + +Rendered snapshot: + +```json +Pretty foo: Object { + "x": 1, + "y": 2, +} +``` + +To make a dependency explicit instead of implicit, you can call +[`expect.addSnapshotSerializer`](ExpectAPI.md#expectaddsnapshotserializerserializer) +to add a module for an individual test file instead of adding its path to +`snapshotSerializers` in Jest configuration. + +### `testEnvironment` [string] + +Default: `"jsdom"` + +The test environment that will be used for testing. The default environment in +Jest is a browser-like environment through +[jsdom](https://github.com/tmpvar/jsdom). If you are building a node service, +you can use the `node` option to use a node-like environment instead. + +If some tests require another environment, you can add a `@jest-environment` +docblock. + +##### available in Jest **20.0.0+** + +```js +/** + * @jest-environment jsdom + */ + +test('use jsdom in this test file', () => { + const element = document.createElement('div'); + expect(element).not.toBeNull(); +}); +``` + +You can create your own module that will be used for setting up the test +environment. The module must export a class with `setup`, `teardown` and +`runScript` methods. You can also pass variables from this module to your test +suites by assigning them to `this.global` object – this will make them +available in your test suites as global variables. + +##### available in Jest **22.0.0+** + +_Note: TestEnvironment is sandboxed. Each test suite will trigger setup/teardown +in their own TestEnvironment._ + +Example: + +```js +// my-custom-environment +const NodeEnvironment = require('jest-environment-node'); + +class CustomEnvironment extends NodeEnvironment { + constructor(config) { + super(config); + } + + async setup() { + await super.setup(); + await someSetupTasks(); + this.global.someGlobalObject = createGlobalObject(); + } + + async teardown() { + this.global.someGlobalObject = destroyGlobalObject(); + await someTeardownTasks(); + await super.teardown(); + } + + runScript(script) { + return super.runScript(script); + } +} +``` + +```js +// my-test-suite +let someGlobalObject; + +beforeAll(() => { + someGlobalObject = global.someGlobalObject; +}); +``` + +### `testEnvironmentOptions` [Object] + +##### available in Jest **22.0.0+** + +Default: `{}` + +Test environment options that will be passed to the `testEnvironment`. The +relevant options depend on the environment. For example you can override options +given to [jsdom](https://github.com/tmpvar/jsdom) such as +`{userAgent: "Agent/007"}`. + +### `testMatch` [array] + +##### available in Jest **19.0.0+** + +(default: `[ '**/__tests__/**/*.js?(x)', '**/?(*.)(spec|test).js?(x)' ]`) + +The glob patterns Jest uses to detect test files. By default it looks for `.js` +and `.jsx` files inside of `__tests__` folders, as well as any files with a +suffix of `.test` or `.spec` (e.g. `Component.test.js` or `Component.spec.js`). +It will also find files called `test.js` or `spec.js`. + +See the [micromatch](https://github.com/jonschlinkert/micromatch) package for +details of the patterns you can specify. + +See also [`testRegex` [string]](#testregex-string), but note that you cannot +specify both options. + +### `testPathIgnorePatterns` [array] + +Default: `["/node_modules/"]` + +An array of regexp pattern strings that are matched against all test paths +before executing the test. If the test path matches any of the patterns, it will +be skipped. + +These pattern strings match against the full path. Use the `` string +token to include the path to your project's root directory to prevent it from +accidentally ignoring all of your files in different environments that may have +different root directories. Example: +`["/build/", "/node_modules/"]`. + +### `testRegex` [string] + +Default: `(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$` + +The pattern Jest uses to detect test files. By default it looks for `.js` and +`.jsx` files inside of `__tests__` folders, as well as any files with a suffix +of `.test` or `.spec` (e.g. `Component.test.js` or `Component.spec.js`). It will +also find files called `test.js` or `spec.js`. See also +[`testMatch` [array]](#testmatch-array-string), but note that you cannot +specify both options. + +The following is a visualization of the default regex: + +```bash +├── __tests__ +│ └── component.spec.js # test +│ └── anything # test +├── package.json # not test +├── foo.test.js # test +├── bar.spec.jsx # test +└── component.js # not test +``` + +### `testResultsProcessor` [string] + +Default: `undefined` + +This option allows the use of a custom results processor. This processor must be +a node module that exports a function expecting an object with the following +structure as the first argument and return it: + +```json +{ + "success": bool, + "startTime": epoch, + "numTotalTestSuites": number, + "numPassedTestSuites": number, + "numFailedTestSuites": number, + "numRuntimeErrorTestSuites": number, + "numTotalTests": number, + "numPassedTests": number, + "numFailedTests": number, + "numPendingTests": number, + "testResults": [{ + "numFailingTests": number, + "numPassingTests": number, + "numPendingTests": number, + "testResults": [{ + "title": string (message in it block), + "status": "failed" | "pending" | "passed", + "ancestorTitles": [string (message in describe blocks)], + "failureMessages": [string], + "numPassingAsserts": number, + "location": { + "column": number, + "line": number + } + }, + ... + ], + "perfStats": { + "start": epoch, + "end": epoch + }, + "testFilePath": absolute path to test file, + "coverage": {} + }, + ... + ] +} +``` + +### `testRunner` [string] + +Default: `jasmine2` + +This option allows use of a custom test runner. The default is jasmine2. A +custom test runner can be provided by specifying a path to a test runner +implementation. + +The test runner module must export a function with the following signature: + +```ts +function testRunner( + config: Config, + environment: Environment, + runtime: Runtime, + testPath: string, +): Promise; +``` + +An example of such function can be found in our default +[jasmine2 test runner package](https://github.com/facebook/jest/blob/master/packages/jest-jasmine2/src/index.js). + +### `testURL` [string] + +Default: `about:blank` + +This option sets the URL for the jsdom environment. It is reflected in +properties such as `location.href`. + +### `timers` [string] + +Default: `real` + +Setting this value to `fake` allows the use of fake timers for functions such as +`setTimeout`. Fake timers are useful when a piece of code sets a long timeout +that we don't want to wait for in a test. + +### `transform` [object] + +Default: `undefined` + +A map from regular expressions to paths to transformers. A transformer is a +module that provides a synchronous function for transforming source files. For +example, if you wanted to be able to use a new language feature in your modules +or tests that isn't yet supported by node, you might plug in one of many +compilers that compile a future version of JavaScript to a current one. Example: +see the +[examples/typescript](https://github.com/facebook/jest/blob/master/examples/typescript/package.json#L16) +example or the [webpack tutorial](Webpack.md). + +Examples of such compilers include [Babel](https://babeljs.io/), +[TypeScript](http://www.typescriptlang.org/) and +[async-to-gen](http://github.com/leebyron/async-to-gen#jest). + +_Note: a transformer is only ran once per file unless the file has changed. +During development of a transformer it can be useful to run Jest with +`--no-cache` to frequently +[delete Jest's cache](Troubleshooting.md#caching-issues)._ + +_Note: if you are using the `babel-jest` transformer and want to use an +additional code preprocessor, keep in mind that when "transform" is overwritten +in any way the `babel-jest` is not loaded automatically anymore. If you want to +use it to compile JavaScript code it has to be explicitly defined. See +[babel-jest plugin](https://github.com/facebook/jest/tree/master/packages/babel-jest#setup)_ + +### `transformIgnorePatterns` [array] + +Default: `["/node_modules/"]` + +An array of regexp pattern strings that are matched against all source file +paths before transformation. If the test path matches any of the patterns, it +will not be transformed. + +These pattern strings match against the full path. Use the `` string +token to include the path to your project's root directory to prevent it from +accidentally ignoring all of your files in different environments that may have +different root directories. + +Example: `["/bower_components/", "/node_modules/"]`. + +Sometimes it happens (especially in React Native or TypeScript projects) that +3rd party modules are published as untranspiled. Since all files inside +`node_modules` are not transformed by default, Jest will not understand the code +in these modules, resulting in syntax errors. To overcome this, you may use +`transformIgnorePatterns` to whitelist such modules. You'll find a good example +of this use case in +[React Native Guide](http://facebook.github.io/jest/docs/en/tutorial-react-native.html#transformignorepatterns-customization). + +### `unmockedModulePathPatterns` [array] + +Default: `[]` + +An array of regexp pattern strings that are matched against all modules before +the module loader will automatically return a mock for them. If a module's path +matches any of the patterns in this list, it will not be automatically mocked by +the module loader. + +This is useful for some commonly used 'utility' modules that are almost always +used as implementation details almost all the time (like underscore/lo-dash, +etc). It's generally a best practice to keep this list as small as possible and +always use explicit `jest.mock()`/`jest.unmock()` calls in individual tests. +Explicit per-test setup is far easier for other readers of the test to reason +about the environment the test will run in. + +It is possible to override this setting in individual tests by explicitly +calling `jest.mock()` at the top of the test file. + +### `verbose` [boolean] + +Default: `false` + +Indicates whether each individual test should be reported during the run. All +errors will also still be shown on the bottom after execution. + +### `watchPathIgnorePatterns` [array] + +Default: `[]` + +##### available in Jest **21.0.0+** + +An array of RegExp patterns that are matched against all source file paths +before re-running tests in watch mode. If the file path matches any of the +patterns, when it is updated, it will not trigger a re-run of tests. + +These patterns match against the full path. Use the `` string token to +include the path to your project's root directory to prevent it from +accidentally ignoring all of your files in different environments that may have +different root directories. Example: `["/node_modules/"]`. diff --git a/website/versioned_docs/version-22.3/Es6ClassMocks.md b/website/versioned_docs/version-22.3/Es6ClassMocks.md new file mode 100644 index 000000000000..18e2008eb188 --- /dev/null +++ b/website/versioned_docs/version-22.3/Es6ClassMocks.md @@ -0,0 +1,392 @@ +--- +id: version-22.3-es6-class-mocks +title: ES6 Class Mocks +original_id: es6-class-mocks +--- + +Jest can be used to mock ES6 classes that are imported into files you want to +test. + +ES6 classes are constructor functions with some syntactic sugar. Therefore, any +mock for an ES6 class must be a function or an actual ES6 class (which is, +again, another function). So you can mock them using +[mock functions](MockFunctions.md). + +## An ES6 Class Example + +We'll use a contrived example of a class that plays sound files, `SoundPlayer`, +and a consumer class which uses that class, `SoundPlayerConsumer`. We'll mock +`SoundPlayer` in our tests for `SoundPlayerConsumer`. + +```javascript +// sound-player.js +export default class SoundPlayer { + constructor() { + this.foo = 'bar'; + } + + playSoundFile(fileName) { + console.log('Playing sound file ' + fileName); + } +} +``` + +```javascript +// sound-player-consumer.js +import SoundPlayer from './sound-player'; + +export default class SoundPlayerConsumer { + constructor() { + this.soundPlayer = new SoundPlayer(); + } + + playSomethingCool() { + const coolSoundFileName = 'song.mp3'; + this.soundPlayer.playSoundFile(coolSoundFileName); + } +} +``` + +## The 4 ways to create an ES6 class mock + +### Automatic mock + +Calling `jest.mock('./sound-player')` returns a useful "automatic mock" you can +use to spy on calls to the class constructor and all of its methods. It replaces +the ES6 class with a mock constructor, and replaces all of its methods with +[mock functions](MockFunctions.md) that always return `undefined`. Method calls +are saved in `theAutomaticMock.mock.instances[index].methodName.mock.calls`. + +If you don't need to replace the implementation of the class, this is the +easiest option to set up. For example: + +```javascript +import SoundPlayer from './sound-player'; +import SoundPlayerConsumer from './sound-player-consumer'; +jest.mock('./sound-player'); // SoundPlayer is now a mock constructor + +beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + SoundPlayer.mockClear(); +}); + +it('We can check if the consumer called the class constructor', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + // Show that mockClear() is working: + expect(SoundPlayer).not.toHaveBeenCalled(); + + const soundPlayerConsumer = new SoundPlayerConsumer(); + // Constructor should have been called again: + expect(SoundPlayer).toHaveBeenCalledTimes(1); + + const coolSoundFileName = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + + // mock.instances is available with automatic mocks: + const mockSoundPlayerInstance = SoundPlayer.mock.instances[0]; + const mockPlaySoundFile = mockSoundPlayerInstance.playSoundFile; + expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); + // Equivalent to above check: + expect(mockPlaySoundFile).toHaveBeenCalledWith(coolSoundFileName); + expect(mockPlaySoundFile).toHaveBeenCalledTimes(1); +}); +``` + +### Manual mock + +Create a [manual mock](ManualMocks.md) by saving a mock implementation in the +`__mocks__` folder. This allows you to specify the implementation, and it can be +used across test files. + +```javascript +// __mocks__/sound-player.js + +// Import this named export into your test file: +export const mockPlaySoundFile = jest.fn(); +const mock = jest.fn().mockImplementation(() => { + return {playSoundFile: mockPlaySoundFile}; +}); + +export default mock; +``` + +Import the mock and the mock method shared by all instances: + +```javascript +// sound-player-consumer.test.js +import SoundPlayer, {mockPlaySoundFile} from './sound-player'; +import SoundPlayerConsumer from './sound-player-consumer'; +jest.mock('./sound-player'); // SoundPlayer is now a mock constructor + +beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + SoundPlayer.mockClear(); + mockPlaySoundFile.mockClear(); +}); + +it('We can check if the consumer called the class constructor', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + const coolSoundFileName = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + expect(mockPlaySoundFile).toHaveBeenCalledWith(coolSoundFileName); +}); +``` + +### Calling [`jest.mock()`](JestObjectAPI.md#jestmockmodulename-factory-options) with the module factory parameter + +`jest.mock(path, moduleFactory)` takes a **module factory** argument. A module +factory is a function that returns the mock. + +In order to mock a constructor function, the module factory must return a +constructor function. In other words, the module factory must be a function that +returns a function - a higher-order function (HOF). + +```javascript +import SoundPlayer from './sound-player'; +const mockPlaySoundFile = jest.fn(); +jest.mock('./sound-player', () => { + return jest.fn().mockImplementation(() => { + return {playSoundFile: mockPlaySoundFile}; + }); +}); +``` + +A limitation with the factory parameter is that, since calls to `jest.mock()` +are hoisted to the top of the file, it's not possible to first define a variable +and then use it in the factory. An exception is made for variables that start +with the word 'mock'. It's up to you to guarantee that they will be initialized +on time! + +### Replacing the mock using [`mockImplementation()`](MockFunctionAPI.md#mockfnmockimplementationfn) or [`mockImplementationOnce()`](MockFunctionAPI.md#mockfnmockimplementationoncefn) + +You can replace all of the above mocks in order to change the implementation, +for a single test or all tests, by calling `mockImplementation()` on the +existing mock. + +Calls to jest.mock are hoisted to the top of the code. You can specify a mock +later, e.g. in `beforeAll()`, by calling `mockImplementation()` (or +`mockImplementationOnce()`) on the existing mock instead of using the factory +parameter. This also allows you to change the mock between tests, if needed: + +```javascript +import SoundPlayer from './sound-player'; +jest.mock('./sound-player'); + +describe('When SoundPlayer throws an error', () => { + beforeAll(() => { + SoundPlayer.mockImplementation(() => { + return { + playSoundFile: () => { + throw new Error('Test error'); + }, + }; + }); + }); + + it('Should throw an error when calling playSomethingCool', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + expect(() => soundPlayerConsumer.playSomethingCool()).toThrow(); + }); +}); +``` + +## In depth: Understanding mock constructor functions + +Building your constructor function mock using `jest.fn().mockImplementation()` +makes mocks appear more complicated than they really are. This section shows how +you can create your own simple mocks to illustrate how mocking works. + +### Manual mock that is another ES6 class + +If you define an ES6 class using the same filename as the mocked class in the +`__mocks__` folder, it will serve as the mock. This class will be used in place +of the real class. This allows you to inject a test implementation for the +class, but does not provide a way to spy on calls. + +For the contrived example, the mock might look like this: + +```javascript +// __mocks/sound-player.js +export default class SoundPlayer { + constructor() { + console.log('Mock SoundPlayer: constructor was called'); + } + + playSoundFile() { + console.log('Mock SoundPlayer: playSoundFile was called'); + } +} +``` + +### Simple mock using module factory parameter + +The module factory function passed to `jest.mock(path, moduleFactory)` can be a +HOF that returns a function\*. This will allow calling `new` on the mock. Again, +this allows you to inject different behavior for testing, but does not provide a +way to spy on calls. + +#### \* Module factory function must return a function + +In order to mock a constructor function, the module factory must return a +constructor function. In other words, the module factory must be a function that +returns a function - a higher-order function (HOF). + +```javascript +jest.mock('./sound-player', () => { + return function() { + return {playSoundFile: () => {}}; + }; +}); +``` + +**_Note: Arrow functions won't work_** + +Note that the mock can't be an arrow function because calling `new` on an arrow +function is not allowed in Javascript. So this won't work: + +```javascript +jest.mock('./sound-player', () => { + return () => { + // Does not work; arrow functions can't be called with new + return {playSoundFile: () => {}}; + }; +}); +``` + +This will throw **_TypeError: \_soundPlayer2.default is not a constructor_**, +unless the code is transpiled to ES5, e.g. by babel-preset-env. (ES5 doesn't +have arrow functions nor classes, so both will be transpiled to plain +functions.) + +## Keeping track of usage (spying on the mock) + +Injecting a test implementation is helpful, but you will probably also want to +test whether the class constructor and methods are called with the correct +parameters. + +### Spying on the constructor + +In order to track calls to the constructor, replace the function returned by the +HOF with a Jest mock function. Create it with +[`jest.fn()`](JestObjectAPI.md#jestfnimplementation), and then specify its +implementation with `mockImplementation()`. + +```javascript +import SoundPlayer from './sound-player'; +jest.mock('./sound-player', () => { + // Works and lets you check for constructor calls: + return jest.fn().mockImplementation(() => { + return {playSoundFile: () => {}}; + }); +}); +``` + +This will let us inspect usage of our mocked class, using +`SoundPlayer.mock.calls`: `expect(SoundPlayer).toHaveBeenCalled();` or +near-equivalent: `expect(SoundPlayer.mock.calls.length).toEqual(1);` + +### Spying on methods of our class + +Our mocked class will need to provide any member functions (`playSoundFile` in +the example) that will be called during our tests, or else we'll get an error +for calling a function that doesn't exist. But we'll probably want to also spy +on calls to those methods, to ensure that they were called with the expected +parameters. + +A new object will be created each time the mock constructor function is called +during tests. To spy on method calls in all of these objects, we populate +`playSoundFile` with another mock function, and store a reference to that same +mock function in our test file, so it's available during tests. + +```javascript +import SoundPlayer from './sound-player'; +const mockPlaySoundFile = jest.fn(); +jest.mock('./sound-player', () => { + return jest.fn().mockImplementation(() => { + return {playSoundFile: mockPlaySoundFile}; + // Now we can track calls to playSoundFile + }); +}); +``` + +The manual mock equivalent of this would be: + +```javascript +// __mocks__/sound-player.js + +// Import this named export into your test file +export const mockPlaySoundFile = jest.fn(); +const mock = jest.fn().mockImplementation(() => { + return {playSoundFile: mockPlaySoundFile}; +}); + +export default mock; +``` + +Usage is similar to the module factory function, except that you can omit the +second argument from `jest.mock()`, and you must import the mocked method into +your test file, since it is no longer defined there. Use the original module +path for this; don't include `__mocks__`. + +### Cleaning up between tests + +To clear the record of calls to the mock constructor function and its methods, +we call [`mockClear()`](MockFunctionAPI.md#mockfnmockclear) in the +`beforeEach()` function: + +```javascript +beforeEach(() => { + SoundPlayer.mockClear(); + mockPlaySoundFile.mockClear(); +}); +``` + +## Complete example + +Here's a complete test file which uses the module factory parameter to +`jest.mock`: + +```javascript +// sound-player-consumer.test.js +import SoundPlayerConsumer from './sound-player-consumer'; +import SoundPlayer from './sound-player'; + +const mockPlaySoundFile = jest.fn(); +jest.mock('./sound-player', () => { + return jest.fn().mockImplementation(() => { + return {playSoundFile: mockPlaySoundFile}; + }); +}); + +beforeEach(() => { + SoundPlayer.mockClear(); + mockPlaySoundFile.mockClear(); +}); + +it('The consumer should be able to call new() on SoundPlayer', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + // Ensure constructor created the object: + expect(soundPlayerConsumer).toBeTruthy(); +}); + +it('We can check if the consumer called the class constructor', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + const coolSoundFileName = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); +}); +``` diff --git a/website/versioned_docs/version-22.3/ExpectAPI.md b/website/versioned_docs/version-22.3/ExpectAPI.md new file mode 100644 index 000000000000..3985db9a85f2 --- /dev/null +++ b/website/versioned_docs/version-22.3/ExpectAPI.md @@ -0,0 +1,1060 @@ +--- +id: version-22.3-expect +title: Expect +original_id: expect +--- + +When you're writing tests, you often need to check that values meet certain +conditions. `expect` gives you access to a number of "matchers" that let you +validate different things. + +## Methods + + + +--- + +## Reference + +### `expect(value)` + +The `expect` function is used every time you want to test a value. You will +rarely call `expect` by itself. Instead, you will use `expect` along with a +"matcher" function to assert something about a value. + +It's easier to understand this with an example. Let's say you have a method +`bestLaCroixFlavor()` which is supposed to return the string `'grapefruit'`. +Here's how you would test that: + +```js +test('the best flavor is grapefruit', () => { + expect(bestLaCroixFlavor()).toBe('grapefruit'); +}); +``` + +In this case, `toBe` is the matcher function. There are a lot of different +matcher functions, documented below, to help you test different things. + +The argument to `expect` should be the value that your code produces, and any +argument to the matcher should be the correct value. If you mix them up, your +tests will still work, but the error messages on failing tests will look +strange. + +### `expect.extend(matchers)` + +You can use `expect.extend` to add your own matchers to Jest. For example, let's +say that you're testing a number theory library and you're frequently asserting +that numbers are divisible by other numbers. You could abstract that into a +`toBeDivisibleBy` matcher: + +```js +expect.extend({ + toBeDivisibleBy(received, argument) { + const pass = received % argument == 0; + if (pass) { + return { + message: () => + `expected ${received} not to be divisible by ${argument}`, + pass: true, + }; + } else { + return { + message: () => `expected ${received} to be divisible by ${argument}`, + pass: false, + }; + } + }, +}); + +test('even and odd numbers', () => { + expect(100).toBeDivisibleBy(2); + expect(101).not.toBeDivisibleBy(2); +}); +``` + +Matchers should return an object with two keys. `pass` indicates whether there +was a match or not, and `message` provides a function with no arguments that +returns an error message in case of failure. Thus, when `pass` is false, +`message` should return the error message for when `expect(x).yourMatcher()` +fails. And when `pass` is true, `message` should return the error message for +when `expect(x).not.yourMatcher()` fails. + +These helper functions can be found on `this` inside a custom matcher: + +#### `this.isNot` + +A boolean to let you know this matcher was called with the negated `.not` +modifier allowing you to flip your assertion. + +#### `this.equals(a, b)` + +This is a deep-equality function that will return `true` if two objects have the +same values (recursively). + +#### `this.utils` + +There are a number of helpful tools exposed on `this.utils` primarily consisting +of the exports from +[`jest-matcher-utils`](https://github.com/facebook/jest/tree/master/packages/jest-matcher-utils). + +The most useful ones are `matcherHint`, `printExpected` and `printReceived` to +format the error messages nicely. For example, take a look at the implementation +for the `toBe` matcher: + +```js +const diff = require('jest-diff'); +expect.extend({ + toBe(received, expected) { + const pass = Object.is(received, expected); + + const message = pass + ? () => + this.utils.matcherHint('.not.toBe') + + '\n\n' + + `Expected value to not be (using Object.is):\n` + + ` ${this.utils.printExpected(expected)}\n` + + `Received:\n` + + ` ${this.utils.printReceived(received)}` + : () => { + const diffString = diff(expected, received, { + expand: this.expand, + }); + return ( + this.utils.matcherHint('.toBe') + + '\n\n' + + `Expected value to be (using Object.is):\n` + + ` ${this.utils.printExpected(expected)}\n` + + `Received:\n` + + ` ${this.utils.printReceived(received)}` + + (diffString ? `\n\nDifference:\n\n${diffString}` : '') + ); + }; + + return {actual: received, message, pass}; + }, +}); +``` + +This will print something like this: + +```bash + expect(received).toBe(expected) + + Expected value to be (using Object.is): + "banana" + Received: + "apple" +``` + +When an assertion fails, the error message should give as much signal as +necessary to the user so they can resolve their issue quickly. You should craft +a precise failure message to make sure users of your custom assertions have a +good developer experience. + +### `expect.anything()` + +`expect.anything()` matches anything but `null` or `undefined`. You can use it +inside `toEqual` or `toBeCalledWith` instead of a literal value. For example, if +you want to check that a mock function is called with a non-null argument: + +```js +test('map calls its argument with a non-null argument', () => { + const mock = jest.fn(); + [1].map(x => mock(x)); + expect(mock).toBeCalledWith(expect.anything()); +}); +``` + +### `expect.any(constructor)` + +`expect.any(constructor)` matches anything that was created with the given +constructor. You can use it inside `toEqual` or `toBeCalledWith` instead of a +literal value. For example, if you want to check that a mock function is called +with a number: + +```js +function randocall(fn) { + return fn(Math.floor(Math.random() * 6 + 1)); +} + +test('randocall calls its callback with a number', () => { + const mock = jest.fn(); + randocall(mock); + expect(mock).toBeCalledWith(expect.any(Number)); +}); +``` + +### `expect.arrayContaining(array)` + +`expect.arrayContaining(array)` matches a received array which contains all of +the elements in the expected array. That is, the expected array is a **subset** +of the received array. Therefore, it matches a received array which contains +elements that are **not** in the expected array. + +You can use it instead of a literal value: + +* in `toEqual` or `toBeCalledWith` +* to match a property in `objectContaining` or `toMatchObject` + +```js +describe('arrayContaining', () => { + const expected = ['Alice', 'Bob']; + it('matches even if received contains additional elements', () => { + expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected)); + }); + it('does not match if received does not contain expected elements', () => { + expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected)); + }); +}); +``` + +```js +describe('Beware of a misunderstanding! A sequence of dice rolls', () => { + const expected = [1, 2, 3, 4, 5, 6]; + it('matches even with an unexpected number 7', () => { + expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual( + expect.arrayContaining(expected), + ); + }); + it('does not match without an expected number 2', () => { + expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual( + expect.arrayContaining(expected), + ); + }); +}); +``` + +### `expect.assertions(number)` + +`expect.assertions(number)` verifies that a certain number of assertions are +called during a test. This is often useful when testing asynchronous code, in +order to make sure that assertions in a callback actually got called. + +For example, let's say that we have a function `doAsync` that receives two +callbacks `callback1` and `callback2`, it will asynchronously call both of them +in an unknown order. We can test this with: + +```js +test('doAsync calls both callbacks', () => { + expect.assertions(2); + function callback1(data) { + expect(data).toBeTruthy(); + } + function callback2(data) { + expect(data).toBeTruthy(); + } + + doAsync(callback1, callback2); +}); +``` + +The `expect.assertions(2)` call ensures that both callbacks actually get called. + +### `expect.hasAssertions()` + +`expect.hasAssertions()` verifies that at least one assertion is called during a +test. This is often useful when testing asynchronous code, in order to make sure +that assertions in a callback actually got called. + +For example, let's say that we have a few functions that all deal with state. +`prepareState` calls a callback with a state object, `validateState` runs on +that state object, and `waitOnState` returns a promise that waits until all +`prepareState` callbacks complete. We can test this with: + +```js +test('prepareState prepares a valid state', () => { + expect.hasAssertions(); + prepareState(state => { + expect(validateState(state)).toBeTruthy(); + }); + return waitOnState(); +}); +``` + +The `expect.hasAssertions()` call ensures that the `prepareState` callback +actually gets called. + +### `expect.objectContaining(object)` + +`expect.objectContaining(object)` matches any received object that recursively +matches the expected properties. That is, the expected object is a **subset** of +the received object. Therefore, it matches a received object which contains +properties that are **not** in the expected object. + +Instead of literal property values in the expected object, you can use matchers, +`expect.anything()`, and so on. + +For example, let's say that we expect an `onPress` function to be called with an +`Event` object, and all we need to verify is that the event has `event.x` and +`event.y` properties. We can do that with: + +```js +test('onPress gets called with the right thing', () => { + const onPress = jest.fn(); + simulatePresses(onPress); + expect(onPress).toBeCalledWith( + expect.objectContaining({ + x: expect.any(Number), + y: expect.any(Number), + }), + ); +}); +``` + +### `expect.stringContaining(string)` + +##### available in Jest **19.0.0+** + +`expect.stringContaining(string)` matches any received string that contains the +exact expected string. + +### `expect.stringMatching(regexp)` + +`expect.stringMatching(regexp)` matches any received string that matches the +expected regexp. + +You can use it instead of a literal value: + +* in `toEqual` or `toBeCalledWith` +* to match an element in `arrayContaining` +* to match a property in `objectContaining` or `toMatchObject` + +This example also shows how you can nest multiple asymmetric matchers, with +`expect.stringMatching` inside the `expect.arrayContaining`. + +```js +describe('stringMatching in arrayContaining', () => { + const expected = [ + expect.stringMatching(/^Alic/), + expect.stringMatching(/^[BR]ob/), + ]; + it('matches even if received contains additional elements', () => { + expect(['Alicia', 'Roberto', 'Evelina']).toEqual( + expect.arrayContaining(expected), + ); + }); + it('does not match if received does not contain expected elements', () => { + expect(['Roberto', 'Evelina']).not.toEqual( + expect.arrayContaining(expected), + ); + }); +}); +``` + +### `expect.addSnapshotSerializer(serializer)` + +You can call `expect.addSnapshotSerializer` to add a module that formats +application-specific data structures. + +For an individual test file, an added module precedes any modules from +`snapshotSerializers` configuration, which precede the default snapshot +serializers for built-in JavaScript types and for React elements. The last +module added is the first module tested. + +```js +import serializer from 'my-serializer-module'; +expect.addSnapshotSerializer(serializer); + +// affects expect(value).toMatchSnapshot() assertions in the test file +``` + +If you add a snapshot serializer in individual test files instead of to adding +it to `snapshotSerializers` configuration: + +* You make the dependency explicit instead of implicit. +* You avoid limits to configuration that might cause you to eject from + [create-react-app](https://github.com/facebookincubator/create-react-app). + +See [configuring Jest](Configuration.md#snapshotserializers-array-string) for +more information. + +### `.not` + +If you know how to test something, `.not` lets you test its opposite. For +example, this code tests that the best La Croix flavor is not coconut: + +```js +test('the best flavor is not coconut', () => { + expect(bestLaCroixFlavor()).not.toBe('coconut'); +}); +``` + +### `.resolves` + +##### available in Jest **20.0.0+** + +Use `resolves` to unwrap the value of a fulfilled promise so any other matcher +can be chained. If the promise is rejected the assertion fails. + +For example, this code tests that the promise resolves and that the resulting +value is `'lemon'`: + +```js +test('resolves to lemon', () => { + // make sure to add a return statement + return expect(Promise.resolve('lemon')).resolves.toBe('lemon'); +}); +``` + +Note that, since you are still testing promises, the test is still asynchronous. +Hence, you will need to [tell Jest to wait](TestingAsyncCode.md#promises) by +returning the unwrapped assertion. + +Alternatively, you can use `async/await` in combination with `.resolves`: + +```js +test('resolves to lemon', async () => { + await expect(Promise.resolve('lemon')).resolves.toBe('lemon'); + await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus'); +}); +``` + +### `.rejects` + +##### available in Jest **20.0.0+** + +Use `.rejects` to unwrap the reason of a rejected promise so any other matcher +can be chained. If the promise is fulfilled the assertion fails. + +For example, this code tests that the promise rejects with reason `'octopus'`: + +```js +test('rejects to octopus', () => { + // make sure to add a return statement + return expect(Promise.reject(new Error('octopus'))).rejects.toThrow( + 'octopus', + ); +}); +``` + +Note that, since you are still testing promises, the test is still asynchronous. +Hence, you will need to [tell Jest to wait](TestingAsyncCode.md#promises) by +returning the unwrapped assertion. + +Alternatively, you can use `async/await` in combination with `.rejects`. + +```js +test('rejects to octopus', async () => { + await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus'); +}); +``` + +### `.toBe(value)` + +`toBe` just checks that a value is what you expect. It uses `Object.is` to check +exact equality. + +For example, this code will validate some properties of the `can` object: + +```js +const can = { + name: 'pamplemousse', + ounces: 12, +}; + +describe('the can', () => { + test('has 12 ounces', () => { + expect(can.ounces).toBe(12); + }); + + test('has a sophisticated name', () => { + expect(can.name).toBe('pamplemousse'); + }); +}); +``` + +Don't use `toBe` with floating-point numbers. For example, due to rounding, in +JavaScript `0.2 + 0.1` is not strictly equal to `0.3`. If you have floating +point numbers, try `.toBeCloseTo` instead. + +### `.toHaveBeenCalled()` + +Also under the alias: `.toBeCalled()` + +Use `.toHaveBeenCalled` to ensure that a mock function got called. + +For example, let's say you have a `drinkAll(drink, flavor)` function that takes +a `drink` function and applies it to all available beverages. You might want to +check that `drink` gets called for `'lemon'`, but not for `'octopus'`, because +`'octopus'` flavor is really weird and why would anything be octopus-flavored? +You can do that with this test suite: + +```js +describe('drinkAll', () => { + test('drinks something lemon-flavored', () => { + const drink = jest.fn(); + drinkAll(drink, 'lemon'); + expect(drink).toHaveBeenCalled(); + }); + + test('does not drink something octopus-flavored', () => { + const drink = jest.fn(); + drinkAll(drink, 'octopus'); + expect(drink).not.toHaveBeenCalled(); + }); +}); +``` + +### `.toHaveBeenCalledTimes(number)` + +Use `.toHaveBeenCalledTimes` to ensure that a mock function got called exact +number of times. + +For example, let's say you have a `drinkEach(drink, Array)` function +that takes a `drink` function and applies it to array of passed beverages. You +might want to check that drink function was called exact number of times. You +can do that with this test suite: + +```js +test('drinkEach drinks each drink', () => { + const drink = jest.fn(); + drinkEach(drink, ['lemon', 'octopus']); + expect(drink).toHaveBeenCalledTimes(2); +}); +``` + +### `.toHaveBeenCalledWith(arg1, arg2, ...)` + +Also under the alias: `.toBeCalledWith()` + +Use `.toHaveBeenCalledWith` to ensure that a mock function was called with +specific arguments. + +For example, let's say that you can register a beverage with a `register` +function, and `applyToAll(f)` should apply the function `f` to all registered +beverages. To make sure this works, you could write: + +```js +test('registration applies correctly to orange La Croix', () => { + const beverage = new LaCroix('orange'); + register(beverage); + const f = jest.fn(); + applyToAll(f); + expect(f).toHaveBeenCalledWith(beverage); +}); +``` + +### `.toHaveBeenLastCalledWith(arg1, arg2, ...)` + +Also under the alias: `.lastCalledWith(arg1, arg2, ...)` + +If you have a mock function, you can use `.toHaveBeenLastCalledWith` to test +what arguments it was last called with. For example, let's say you have a +`applyToAllFlavors(f)` function that applies `f` to a bunch of flavors, and you +want to ensure that when you call it, the last flavor it operates on is +`'mango'`. You can write: + +```js +test('applying to all flavors does mango last', () => { + const drink = jest.fn(); + applyToAllFlavors(drink); + expect(drink).toHaveBeenLastCalledWith('mango'); +}); +``` + +### `.toBeCloseTo(number, numDigits)` + +Using exact equality with floating point numbers is a bad idea. Rounding means +that intuitive things fail. For example, this test fails: + +```js +test('adding works sanely with simple decimals', () => { + expect(0.2 + 0.1).toBe(0.3); // Fails! +}); +``` + +It fails because in JavaScript, `0.2 + 0.1` is actually `0.30000000000000004`. +Sorry. + +Instead, use `.toBeCloseTo`. Use `numDigits` to control how many digits after +the decimal point to check. For example, if you want to be sure that `0.2 + 0.1` +is equal to `0.3` with a precision of 5 decimal digits, you can use this test: + +```js +test('adding works sanely with simple decimals', () => { + expect(0.2 + 0.1).toBeCloseTo(0.3, 5); +}); +``` + +The default for `numDigits` is 2, which has proved to be a good default in most +cases. + +### `.toBeDefined()` + +Use `.toBeDefined` to check that a variable is not undefined. For example, if +you just want to check that a function `fetchNewFlavorIdea()` returns +_something_, you can write: + +```js +test('there is a new flavor idea', () => { + expect(fetchNewFlavorIdea()).toBeDefined(); +}); +``` + +You could write `expect(fetchNewFlavorIdea()).not.toBe(undefined)`, but it's +better practice to avoid referring to `undefined` directly in your code. + +### `.toBeFalsy()` + +Use `.toBeFalsy` when you don't care what a value is, you just want to ensure a +value is false in a boolean context. For example, let's say you have some +application code that looks like: + +```js +drinkSomeLaCroix(); +if (!getErrors()) { + drinkMoreLaCroix(); +} +``` + +You may not care what `getErrors` returns, specifically - it might return +`false`, `null`, or `0`, and your code would still work. So if you want to test +there are no errors after drinking some La Croix, you could write: + +```js +test('drinking La Croix does not lead to errors', () => { + drinkSomeLaCroix(); + expect(getErrors()).toBeFalsy(); +}); +``` + +In JavaScript, there are six falsy values: `false`, `0`, `''`, `null`, +`undefined`, and `NaN`. Everything else is truthy. + +### `.toBeGreaterThan(number)` + +To compare floating point numbers, you can use `toBeGreaterThan`. For example, +if you want to test that `ouncesPerCan()` returns a value of more than 10 +ounces, write: + +```js +test('ounces per can is more than 10', () => { + expect(ouncesPerCan()).toBeGreaterThan(10); +}); +``` + +### `.toBeGreaterThanOrEqual(number)` + +To compare floating point numbers, you can use `toBeGreaterThanOrEqual`. For +example, if you want to test that `ouncesPerCan()` returns a value of at least +12 ounces, write: + +```js +test('ounces per can is at least 12', () => { + expect(ouncesPerCan()).toBeGreaterThanOrEqual(12); +}); +``` + +### `.toBeLessThan(number)` + +To compare floating point numbers, you can use `toBeLessThan`. For example, if +you want to test that `ouncesPerCan()` returns a value of less than 20 ounces, +write: + +```js +test('ounces per can is less than 20', () => { + expect(ouncesPerCan()).toBeLessThan(20); +}); +``` + +### `.toBeLessThanOrEqual(number)` + +To compare floating point numbers, you can use `toBeLessThanOrEqual`. For +example, if you want to test that `ouncesPerCan()` returns a value of at most 12 +ounces, write: + +```js +test('ounces per can is at most 12', () => { + expect(ouncesPerCan()).toBeLessThanOrEqual(12); +}); +``` + +### `.toBeInstanceOf(Class)` + +Use `.toBeInstanceOf(Class)` to check that an object is an instance of a class. +This matcher uses `instanceof` underneath. + +```js +class A {} + +expect(new A()).toBeInstanceOf(A); +expect(() => {}).toBeInstanceOf(Function); +expect(new A()).toBeInstanceOf(Function); // throws +``` + +### `.toBeNull()` + +`.toBeNull()` is the same as `.toBe(null)` but the error messages are a bit +nicer. So use `.toBeNull()` when you want to check that something is null. + +```js +function bloop() { + return null; +} + +test('bloop returns null', () => { + expect(bloop()).toBeNull(); +}); +``` + +### `.toBeTruthy()` + +Use `.toBeTruthy` when you don't care what a value is, you just want to ensure a +value is true in a boolean context. For example, let's say you have some +application code that looks like: + +```js +drinkSomeLaCroix(); +if (thirstInfo()) { + drinkMoreLaCroix(); +} +``` + +You may not care what `thirstInfo` returns, specifically - it might return +`true` or a complex object, and your code would still work. So if you just want +to test that `thirstInfo` will be truthy after drinking some La Croix, you could +write: + +```js +test('drinking La Croix leads to having thirst info', () => { + drinkSomeLaCroix(); + expect(thirstInfo()).toBeTruthy(); +}); +``` + +In JavaScript, there are six falsy values: `false`, `0`, `''`, `null`, +`undefined`, and `NaN`. Everything else is truthy. + +### `.toBeUndefined()` + +Use `.toBeUndefined` to check that a variable is undefined. For example, if you +want to check that a function `bestDrinkForFlavor(flavor)` returns `undefined` +for the `'octopus'` flavor, because there is no good octopus-flavored drink: + +```js +test('the best drink for octopus flavor is undefined', () => { + expect(bestDrinkForFlavor('octopus')).toBeUndefined(); +}); +``` + +You could write `expect(bestDrinkForFlavor('octopus')).toBe(undefined)`, but +it's better practice to avoid referring to `undefined` directly in your code. + +### `.toContain(item)` + +Use `.toContain` when you want to check that an item is in an array. For testing +the items in the array, this uses `===`, a strict equality check. `.toContain` +can also check whether a string is a substring of another string. + +For example, if `getAllFlavors()` returns an array of flavors and you want to be +sure that `lime` is in there, you can write: + +```js +test('the flavor list contains lime', () => { + expect(getAllFlavors()).toContain('lime'); +}); +``` + +### `.toContainEqual(item)` + +Use `.toContainEqual` when you want to check that an item with a specific +structure and values is contained in an array. For testing the items in the +array, this matcher recursively checks the equality of all fields, rather than +checking for object identity. + +```js +describe('my beverage', () => { + test('is delicious and not sour', () => { + const myBeverage = {delicious: true, sour: false}; + expect(myBeverages()).toContainEqual(myBeverage); + }); +}); +``` + +### `.toEqual(value)` + +Use `.toEqual` when you want to check that two objects have the same value. This +matcher recursively checks the equality of all fields, rather than checking for +object identity—this is also known as "deep equal". For example, `toEqual` and +`toBe` behave differently in this test suite, so all the tests pass: + +```js +const can1 = { + flavor: 'grapefruit', + ounces: 12, +}; +const can2 = { + flavor: 'grapefruit', + ounces: 12, +}; + +describe('the La Croix cans on my desk', () => { + test('have all the same properties', () => { + expect(can1).toEqual(can2); + }); + test('are not the exact same can', () => { + expect(can1).not.toBe(can2); + }); +}); +``` + +> Note: `.toEqual` won't perform a _deep equality_ check for two errors. Only +> the `message` property of an Error is considered for equality. It is +> recommended to use the `.toThrow` matcher for testing against errors. + +### `.toHaveLength(number)` + +Use `.toHaveLength` to check that an object has a `.length` property and it is +set to a certain numeric value. + +This is especially useful for checking arrays or strings size. + +```js +expect([1, 2, 3]).toHaveLength(3); +expect('abc').toHaveLength(3); +expect('').not.toHaveLength(5); +``` + +### `.toMatch(regexpOrString)` + +Use `.toMatch` to check that a string matches a regular expression. + +For example, you might not know what exactly `essayOnTheBestFlavor()` returns, +but you know it's a really long string, and the substring `grapefruit` should be +in there somewhere. You can test this with: + +```js +describe('an essay on the best flavor', () => { + test('mentions grapefruit', () => { + expect(essayOnTheBestFlavor()).toMatch(/grapefruit/); + expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit')); + }); +}); +``` + +This matcher also accepts a string, which it will try to match: + +```js +describe('grapefruits are healthy', () => { + test('grapefruits are a fruit', () => { + expect('grapefruits').toMatch('fruit'); + }); +}); +``` + +### `.toMatchObject(object)` + +Use `.toMatchObject` to check that a JavaScript object matches a subset of the +properties of an object. It will match received objects with properties that are +**not** in the expected object. + +You can also pass an array of objects, in which case the method will return true +only if each object in the received array matches (in the `toMatchObject` sense +described above) the corresponding object in the expected array. This is useful +if you want to check that two arrays match in their number of elements, as +opposed to `arrayContaining`, which allows for extra elements in the received +array. + +You can match properties against values or against matchers. + +```js +const houseForSale = { + bath: true, + bedrooms: 4, + kitchen: { + amenities: ['oven', 'stove', 'washer'], + area: 20, + wallColor: 'white', + }, +}; +const desiredHouse = { + bath: true, + kitchen: { + amenities: ['oven', 'stove', 'washer'], + wallColor: expect.stringMatching(/white|yellow/), + }, +}; + +test('the house has my desired features', () => { + expect(houseForSale).toMatchObject(desiredHouse); +}); +``` + +```js +describe('toMatchObject applied to arrays arrays', () => { + test('the number of elements must match exactly', () => { + expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]); + }); + + // .arrayContaining "matches a received array which contains elements that + // are *not* in the expected array" + test('.toMatchObject does not allow extra elements', () => { + expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}]); + }); + + test('.toMatchObject is called for each elements, so extra object properties are okay', () => { + expect([{foo: 'bar'}, {baz: 1, extra: 'quux'}]).toMatchObject([ + {foo: 'bar'}, + {baz: 1}, + ]); + }); +}); +``` + +### `.toHaveProperty(keyPath, value)` + +Use `.toHaveProperty` to check if property at provided reference `keyPath` +exists for an object. For checking deeply nested properties in an object you may +use +[dot notation](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors) +or an array containing the keyPath for deep references. + +Optionally, you can provide a `value` to check if it's equal to the value +present at `keyPath` on the target object. This matcher uses 'deep equality' +(like `toEqual()`) and recursively checks the equality of all fields. + +The following example contains a `houseForSale` object with nested properties. +We are using `toHaveProperty` to check for the existence and values of various +properties in the object. + +```js +// Object containing house features to be tested +const houseForSale = { + bath: true, + bedrooms: 4, + kitchen: { + amenities: ['oven', 'stove', 'washer'], + area: 20, + wallColor: 'white', + }, +}; + +test('this house has my desired features', () => { + // Simple Referencing + expect(houseForSale).toHaveProperty('bath'); + expect(houseForSale).toHaveProperty('bedrooms', 4); + + expect(houseForSale).not.toHaveProperty('pool'); + + // Deep referencing using dot notation + expect(houseForSale).toHaveProperty('kitchen.area', 20); + expect(houseForSale).toHaveProperty('kitchen.amenities', [ + 'oven', + 'stove', + 'washer', + ]); + + expect(houseForSale).not.toHaveProperty('kitchen.open'); + + // Deep referencing using an array containing the keyPath + expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20); + expect(houseForSale).toHaveProperty( + ['kitchen', 'amenities'], + ['oven', 'stove', 'washer'], + ); + expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven'); + + expect(houseForSale).not.toHaveProperty(['kitchen', 'open']); +}); +``` + +### `.toMatchSnapshot(optionalString)` + +This ensures that a value matches the most recent snapshot. Check out +[the Snapshot Testing guide](SnapshotTesting.md) for more information. + +You can also specify an optional snapshot name. Otherwise, the name is inferred +from the test. + +_Note: While snapshot testing is most commonly used with React components, any +serializable value can be used as a snapshot._ + +### `.toThrow(error)` + +Also under the alias: `.toThrowError(error)` + +Use `.toThrow` to test that a function throws when it is called. For example, if +we want to test that `drinkFlavor('octopus')` throws, because octopus flavor is +too disgusting to drink, we could write: + +```js +test('throws on octopus', () => { + expect(() => { + drinkFlavor('octopus'); + }).toThrow(); +}); +``` + +If you want to test that a specific error gets thrown, you can provide an +argument to `toThrow`. The argument can be a string for the error message, a +class for the error, or a regex that should match the error. For example, let's +say that `drinkFlavor` is coded like this: + +```js +function drinkFlavor(flavor) { + if (flavor == 'octopus') { + throw new DisgustingFlavorError('yuck, octopus flavor'); + } + // Do some other stuff +} +``` + +We could test this error gets thrown in several ways: + +```js +test('throws on octopus', () => { + function drinkOctopus() { + drinkFlavor('octopus'); + } + + // Test the exact error message + expect(drinkOctopus).toThrowError('yuck, octopus flavor'); + + // Test that the error message says "yuck" somewhere + expect(drinkOctopus).toThrowError(/yuck/); + + // Test that we get a DisgustingFlavorError + expect(drinkOctopus).toThrowError(DisgustingFlavorError); +}); +``` + +> Note: You must wrap the code in a function, otherwise the error will not be +> caught and the assertion will fail. + +### `.toThrowErrorMatchingSnapshot()` + +Use `.toThrowErrorMatchingSnapshot` to test that a function throws an error +matching the most recent snapshot when it is called. For example, let's say you +have a `drinkFlavor` function that throws whenever the flavor is `'octopus'`, +and is coded like this: + +```js +function drinkFlavor(flavor) { + if (flavor == 'octopus') { + throw new DisgustingFlavorError('yuck, octopus flavor'); + } + // Do some other stuff +} +``` + +The test for this function will look this way: + +```js +test('throws on octopus', () => { + function drinkOctopus() { + drinkFlavor('octopus'); + } + + expect(drinkOctopus).toThrowErrorMatchingSnapshot(); +}); +``` + +And it will generate the following snapshot: + +```js +exports[`drinking flavors throws on octopus 1`] = `"yuck, octopus flavor"`; +``` + +Check out +[React Tree Snapshot Testing](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html) +for more information on snapshot testing. diff --git a/website/versioned_docs/version-22.3/GettingStarted.md b/website/versioned_docs/version-22.3/GettingStarted.md new file mode 100644 index 000000000000..2238758cacc0 --- /dev/null +++ b/website/versioned_docs/version-22.3/GettingStarted.md @@ -0,0 +1,156 @@ +--- +id: version-22.3-getting-started +title: Getting Started +original_id: getting-started +--- + +Install Jest using [`npm`](https://www.npmjs.com/): + +```bash +npm install --save-dev jest +``` + +Or via [`yarn`](https://yarnpkg.com/en/package/jest): + +```bash +yarn add --dev jest +``` + +Let's get started by writing a test for a hypothetical function that adds two +numbers. First, create a `sum.js` file: + +```javascript +function sum(a, b) { + return a + b; +} +module.exports = sum; +``` + +Then, create a file named `sum.test.js`. This will contain our actual test: + +```javascript +const sum = require('./sum'); + +test('adds 1 + 2 to equal 3', () => { + expect(sum(1, 2)).toBe(3); +}); +``` + +Add the following section to your `package.json`: + +```json +{ + "scripts": { + "test": "jest" + } +} +``` + +Finally, run `npm test` and Jest will print this message: + +```bash +PASS ./sum.test.js +✓ adds 1 + 2 to equal 3 (5ms) +``` + +**You just successfully wrote your first test using Jest!** + +This test used `expect` and `toBe` to test that two values were exactly +identical. To learn about the other things that Jest can test, see +[Using Matchers](UsingMatchers.md). + +## Running from command line + +You can run Jest directly from the CLI (if it's globally available in your +`PATH`, e.g. by `npm install -g jest`) with variety of useful options. + +Here's how to run Jest on files matching `my-test`, using `config.json` as a +configuration file and display a native OS notification after the run: + +```bash +jest my-test --notify --config=config.json +``` + +If you'd like to learn more about running `jest` through the command line, take +a look at the [Jest CLI Options](CLI.md) page. + +## Additional Configuration + +### Using Babel + +To use [Babel](http://babeljs.io/), install the `babel-jest` and +`regenerator-runtime` packages: + +```bash +npm install --save-dev babel-jest babel-core regenerator-runtime +``` + +> Note: If you are using a babel version 7 then you need to install `babel-jest` +> with the following command: +> +> ```bash +> npm install --save-dev babel-jest 'babel-core@^7.0.0-0' @babel/core regenerator-runtime +> ``` + +_Note: Explicitly installing `regenerator-runtime` is not needed if you use +`npm` 3 or 4 or Yarn_ + +Don't forget to add a [`.babelrc`](https://babeljs.io/docs/usage/babelrc/) file +in your project's root folder. For example, if you are using ES6 and +[React.js](https://facebook.github.io/react/) with the +[`babel-preset-env`](https://babeljs.io/docs/plugins/preset-env/) and +[`babel-preset-react`](https://babeljs.io/docs/plugins/preset-react/) presets: + +```json +{ + "presets": ["env", "react"] +} +``` + +You are now set up to use all ES6 features and React specific syntax. + +> Note: If you are using a more complicated Babel configuration, using Babel's +> `env` option, keep in mind that Jest will automatically define `NODE_ENV` as +> `test`. It will not use `development` section like Babel does by default when +> no `NODE_ENV` is set. + +> Note: If you've turned off transpilation of ES6 modules with the option +> `{ "modules": false }`, you have to make sure to turn this on in your test +> environment. + +```json +{ + "presets": [["env", {"modules": false}], "react"], + "env": { + "test": { + "presets": [["env"], "react"] + } + } +} +``` + +> Note: `babel-jest` is automatically installed when installing Jest and will +> automatically transform files if a babel configuration exists in your project. +> To avoid this behavior, you can explicitly reset the `transform` configuration +> option: + +```json +// package.json +{ + "jest": { + "transform": {} + } +} +``` + +### Using webpack + +Jest can be used in projects that use [webpack](https://webpack.github.io/) to +manage assets, styles, and compilation. webpack does offer some unique +challenges over other tools. Refer to the [webpack guide](Webpack.md) to get +started. + +### Using TypeScript + +To use TypeScript in your tests you can use +[ts-jest](https://github.com/kulshekhar/ts-jest). diff --git a/website/versioned_docs/version-22.3/GlobalAPI.md b/website/versioned_docs/version-22.3/GlobalAPI.md new file mode 100644 index 000000000000..ad5181dd7bdc --- /dev/null +++ b/website/versioned_docs/version-22.3/GlobalAPI.md @@ -0,0 +1,413 @@ +--- +id: version-22.3-api +title: Globals +original_id: api +--- + +In your test files, Jest puts each of these methods and objects into the global +environment. You don't have to require or import anything to use them. + +## Methods + + + +--- + +## Reference + +### `afterAll(fn, timeout)` + +Runs a function after all the tests in this file have completed. If the function +returns a promise or is a generator, Jest waits for that promise to resolve +before continuing. + +Optionally, you can provide a `timeout` (in milliseconds) for specifying how +long to wait before aborting. _Note: The default timeout is 5 seconds._ + +This is often useful if you want to clean up some global setup state that is +shared across tests. + +For example: + +```js +const globalDatabase = makeGlobalDatabase(); + +function cleanUpDatabase(db) { + db.cleanUp(); +} + +afterAll(() => { + cleanUpDatabase(globalDatabase); +}); + +test('can find things', () => { + return globalDatabase.find('thing', {}, results => { + expect(results.length).toBeGreaterThan(0); + }); +}); + +test('can insert a thing', () => { + return globalDatabase.insert('thing', makeThing(), response => { + expect(response.success).toBeTruthy(); + }); +}); +``` + +Here the `afterAll` ensures that `cleanUpDatabase` is called after all tests +run. + +If `afterAll` is inside a `describe` block, it runs at the end of the describe +block. + +If you want to run some cleanup after every test instead of after all tests, use +`afterEach` instead. + +### `afterEach(fn, timeout)` + +Runs a function after each one of the tests in this file completes. If the +function returns a promise or is a generator, Jest waits for that promise to +resolve before continuing. + +Optionally, you can provide a `timeout` (in milliseconds) for specifying how +long to wait before aborting. _Note: The default timeout is 5 seconds._ + +This is often useful if you want to clean up some temporary state that is +created by each test. + +For example: + +```js +const globalDatabase = makeGlobalDatabase(); + +function cleanUpDatabase(db) { + db.cleanUp(); +} + +afterEach(() => { + cleanUpDatabase(globalDatabase); +}); + +test('can find things', () => { + return globalDatabase.find('thing', {}, results => { + expect(results.length).toBeGreaterThan(0); + }); +}); + +test('can insert a thing', () => { + return globalDatabase.insert('thing', makeThing(), response => { + expect(response.success).toBeTruthy(); + }); +}); +``` + +Here the `afterEach` ensures that `cleanUpDatabase` is called after each test +runs. + +If `afterEach` is inside a `describe` block, it only runs after the tests that +are inside this describe block. + +If you want to run some cleanup just once, after all of the tests run, use +`afterAll` instead. + +### `beforeAll(fn, timeout)` + +Runs a function before any of the tests in this file run. If the function +returns a promise or is a generator, Jest waits for that promise to resolve +before running tests. + +Optionally, you can provide a `timeout` (in milliseconds) for specifying how +long to wait before aborting. _Note: The default timeout is 5 seconds._ + +This is often useful if you want to set up some global state that will be used +by many tests. + +For example: + +```js +const globalDatabase = makeGlobalDatabase(); + +beforeAll(() => { + // Clears the database and adds some testing data. + // Jest will wait for this promise to resolve before running tests. + return globalDatabase.clear().then(() => { + return globalDatabase.insert({testData: 'foo'}); + }); +}); + +// Since we only set up the database once in this example, it's important +// that our tests don't modify it. +test('can find things', () => { + return globalDatabase.find('thing', {}, results => { + expect(results.length).toBeGreaterThan(0); + }); +}); +``` + +Here the `beforeAll` ensures that the database is set up before tests run. If +setup was synchronous, you could just do this without `beforeAll`. The key is +that Jest will wait for a promise to resolve, so you can have asynchronous setup +as well. + +If `beforeAll` is inside a `describe` block, it runs at the beginning of the +describe block. + +If you want to run something before every test instead of before any test runs, +use `beforeEach` instead. + +### `beforeEach(fn, timeout)` + +Runs a function before each of the tests in this file runs. If the function +returns a promise or is a generator, Jest waits for that promise to resolve +before running the test. + +Optionally, you can provide a `timeout` (in milliseconds) for specifying how +long to wait before aborting. _Note: The default timeout is 5 seconds._ + +This is often useful if you want to reset some global state that will be used by +many tests. + +For example: + +```js +const globalDatabase = makeGlobalDatabase(); + +beforeEach(() => { + // Clears the database and adds some testing data. + // Jest will wait for this promise to resolve before running tests. + return globalDatabase.clear().then(() => { + return globalDatabase.insert({testData: 'foo'}); + }); +}); + +test('can find things', () => { + return globalDatabase.find('thing', {}, results => { + expect(results.length).toBeGreaterThan(0); + }); +}); + +test('can insert a thing', () => { + return globalDatabase.insert('thing', makeThing(), response => { + expect(response.success).toBeTruthy(); + }); +}); +``` + +Here the `beforeEach` ensures that the database is reset for each test. + +If `beforeEach` is inside a `describe` block, it runs for each test in the +describe block. + +If you only need to run some setup code once, before any tests run, use +`beforeAll` instead. + +### `describe(name, fn)` + +`describe(name, fn)` creates a block that groups together several related tests +in one "test suite". For example, if you have a `myBeverage` object that is +supposed to be delicious but not sour, you could test it with: + +```js +const myBeverage = { + delicious: true, + sour: false, +}; + +describe('my beverage', () => { + test('is delicious', () => { + expect(myBeverage.delicious).toBeTruthy(); + }); + + test('is not sour', () => { + expect(myBeverage.sour).toBeFalsy(); + }); +}); +``` + +This isn't required - you can just write the `test` blocks directly at the top +level. But this can be handy if you prefer your tests to be organized into +groups. + +You can also nest `describe` blocks if you have a hierarchy of tests: + +```js +const binaryStringToNumber = binString => { + if (!/^[01]+$/.test(binString)) { + throw new CustomError('Not a binary number.'); + } + + return parseInt(binString, 2); +}; + +describe('binaryStringToNumber', () => { + describe('given an invalid binary string', () => { + test('composed of non-numbers throws CustomError', () => { + expect(() => binaryStringToNumber('abc')).toThrowError(CustomError); + }); + + test('with extra whitespace throws CustomError', () => { + expect(() => binaryStringToNumber(' 100')).toThrowError(CustomError); + }); + }); + + describe('given a valid binary string', () => { + test('returns the correct number', () => { + expect(binaryStringToNumber('100')).toBe(4); + }); + }); +}); +``` + +### `describe.only(name, fn)` + +Also under the alias: `fdescribe(name, fn)` + +You can use `describe.only` if you want to run only one describe block: + +```js +describe.only('my beverage', () => { + test('is delicious', () => { + expect(myBeverage.delicious).toBeTruthy(); + }); + + test('is not sour', () => { + expect(myBeverage.sour).toBeFalsy(); + }); +}); + +describe('my other beverage', () => { + // ... will be skipped +}); +``` + +### `describe.skip(name, fn)` + +Also under the alias: `xdescribe(name, fn)` + +You can use `describe.skip` if you do not want to run a particular describe +block: + +```js +describe('my beverage', () => { + test('is delicious', () => { + expect(myBeverage.delicious).toBeTruthy(); + }); + + test('is not sour', () => { + expect(myBeverage.sour).toBeFalsy(); + }); +}); + +describe.skip('my other beverage', () => { + // ... will be skipped +}); +``` + +Using `describe.skip` is often just an easier alternative to temporarily +commenting out a chunk of tests. + +### `require.requireActual(moduleName)` + +Returns the actual module instead of a mock, bypassing all checks on whether the +module should receive a mock implementation or not. + +### `require.requireMock(moduleName)` + +Returns a mock module instead of the actual module, bypassing all checks on +whether the module should be required normally or not. + +### `test(name, fn, timeout)` + +Also under the alias: `it(name, fn, timeout)` + +All you need in a test file is the `test` method which runs a test. For example, +let's say there's a function `inchesOfRain()` that should be zero. Your whole +test could be: + +```js +test('did not rain', () => { + expect(inchesOfRain()).toBe(0); +}); +``` + +The first argument is the test name; the second argument is a function that +contains the expectations to test. The third argument (optional) is `timeout` +(in milliseconds) for specifying how long to wait before aborting. _Note: The +default timeout is 5 seconds._ + +> Note: If a **promise is returned** from `test`, Jest will wait for the promise +> to resolve before letting the test complete. Jest will also wait if you +> **provide an argument to the test function**, usually called `done`. This +> could be handy when you want to test callbacks. See how to test async code +> [here](TestingAsyncCode.md#callbacks). + +For example, let's say `fetchBeverageList()` returns a promise that is supposed +to resolve to a list that has `lemon` in it. You can test this with: + +```js +test('has lemon in it', () => { + return fetchBeverageList().then(list => { + expect(list).toContain('lemon'); + }); +}); +``` + +Even though the call to `test` will return right away, the test doesn't complete +until the promise resolves as well. + +### `test.only(name, fn, timeout)` + +Also under the aliases: `it.only(name, fn, timeout)` or `fit(name, fn, timeout)` + +When you are debugging a large test file, you will often only want to run a +subset of tests. You can use `.only` to specify which tests are the only ones +you want to run in that test file. + +Optionally, you can provide a `timeout` (in milliseconds) for specifying how +long to wait before aborting. _Note: The default timeout is 5 seconds._ + +For example, let's say you had these tests: + +```js +test.only('it is raining', () => { + expect(inchesOfRain()).toBeGreaterThan(0); +}); + +test('it is not snowing', () => { + expect(inchesOfSnow()).toBe(0); +}); +``` + +Only the "it is raining" test will run in that test file, since it is run with +`test.only`. + +Usually you wouldn't check code using `test.only` into source control - you +would use it just for debugging, and remove it once you have fixed the broken +tests. + +### `test.skip(name, fn)` + +Also under the aliases: `it.skip(name, fn)` or `xit(name, fn)` or +`xtest(name, fn)` + +When you are maintaining a large codebase, you may sometimes find a test that is +temporarily broken for some reason. If you want to skip running this test, but +you don't want to just delete this code, you can use `test.skip` to specify some +tests to skip. + +For example, let's say you had these tests: + +```js +test('it is raining', () => { + expect(inchesOfRain()).toBeGreaterThan(0); +}); + +test.skip('it is not snowing', () => { + expect(inchesOfSnow()).toBe(0); +}); +``` + +Only the "it is raining" test will run, since the other test is run with +`test.skip`. + +You could simply comment the test out, but it's often a bit nicer to use +`test.skip` because it will maintain indentation and syntax highlighting. diff --git a/website/versioned_docs/version-22.3/JestObjectAPI.md b/website/versioned_docs/version-22.3/JestObjectAPI.md new file mode 100644 index 000000000000..d15d5eab9ae8 --- /dev/null +++ b/website/versioned_docs/version-22.3/JestObjectAPI.md @@ -0,0 +1,484 @@ +--- +id: version-22.3-jest-object +title: The Jest Object +original_id: jest-object +--- + +The `jest` object is automatically in scope within every test file. The methods +in the `jest` object help create mocks and let you control Jest's overall +behavior. + +## Methods + +* [`jest.clearAllTimers()`](#jestclearalltimers) +* [`jest.disableAutomock()`](#jestdisableautomock) +* [`jest.enableAutomock()`](#jestenableautomock) +* [`jest.fn(implementation)`](#jestfnimplementation) +* [`jest.isMockFunction(fn)`](#jestismockfunctionfn) +* [`jest.genMockFromModule(moduleName)`](#jestgenmockfrommodulemodulename) +* [`jest.mock(moduleName, factory, options)`](#jestmockmodulename-factory-options) +* [`jest.unmock(moduleName)`](#jestunmockmodulename) +* [`jest.doMock(moduleName, factory, options)`](#jestdomockmodulename-factory-options) +* [`jest.dontMock(moduleName)`](#jestdontmockmodulename) +* [`jest.clearAllMocks()`](#jestclearallmocks) +* [`jest.resetAllMocks()`](#jestresetallmocks) +* [`jest.restoreAllMocks()`](#jestrestoreallmocks) +* [`jest.resetModules()`](#jestresetmodules) +* [`jest.runAllTicks()`](#jestrunallticks) +* [`jest.runAllTimers()`](#jestrunalltimers) +* [`jest.advanceTimersByTime(msToRun)`](#jestadvancetimersbytimemstorun) +* [`jest.runOnlyPendingTimers()`](#jestrunonlypendingtimers) +* [`jest.setMock(moduleName, moduleExports)`](#jestsetmockmodulename-moduleexports) +* [`jest.setTimeout(timeout)`](#jestsettimeouttimeout) +* [`jest.useFakeTimers()`](#jestusefaketimers) +* [`jest.useRealTimers()`](#jestuserealtimers) +* [`jest.spyOn(object, methodName)`](#jestspyonobject-methodname) +* [`jest.spyOn(object, methodName, accessType?)`](#jestspyonobject-methodname-accesstype) + +--- + +## Reference + +### `jest.clearAllTimers()` + +Removes any pending timers from the timer system. + +This means, if any timers have been scheduled (but have not yet executed), they +will be cleared and will never have the opportunity to execute in the future. + +### `jest.disableAutomock()` + +Disables automatic mocking in the module loader. + +After this method is called, all `require()`s will return the real versions of +each module (rather than a mocked version). + +This is usually useful when you have a scenario where the number of dependencies +you want to mock is far less than the number of dependencies that you don't. For +example, if you're writing a test for a module that uses a large number of +dependencies that can be reasonably classified as "implementation details" of +the module, then you likely do not want to mock them. + +Examples of dependencies that might be considered "implementation details" are +things ranging from language built-ins (e.g. Array.prototype methods) to highly +common utility methods (e.g. underscore/lo-dash, array utilities etc) and entire +libraries like React.js. + +Returns the `jest` object for chaining. + +_Note: this method was previously called `autoMockOff`. When using `babel-jest`, +calls to `disableAutomock` will automatically be hoisted to the top of the code +block. Use `autoMockOff` if you want to explicitly avoid this behavior._ + +### `jest.enableAutomock()` + +Enables automatic mocking in the module loader. + +Returns the `jest` object for chaining. + +_Note: this method was previously called `autoMockOn`. When using `babel-jest`, +calls to `enableAutomock` will automatically be hoisted to the top of the code +block. Use `autoMockOn` if you want to explicitly avoid this behavior._ + +### `jest.fn(implementation)` + +Returns a new, unused [mock function](MockFunctionAPI.md). Optionally takes a +mock implementation. + +```js +const mockFn = jest.fn(); +mockFn(); +expect(mockFn).toHaveBeenCalled(); + +// With a mock implementation: +const returnsTrue = jest.fn(() => true); +console.log(returnsTrue()); // true; +``` + +### `jest.isMockFunction(fn)` + +Determines if the given function is a mocked function. + +### `jest.genMockFromModule(moduleName)` + +Given the name of a module, use the automatic mocking system to generate a +mocked version of the module for you. + +This is useful when you want to create a [manual mock](ManualMocks.md) that +extends the automatic mock's behavior. + +### `jest.mock(moduleName, factory, options)` + +Mocks a module with an auto-mocked version when it is being required. `factory` +and `options` are optional. For example: + +```js +// banana.js +module.exports = () => 'banana'; + +// __tests__/test.js +jest.mock('../banana'); + +const banana = require('../banana'); // banana will be explicitly mocked. + +banana(); // will return 'undefined' because the function is auto-mocked. +``` + +The second argument can be used to specify an explicit module factory that is +being run instead of using Jest's automocking feature: + +```js +jest.mock('../moduleName', () => { + return jest.fn(() => 42); +}); + +// This runs the function specified as second argument to `jest.mock`. +const moduleName = require('../moduleName'); +moduleName(); // Will return '42'; +``` + +The third argument can be used to create virtual mocks – mocks of modules that +don't exist anywhere in the system: + +```js +jest.mock( + '../moduleName', + () => { + /* + * Custom implementation of a module that doesn't exist in JS, + * like a generated module or a native module in react-native. + */ + }, + {virtual: true}, +); +``` + +_Warning: Importing a module in a setup file (as specified by +`setupTestFrameworkScriptFile`) will prevent mocking for the module in question, +as well as all the modules that it imports._ + +Modules that are mocked with `jest.mock` are mocked only for the file that calls +`jest.mock`. Another file that imports the module will get the original +implementation even if it runs after the test file that mocks the module. + +Returns the `jest` object for chaining. + +### `jest.unmock(moduleName)` + +Indicates that the module system should never return a mocked version of the +specified module from `require()` (e.g. that it should always return the real +module). + +The most common use of this API is for specifying the module a given test +intends to be testing (and thus doesn't want automatically mocked). + +Returns the `jest` object for chaining. + +### `jest.doMock(moduleName, factory, options)` + +When using `babel-jest`, calls to `mock` will automatically be hoisted to the +top of the code block. Use this method if you want to explicitly avoid this +behavior. + +One example when this is useful is when you want to mock a module differently +within the same file: + +```js +beforeEach(() => { + jest.resetModules(); +}); + +test('moduleName 1', () => { + jest.doMock('../moduleName', () => { + return jest.fn(() => 1); + }); + const moduleName = require('../moduleName'); + expect(moduleName()).toEqual(1); +}); + +test('moduleName 2', () => { + jest.doMock('../moduleName', () => { + return jest.fn(() => 2); + }); + const moduleName = require('../moduleName'); + expect(moduleName()).toEqual(2); +}); +``` + +Returns the `jest` object for chaining. + +### `jest.dontMock(moduleName)` + +When using `babel-jest`, calls to `unmock` will automatically be hoisted to the +top of the code block. Use this method if you want to explicitly avoid this +behavior. + +Returns the `jest` object for chaining. + +### `jest.clearAllMocks()` + +Clears the `mock.calls` and `mock.instances` properties of all mocks. Equivalent +to calling `.mockClear()` on every mocked function. + +Returns the `jest` object for chaining. + +### `jest.resetAllMocks()` + +Resets the state of all mocks. Equivalent to calling `.mockReset()` on every +mocked function. + +Returns the `jest` object for chaining. + +### `jest.restoreAllMocks()` + +##### available in Jest **21.1.0+** + +Restores all mocks back to their original value. Equivalent to calling +`.mockRestore` on every mocked function. Beware that `jest.restoreAllMocks()` +only works when mock was created with `jest.spyOn`; other mocks will require you +to manually restore them. + +### `jest.resetModules()` + +Resets the module registry - the cache of all required modules. This is useful +to isolate modules where local state might conflict between tests. + +Example: + +```js +const sum1 = require('../sum'); +jest.resetModules(); +const sum2 = require('../sum'); +sum1 === sum2; +// > false (Both sum modules are separate "instances" of the sum module.) +``` + +Example in a test: + +```js +beforeEach(() => { + jest.resetModules(); +}); + +test('works', () => { + const sum = require('../sum'); +}); + +test('works too', () => { + const sum = require('../sum'); + // sum is a different copy of the sum module from the previous test. +}); +``` + +Returns the `jest` object for chaining. + +### `jest.runAllTicks()` + +Exhausts the **micro**-task queue (usually interfaced in node via +`process.nextTick`). + +When this API is called, all pending micro-tasks that have been queued via +`process.nextTick` will be executed. Additionally, if those micro-tasks +themselves schedule new micro-tasks, those will be continually exhausted until +there are no more micro-tasks remaining in the queue. + +### `jest.runAllTimers()` + +Exhausts the **macro**-task queue (i.e., all tasks queued by `setTimeout()`, +`setInterval()`, and `setImmediate()`). + +When this API is called, all pending "macro-tasks" that have been queued via +`setTimeout()` or `setInterval()` will be executed. Additionally if those +macro-tasks themselves schedule new macro-tasks, those will be continually +exhausted until there are no more macro-tasks remaining in the queue. + +This is often useful for synchronously executing setTimeouts during a test in +order to synchronously assert about some behavior that would only happen after +the `setTimeout()` or `setInterval()` callbacks executed. See the +[Timer mocks](TimerMocks.md) doc for more information. + +### `jest.runAllImmediates()` + +Exhausts all tasks queued by `setImmediate()`. + +### `jest.advanceTimersByTime(msToRun)` + +##### renamed in Jest **22.0.0+** + +Also under the alias: `.runTimersToTime()` + +Executes only the macro task queue (i.e. all tasks queued by `setTimeout()` or +`setInterval()` and `setImmediate()`). + +When this API is called, all timers are advanced by `msToRun` milliseconds. All +pending "macro-tasks" that have been queued via `setTimeout()` or +`setInterval()`, and would be executed within this time frame will be executed. +Additionally if those macro-tasks schedule new macro-tasks that would be +executed within the same time frame, those will be executed until there are no +more macro-tasks remaining in the queue, that should be run within `msToRun` +milliseconds. + +### `jest.runOnlyPendingTimers()` + +Executes only the macro-tasks that are currently pending (i.e., only the tasks +that have been queued by `setTimeout()` or `setInterval()` up to this point). If +any of the currently pending macro-tasks schedule new macro-tasks, those new +tasks will not be executed by this call. + +This is useful for scenarios such as one where the module being tested schedules +a `setTimeout()` whose callback schedules another `setTimeout()` recursively +(meaning the scheduling never stops). In these scenarios, it's useful to be able +to run forward in time by a single step at a time. + +### `jest.setMock(moduleName, moduleExports)` + +Explicitly supplies the mock object that the module system should return for the +specified module. + +On occasion there are times where the automatically generated mock the module +system would normally provide you isn't adequate enough for your testing needs. +Normally under those circumstances you should write a +[manual mock](ManualMocks.md) that is more adequate for the module in question. +However, on extremely rare occasions, even a manual mock isn't suitable for your +purposes and you need to build the mock yourself inside your test. + +In these rare scenarios you can use this API to manually fill the slot in the +module system's mock-module registry. + +Returns the `jest` object for chaining. + +_Note It is recommended to use +[`jest.mock()`](#jestmockmodulename-factory-options) instead. The `jest.mock` +API's second argument is a module factory instead of the expected exported +module object._ + +### `jest.setTimeout(timeout)` + +Set the default timeout interval for tests and before/after hooks in +milliseconds. + +_Note: The default timeout interval is 5 seconds if this method is not called._ + +Example: + +```js +jest.setTimeout(1000); // 1 second +``` + +### `jest.useFakeTimers()` + +Instructs Jest to use fake versions of the standard timer functions +(`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `nextTick`, +`setImmediate` and `clearImmediate`). + +Returns the `jest` object for chaining. + +### `jest.useRealTimers()` + +Instructs Jest to use the real versions of the standard timer functions. + +Returns the `jest` object for chaining. + +### `jest.spyOn(object, methodName)` + +##### available in Jest **19.0.0+** + +Creates a mock function similar to `jest.fn` but also tracks calls to +`object[methodName]`. Returns a Jest mock function. + +_Note: By default, `jest.spyOn` also calls the **spied** method. This is +different behavior from most other test libraries. If you want to overwrite the +original function, you can use +`jest.spyOn(object, methodName).mockImplementation(() => customImplementation)` +or `object[methodName] = jest.fn(() => customImplementation);`_ + +Example: + +```js +const video = { + play() { + return true; + }, +}; + +module.exports = video; +``` + +Example test: + +```js +const video = require('./video'); + +test('plays video', () => { + const spy = jest.spyOn(video, 'play'); + const isPlaying = video.play(); + + expect(spy).toHaveBeenCalled(); + expect(isPlaying).toBe(true); + + spy.mockReset(); + spy.mockRestore(); +}); +``` + +### `jest.spyOn(object, methodName, accessType?)` + +##### available in Jest **22.1.0+** + +Since Jest 22.1.0+, the `jest.spyOn` method takes an optional third argument of +`accessType` that can be either `'get'` or `'set'`, which proves to be useful +when you want to spy on a getter or a setter, respectively. + +Example: + +```js +const video = { + // it's a getter! + get play() { + return true; + }, +}; + +module.exports = video; + +const audio = { + _volume: false, + // it's a setter! + set volume(value) { + this._volume = value; + }, + get volume() { + return this._volume; + }, +}; + +module.exports = video; +``` + +Example test: + +```js +const video = require('./video'); + +test('plays video', () => { + const spy = jest.spyOn(video, 'play', 'get'); // we pass 'get' + const isPlaying = video.play; + + expect(spy).toHaveBeenCalled(); + expect(isPlaying).toBe(true); + + spy.mockReset(); + spy.mockRestore(); +}); + +test('plays audio', () => { + const spy = jest.spyOn(video, 'play', 'set'); // we pass 'set' + video.volume = 100; + + expect(spy).toHaveBeenCalled(); + expect(video.volume).toBe(100); + + spy.mockReset(); + spy.mockRestore(); +}); +``` diff --git a/website/versioned_docs/version-22.3/JestPlatform.md b/website/versioned_docs/version-22.3/JestPlatform.md new file mode 100644 index 000000000000..822590de2dd4 --- /dev/null +++ b/website/versioned_docs/version-22.3/JestPlatform.md @@ -0,0 +1,197 @@ +--- +id: version-22.3-jest-platform +title: Jest Platform +original_id: jest-platform +--- + +You can cherry pick specific features of Jest and use them as standalone +packages. Here's a list of the available packages: + +## jest-changed-files + +Tool for identifying modified files in a git/hg repository. Exports two +functions: + +* `getChangedFilesForRoots` returns a promise that resolves to an object with + the changed files and repos. +* `findRepos` returns a promise that resolves to a set of repositories contained + in the specified path. + +### Example + +```javascript +const {getChangedFilesForRoots} = require('jest-changed-files'); + +// print the set of modified files since last commit in the current repo +getChangedFilesForRoots(['./'], { + lastCommit: true, +}).then(result => console.log(result.changedFiles)); +``` + +You can read more about `jest-changed-files` in the +[readme file](https://github.com/facebook/jest/blob/master/packages/jest-changed-files/README.md). + +## jest-diff + +Tool for visualizing changes in data. Exports a function that compares two +values of any type and returns a "pretty-printed" string illustrating the +difference between the two arguments. + +### Example + +```javascript +const diff = require('jest-diff'); + +const a = {a: {b: {c: 5}}}; +const b = {a: {b: {c: 6}}}; + +const result = diff(a, b); + +// print diff +console.log(result); +``` + +## jest-docblock + +Tool for extracting and parsing the comments at the top of a JavaScript file. +Exports various function to manipulate the data inside the comment block. + +### Example + +```javascript +const {parseWithComments} = require('jest-docblock'); + +const code = ` +/** + * This is a sample + * + * @flow + */ + + console.log('Hello World!'); +`; + +const parsed = parseWithComments(code); + +// prints an object with two attributes: comments and pragmas. +console.log(parsed); +``` + +You can read more about `jest-docblock` in the +[readme file](https://github.com/facebook/jest/blob/master/packages/jest-docblock/README.md). + +## jest-get-type + +Module that identifies the primitive type of any JavaScript value. Exports a +function that returns a string with the type of the value passed as argument. + +### Example + +```javascript +const getType = require('jest-get-type'); + +const array = [1, 2, 3]; +const nullValue = null; +const undefinedValue = undefined; + +// prints 'array' +console.log(getType(array)); +// prints 'null' +console.log(getType(nullValue)); +// prints 'undefined' +console.log(getType(undefinedValue)); +``` + +## jest-validate + +Tool for validating configurations submitted by users. Exports a function that +takes two arguments: the user's configuration and an object containing an +example configuration and other options. The return value is an object with two +attributes: + +* `hasDeprecationWarnings`, a boolean indicating whether the submitted + configuration has deprecation warnings, +* `isValid`, a boolean indicating whether the configuration is correct or not. + +### Example + +```javascript +const {validate} = require('jest-validate'); + +const configByUser = { + transform: '/node_modules/my-custom-transform', +}; + +const result = validate(configByUser, { + comment: ' Documentation: http://custom-docs.com', + exampleConfig: {transform: '/node_modules/babel-jest'}, +}); + +console.log(result); +``` + +You can read more about `jest-validate` in the +[readme file](https://github.com/facebook/jest/blob/master/packages/jest-validate/README.md). + +## jest-worker + +Module used for parallelization of tasks. Exports a class `Worker` that takes +the path of Node.js module and lets you call the module's exported methods as if +they where class methods, returning a promise that resolves when the specified +method finishes its execution in a forked process. + +### Example + +```javascript +// heavy-task.js + +module.exports = { + myHeavyTask: args => { + // long running CPU intensive task. + }, +}; +``` + +```javascript +// main.js + +async function main() { + const worker = new Worker(require.resolve('./heavy-task.js')); + + // run 2 tasks in parallel with different arguments + const results = await Promise.all([ + worker.myHeavyTask({foo: 'bar'}), + worker.myHeavyTask({bar: 'foo'}), + ]); + + console.log(results); +} + +main(); +``` + +You can read more about `jest-worker` in the +[readme file](https://github.com/facebook/jest/blob/master/packages/jest-worker/README.md). + +## pretty-format + +Exports a function that converts any JavaScript value into a human-readable +string. Supports all built-in JavaScript types out of the box and allows +extension for application-specific types via user-defined plugins. + +### Example + +```javascript +const prettyFormat = require('pretty-format'); + +const val = {object: {}}; +val.circularReference = val; +val[Symbol('foo')] = 'foo'; +val.map = new Map([['prop', 'value']]); +val.array = [-0, Infinity, NaN]; + +console.log(prettyFormat(val)); +``` + +You can read more about `pretty-format` in the +[readme file](https://github.com/facebook/jest/blob/master/packages/pretty-format/README.md). diff --git a/website/versioned_docs/version-22.3/ManualMocks.md b/website/versioned_docs/version-22.3/ManualMocks.md new file mode 100644 index 000000000000..eb2030bd5681 --- /dev/null +++ b/website/versioned_docs/version-22.3/ManualMocks.md @@ -0,0 +1,157 @@ +--- +id: version-22.3-manual-mocks +title: Manual Mocks +original_id: manual-mocks +--- + +Manual mocks are used to stub out functionality with mock data. For example, +instead of accessing a remote resource like a website or a database, you might +want to create a manual mock that allows you to use fake data. This ensures your +tests will be fast and not flaky. + +Manual mocks are defined by writing a module in a `__mocks__/` subdirectory +immediately adjacent to the module. For example, to mock a module called `user` +in the `models` directory, create a file called `user.js` and put it in the +`models/__mocks__` directory. Note that the `__mocks__` folder is +case-sensitive, so naming the directory `__MOCKS__` will break on some systems. +If the module you are mocking is a node module (eg: `fs`), the mock should be +placed in the `__mocks__` directory adjacent to `node_modules` (unless you +configured [`roots`](Configuration.md#roots-array-string) to point to a folder +other than the project root). Eg: + +```bash +. +├── config +├── __mocks__ +│   └── fs.js +├── models +│   ├── __mocks__ +│   │   └── user.js +│   └── user.js +├── node_modules +└── views +``` + +When a manual mock exists for a given module, Jest's module system will use that +module when explicitly calling `jest.mock('moduleName')`. However, manual mocks +will take precedence over node modules even if `jest.mock('moduleName')` is not +called. To opt out of this behavior you will need to explicitly call +`jest.unmock('moduleName')` in tests that should use the actual module +implementation. + +Here's a contrived example where we have a module that provides a summary of all +the files in a given directory. + +```javascript +// FileSummarizer.js +'use strict'; + +const fs = require('fs'); + +function summarizeFilesInDirectorySync(directory) { + return fs.readdirSync(directory).map(fileName => ({ + directory, + fileName, + })); +} + +exports.summarizeFilesInDirectorySync = summarizeFilesInDirectorySync; +``` + +Since we'd like our tests to avoid actually hitting the disk (that's pretty slow +and fragile), we create a manual mock for the `fs` module by extending an +automatic mock. Our manual mock will implement custom versions of the `fs` APIs +that we can build on for our tests: + +```javascript +// __mocks__/fs.js +'use strict'; + +const path = require('path'); + +const fs = jest.genMockFromModule('fs'); + +// This is a custom function that our tests can use during setup to specify +// what the files on the "mock" filesystem should look like when any of the +// `fs` APIs are used. +let mockFiles = Object.create(null); +function __setMockFiles(newMockFiles) { + mockFiles = Object.create(null); + for (const file in newMockFiles) { + const dir = path.dirname(file); + + if (!mockFiles[dir]) { + mockFiles[dir] = []; + } + mockFiles[dir].push(path.basename(file)); + } +} + +// A custom version of `readdirSync` that reads from the special mocked out +// file list set via __setMockFiles +function readdirSync(directoryPath) { + return mockFiles[directoryPath] || []; +} + +fs.__setMockFiles = __setMockFiles; +fs.readdirSync = readdirSync; + +module.exports = fs; +``` + +Now we write our test: + +```javascript +// __tests__/FileSummarizer-test.js +'use strict'; + +jest.mock('fs'); + +describe('listFilesInDirectorySync', () => { + const MOCK_FILE_INFO = { + '/path/to/file1.js': 'console.log("file1 contents");', + '/path/to/file2.txt': 'file2 contents', + }; + + beforeEach(() => { + // Set up some mocked out file info before each test + require('fs').__setMockFiles(MOCK_FILE_INFO); + }); + + test('includes all files in the directory in the summary', () => { + const FileSummarizer = require('../FileSummarizer'); + const fileSummary = FileSummarizer.summarizeFilesInDirectorySync( + '/path/to', + ); + + expect(fileSummary.length).toBe(2); + }); +}); +``` + +The example mock shown here uses +[`jest.genMockFromModule`](JestObjectAPI.md#jestgenmockfrommodulemodulename) to +generate an automatic mock, and overrides its default behavior. This is the +recommended approach, but is completely optional. If you do not want to use the +automatic mock at all, you can simply export your own functions from the mock +file. One downside to fully manual mocks is that they're manual – meaning you +have to manually update them any time the module they are mocking changes. +Because of this, it's best to use or extend the automatic mock when it works for +your needs. + +To ensure that a manual mock and its real implementation stay in sync, it might +be useful to require the real module using `require.requireActual(moduleName)` +in your manual mock and amending it with mock functions before exporting it. + +The code for this example is available at +[examples/manual_mocks](https://github.com/facebook/jest/tree/master/examples/manual_mocks). + +### Using with ES module imports + +If you're using +[ES module imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) +then you'll normally be inclined to put your `import` statements at the top of +the test file. But often you need to instruct Jest to use a mock before modules +use it. For this reason, Jest will automatically hoist `jest.mock` calls to the +top of the module (before any imports). To learn more about this and see it in +action, see [this repo](https://github.com/kentcdodds/how-jest-mocking-works). diff --git a/website/versioned_docs/version-22.3/MigrationGuide.md b/website/versioned_docs/version-22.3/MigrationGuide.md new file mode 100644 index 000000000000..0daca81d6f8a --- /dev/null +++ b/website/versioned_docs/version-22.3/MigrationGuide.md @@ -0,0 +1,48 @@ +--- +id: version-22.3-migration-guide +title: Migrating to Jest +original_id: migration-guide +--- + +If you'd like to try out Jest with an existing codebase, there are a number of +ways to convert to Jest: + +* If you are using Jasmine, or a Jasmine like API (for example + [Mocha](https://mochajs.org)), Jest should be mostly compatible and easy to + migrate to. +* If you are using AVA, Expect.js (by Automattic), Jasmine, Mocha, proxyquire, + Should.js or Tape you can automatically migrate with Jest Codemods (see + below). +* If you like [chai](http://chaijs.com/), you can upgrade to Jest and continue + using chai. However, we recommend trying out Jest's assertions and their + failure messages. Jest Codemods can migrate from chai (see below). + +### jest-codemods + +If you are using [AVA](https://github.com/avajs/ava), +[Chai](https://github.com/chaijs/chai), +[Expect.js (by Automattic)](https://github.com/Automattic/expect.js), +[Jasmine](https://github.com/jasmine/jasmine), +[Mocha](https://github.com/mochajs/mocha), +[proxyquire](https://github.com/thlorenz/proxyquire), +[Should.js](https://github.com/tj/should.js/) or +[Tape](https://github.com/substack/tape) you can use the third-party +[jest-codemods](https://github.com/skovhus/jest-codemods) to do most of the +dirty migration work. It runs a code transformation on your codebase using +[jscodeshift](https://github.com/facebook/jscodeshift). + +Install Jest Codemods with `npm` by running: + +```bash +npm install -g jest-codemods +``` + +To transform your existing tests, navigate to the project containing the tests +and run: + +```bash +jest-codemods +``` + +More information can be found at +[https://github.com/skovhus/jest-codemods](https://github.com/skovhus/jest-codemods). diff --git a/website/versioned_docs/version-22.3/MockFunctionAPI.md b/website/versioned_docs/version-22.3/MockFunctionAPI.md new file mode 100644 index 000000000000..3d118374345a --- /dev/null +++ b/website/versioned_docs/version-22.3/MockFunctionAPI.md @@ -0,0 +1,328 @@ +--- +id: version-22.3-mock-function-api +title: Mock Functions +original_id: mock-function-api +--- + +Mock functions are also known as "spies", because they let you spy on the +behavior of a function that is called indirectly by some other code, rather than +just testing the output. You can create a mock function with `jest.fn()`. If no +implementation is given, the mock function will return `undefined` when invoked. + +## Methods + + + +--- + +## Reference + +### `mockFn.getMockName()` + +##### available in Jest **22.0.0+** + +Returns the mock name string set by calling `mockFn.mockName(value)`. + +### `mockFn.mock.calls` + +An array that represents all calls that have been made into this mock function. +Each call is represented by an array of arguments that were passed during the +call. + +For example: A mock function `f` that has been called twice, with the arguments +`f('arg1', 'arg2')`, and then with the arguments `f('arg3', 'arg4')` would have +a `mock.calls` array that looks like this: + +```js +[['arg1', 'arg2'], ['arg3', 'arg4']]; +``` + +### `mockFn.mock.instances` + +An array that contains all the object instances that have been instantiated from +this mock function using `new`. + +For example: A mock function that has been instantiated twice would have the +following `mock.instances` array: + +```js +const mockFn = jest.fn(); + +const a = new mockFn(); +const b = new mockFn(); + +mockFn.mock.instances[0] === a; // true +mockFn.mock.instances[1] === b; // true +``` + +### `mockFn.mockClear()` + +Resets all information stored in the [`mockFn.mock.calls`](#mockfn-mock-calls) +and [`mockFn.mock.instances`](#mockfn-mock-instances) arrays. + +Often this is useful when you want to clean up a mock's usage data between two +assertions. + +Beware that `mockClear` will replace `mockFn.mock`, not just +[`mockFn.mock.calls`](#mockfn-mock-calls) and +[`mockFn.mock.instances`](#mockfn-mock-instances). You should therefore avoid +assigning `mockFn.mock` to other variables, temporary or not, to make sure you +don't access stale data. + +The [`clearMocks`](configuration.html#clearmocks-boolean) configuration option +is available to clear mocks automatically between tests. + +### `mockFn.mockReset()` + +Resets all information stored in the mock, including any initial implementation +and mock name given. + +This is useful when you want to completely restore a mock back to its initial +state. + +Beware that `mockReset` will replace `mockFn.mock`, not just +[`mockFn.mock.calls`](#mockfn-mock-calls) and +[`mockFn.mock.instances`](#mockfn-mock-instances). You should therefore avoid +assigning `mockFn.mock` to other variables, temporary or not, to make sure you +don't access stale data. + +### `mockFn.mockRestore()` + +Removes the mock and restores the initial implementation. + +This is useful when you want to mock functions in certain test cases and restore +the original implementation in others. + +Beware that `mockFn.mockRestore` only works when mock was created with +`jest.spyOn`. Thus you have to take care of restoration yourself when manually +assigning `jest.fn()`. + +The [`restoreMocks`](configuration.html#restoremocks-boolean) configuration +option is available to restore mocks automatically between tests. + +### `mockFn.mockImplementation(fn)` + +Accepts a function that should be used as the implementation of the mock. The +mock itself will still record all calls that go into and instances that come +from itself – the only difference is that the implementation will also be +executed when the mock is called. + +_Note: `jest.fn(implementation)` is a shorthand for +`jest.fn().mockImplementation(implementation)`._ + +For example: + +```js +const mockFn = jest.fn().mockImplementation(scalar => 42 + scalar); +// or: jest.fn(scalar => 42 + scalar); + +const a = mockFn(0); +const b = mockFn(1); + +a === 42; // true +b === 43; // true + +mockFn.mock.calls[0][0] === 0; // true +mockFn.mock.calls[1][0] === 1; // true +``` + +`mockImplementation` can also be used to mock class constructors: + +```js +// SomeClass.js +module.exports = class SomeClass { + m(a, b) {} +}; + +// OtherModule.test.js +jest.mock('./SomeClass'); // this happens automatically with automocking +const SomeClass = require('./SomeClass'); +const mMock = jest.fn(); +SomeClass.mockImplementation(() => { + return { + m: mMock, + }; +}); + +const some = new SomeClass(); +some.m('a', 'b'); +console.log('Calls to m: ', mMock.mock.calls); +``` + +### `mockFn.mockImplementationOnce(fn)` + +Accepts a function that will be used as an implementation of the mock for one +call to the mocked function. Can be chained so that multiple function calls +produce different results. + +```js +const myMockFn = jest + .fn() + .mockImplementationOnce(cb => cb(null, true)) + .mockImplementationOnce(cb => cb(null, false)); + +myMockFn((err, val) => console.log(val)); // true + +myMockFn((err, val) => console.log(val)); // false +``` + +When the mocked function runs out of implementations defined with +mockImplementationOnce, it will execute the default implementation set with +`jest.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if +they were called: + +```js +const myMockFn = jest + .fn(() => 'default') + .mockImplementationOnce(() => 'first call') + .mockImplementationOnce(() => 'second call'); + +// 'first call', 'second call', 'default', 'default' +console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()); +``` + +### `mockFn.mockName(value)` + +##### available in Jest **22.0.0+** + +Accepts a string to use in test result output in place of "jest.fn()" to +indicate which mock function is being referenced. + +For example: + +```js +const mockFn = jest.fn().mockName('mockedFunction'); +// mockFn(); +expect(mockFn).toHaveBeenCalled(); +``` + +Will result in this error: + +```bash + expect(mockedFunction).toHaveBeenCalled() + + Expected mock function to have been called. +``` + +### `mockFn.mockReturnThis()` + +Just a simple sugar function for: + +```js +jest.fn(function() { + return this; +}); +``` + +### `mockFn.mockReturnValue(value)` + +Accepts a value that will be returned whenever the mock function is called. + +```js +const mock = jest.fn(); +mock.mockReturnValue(42); +mock(); // 42 +mock.mockReturnValue(43); +mock(); // 43 +``` + +### `mockFn.mockReturnValueOnce(value)` + +Accepts a value that will be returned for one call to the mock function. Can be +chained so that successive calls to the mock function return different values. +When there are no more `mockReturnValueOnce` values to use, calls will return a +value specified by `mockReturnValue`. + +```js +const myMockFn = jest + .fn() + .mockReturnValue('default') + .mockReturnValueOnce('first call') + .mockReturnValueOnce('second call'); + +// 'first call', 'second call', 'default', 'default' +console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()); +``` + +### `mockFn.mockResolvedValue(value)` + +Simple sugar function for: + +```js +jest.fn().mockReturnValue(Promise.resolve(value)); +``` + +Useful to mock async functions in async tests: + +```js +test('async test', async () => { + const asyncMock = jest.fn().mockResolvedValue(43); + + await asyncMock(); // 43 +}); +``` + +### `mockFn.mockResolvedValueOnce(value)` + +Simple sugar function for: + +```js +jest.fn().mockReturnValueOnce(Promise.resolve(value)); +``` + +Useful to resolve different values over multiple async calls: + +```js +test('async test', async () => { + const asyncMock = jest + .fn() + .mockResolvedValue('default') + .mockResolvedValueOnce('first call') + .mockResolvedValueOnce('second call'); + + await asyncMock(); // first call + await asyncMock(); // second call + await asyncMock(); // default + await asyncMock(); // default +}); +``` + +### `mockFn.mockRejectedValue(value)` + +Simple sugar function for: + +```js +jest.fn().mockReturnValue(Promise.reject(value)); +``` + +Useful to create async mock functions that will always reject: + +```js +test('async test', async () => { + const asyncMock = jest.fn().mockRejectedValue(new Error('Async error')); + + await asyncMock(); // throws "Async error" +}); +``` + +### `mockFn.mockRejectedValueOnce(value)` + +Simple sugar function for: + +```js +jest.fn().mockReturnValueOnce(Promise.reject(value)); +``` + +Example usage: + +```js +test('async test', async () => { + const asyncMock = jest + .fn() + .mockResolvedValueOnce('first call') + .mockRejectedValueOnce(new Error('Async error')); + + await asyncMock(); // first call + await asyncMock(); // throws "Async error" +}); +``` diff --git a/website/versioned_docs/version-22.3/MockFunctions.md b/website/versioned_docs/version-22.3/MockFunctions.md new file mode 100644 index 000000000000..59c0468d5fdc --- /dev/null +++ b/website/versioned_docs/version-22.3/MockFunctions.md @@ -0,0 +1,279 @@ +--- +id: version-22.3-mock-functions +title: Mock Functions +original_id: mock-functions +--- + +Mock functions make it easy to test the links between code by erasing the actual +implementation of a function, capturing calls to the function (and the +parameters passed in those calls), capturing instances of constructor functions +when instantiated with `new`, and allowing test-time configuration of return +values. + +There are two ways to mock functions: Either by creating a mock function to use +in test code, or writing a [`manual mock`](ManualMocks.md) to override a module +dependency. + +## Using a mock function + +Let's imagine we're testing an implementation of a function `forEach`, which +invokes a callback for each item in a supplied array. + +```javascript +function forEach(items, callback) { + for (let index = 0; index < items.length; index++) { + callback(items[index]); + } +} +``` + +To test this function, we can use a mock function, and inspect the mock's state +to ensure the callback is invoked as expected. + +```javascript +const mockCallback = jest.fn(); +forEach([0, 1], mockCallback); + +// The mock function is called twice +expect(mockCallback.mock.calls.length).toBe(2); + +// The first argument of the first call to the function was 0 +expect(mockCallback.mock.calls[0][0]).toBe(0); + +// The first argument of the second call to the function was 1 +expect(mockCallback.mock.calls[1][0]).toBe(1); +``` + +## `.mock` property + +All mock functions have this special `.mock` property, which is where data about +how the function has been called is kept. The `.mock` property also tracks the +value of `this` for each call, so it is possible to inspect this as well: + +```javascript +const myMock = jest.fn(); + +const a = new myMock(); +const b = {}; +const bound = myMock.bind(b); +bound(); + +console.log(myMock.mock.instances); +// > [ , ] +``` + +These mock members are very useful in tests to assert how these functions get +called, or instantiated: + +```javascript +// The function was called exactly once +expect(someMockFunction.mock.calls.length).toBe(1); + +// The first arg of the first call to the function was 'first arg' +expect(someMockFunction.mock.calls[0][0]).toBe('first arg'); + +// The second arg of the first call to the function was 'second arg' +expect(someMockFunction.mock.calls[0][1]).toBe('second arg'); + +// This function was instantiated exactly twice +expect(someMockFunction.mock.instances.length).toBe(2); + +// The object returned by the first instantiation of this function +// had a `name` property whose value was set to 'test' +expect(someMockFunction.mock.instances[0].name).toEqual('test'); +``` + +## Mock Return Values + +Mock functions can also be used to inject test values into your code during a +test: + +```javascript +const myMock = jest.fn(); +console.log(myMock()); +// > undefined + +myMock + .mockReturnValueOnce(10) + .mockReturnValueOnce('x') + .mockReturnValue(true); + +console.log(myMock(), myMock(), myMock(), myMock()); +// > 10, 'x', true, true +``` + +Mock functions are also very effective in code that uses a functional +continuation-passing style. Code written in this style helps avoid the need for +complicated stubs that recreate behavior of the real component they're standing +in for, in favor of injecting values directly into the test right before they're +used. + +```javascript +const filterTestFn = jest.fn(); + +// Make the mock return `true` for the first call, +// and `false` for the second call +filterTestFn.mockReturnValueOnce(true).mockReturnValueOnce(false); + +const result = [11, 12].filter(filterTestFn); + +console.log(result); +// > [11] +console.log(filterTestFn.mock.calls); +// > [ [11], [12] ] +``` + +Most real-world examples actually involve getting ahold of a mock function on a +dependent component and configuring that, but the technique is the same. In +these cases, try to avoid the temptation to implement logic inside of any +function that's not directly being tested. + +## Mock Implementations + +Still, there are cases where it's useful to go beyond the ability to specify +return values and full-on replace the implementation of a mock function. This +can be done with `jest.fn` or the `mockImplementationOnce` method on mock +functions. + +```javascript +const myMockFn = jest.fn(cb => cb(null, true)); + +myMockFn((err, val) => console.log(val)); +// > true + +myMockFn((err, val) => console.log(val)); +// > true +``` + +The `mockImplementation` method is useful when you need to define the default +implementation of a mock function that is created from another module: + +```js +// foo.js +module.exports = function() { + // some implementation; +}; + +// test.js +jest.mock('../foo'); // this happens automatically with automocking +const foo = require('../foo'); + +// foo is a mock function +foo.mockImplementation(() => 42); +foo(); +// > 42 +``` + +When you need to recreate a complex behavior of a mock function such that +multiple function calls produce different results, use the +`mockImplementationOnce` method: + +```javascript +const myMockFn = jest + .fn() + .mockImplementationOnce(cb => cb(null, true)) + .mockImplementationOnce(cb => cb(null, false)); + +myMockFn((err, val) => console.log(val)); +// > true + +myMockFn((err, val) => console.log(val)); +// > false +``` + +When the mocked function runs out of implementations defined with +`mockImplementationOnce`, it will execute the default implementation set with +`jest.fn` (if it is defined): + +```javascript +const myMockFn = jest + .fn(() => 'default') + .mockImplementationOnce(() => 'first call') + .mockImplementationOnce(() => 'second call'); + +console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()); +// > 'first call', 'second call', 'default', 'default' +``` + +For cases where we have methods that are typically chained (and thus always need +to return `this`), we have a sugary API to simplify this in the form of a +`.mockReturnThis()` function that also sits on all mocks: + +```javascript +const myObj = { + myMethod: jest.fn().mockReturnThis(), +}; + +// is the same as + +const otherObj = { + myMethod: jest.fn(function() { + return this; + }), +}; +``` + +## Mock Names + +##### available in Jest **22.0.0+** + +You can optionally provide a name for your mock functions, which will be +displayed instead of "jest.fn()" in test error output. Use this if you want to +be able to quickly identify the mock function reporting an error in your test +output. + +```javascript +const myMockFn = jest + .fn() + .mockReturnValue('default') + .mockImplementation(scalar => 42 + scalar) + .mockName('add42'); +``` + +## Custom Matchers + +Finally, in order to make it simpler to assert how mock functions have been +called, we've added some custom matcher functions for you: + +```javascript +// The mock function was called at least once +expect(mockFunc).toBeCalled(); + +// The mock function was called at least once with the specified args +expect(mockFunc).toBeCalledWith(arg1, arg2); + +// The last call to the mock function was called with the specified args +expect(mockFunc).lastCalledWith(arg1, arg2); + +// All calls and the name of the mock is written as a snapshot +expect(mockFunc).toMatchSnapshot(); +``` + +These matchers are really just sugar for common forms of inspecting the `.mock` +property. You can always do this manually yourself if that's more to your taste +or if you need to do something more specific: + +```javascript +// The mock function was called at least once +expect(mockFunc.mock.calls.length).toBeGreaterThan(0); + +// The mock function was called at least once with the specified args +expect(mockFunc.mock.calls).toContain([arg1, arg2]); + +// The last call to the mock function was called with the specified args +expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual([ + arg1, + arg2, +]); + +// The first arg of the last call to the mock function was `42` +// (note that there is no sugar helper for this specific of an assertion) +expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42); + +// A snapshot will check that a mock was invoked the same number of times, +// in the same order, with the same arguments. It will also assert on the name. +expect(mockFunc.mock.calls).toEqual([[arg1, arg2]]); +expect(mockFunc.mock.getMockName()).toBe('a mock name'); +``` + +For a complete list of matchers, check out the [reference docs](ExpectAPI.md). diff --git a/website/versioned_docs/version-22.3/MongoDB.md b/website/versioned_docs/version-22.3/MongoDB.md new file mode 100644 index 000000000000..3f0a1b126c3c --- /dev/null +++ b/website/versioned_docs/version-22.3/MongoDB.md @@ -0,0 +1,128 @@ +--- +id: version-22.3-mongodb +title: Using with MongoDB +original_id: mongodb +--- + +With the [Global Setup/Teardown](Configuration.md#globalsetup-string) and +[Async Test Environment](Configuration.md#testenvironment-string) APIs, Jest can +work smoothly with [MongoDB](https://www.mongodb.com/). + +## A jest-mongodb example + +The basic idea is to: + +1. Spin up in-memory mongodb server +2. Export a global variable with mongo URI +3. Write tests for queries / aggregations using a real database ✨ +4. Shut down mongodb server using Global Teardown + +Here's an example of the GlobalSetup script + +```js +// setup.js +const MongodbMemoryServer = require('mongodb-memory-server'); + +const MONGO_DB_NAME = 'jest'; +const mongod = new MongodbMemoryServer.default({ + instance: { + dbName: MONGO_DB_NAME, + }, + binary: { + version: '3.2.19', + }, +}); + +module.exports = function() { + global.__MONGOD__ = mongod; + global.__MONGO_DB_NAME__ = MONGO_DB_NAME; +}; +``` + +Then we need a custom Test Environment for Mongo + +```js +// mongo-environment.js +class MongoEnvironment extends NodeEnvironment { + constructor(config) { + super(config); + } + + async setup() { + console.log('Setup MongoDB Test Environment'); + + this.global.__MONGO_URI__ = await global.__MONGOD__.getConnectionString(); + this.global.__MONGO_DB_NAME__ = global.__MONGO_DB_NAME__; + + await super.setup(); + } + + async teardown() { + console.log('Teardown MongoDB Test Environment'); + + await super.teardown(); + } + + runScript(script) { + return super.runScript(script); + } +} +``` + +Finally we can shut down mongodb server + +```js +// teardown.js +module.exports = async function() { + await global.__MONGOD__.stop(); +}; +``` + +With all the things set up, we can now write our tests like this: + +```js +// test.js +const {MongoClient} = require('mongodb'); + +let connection; +let db; + +beforeAll(async () => { + connection = await MongoClient.connect(global.__MONGO_URI__); + db = await connection.db(global.__MONGO_DB_NAME__); +}); + +afterAll(async () => { + await connection.close(); + await db.close(); +}); + +it('should aggregate docs from collection', async () => { + const files = db.collection('files'); + + await files.insertMany([ + {type: 'Document'}, + {type: 'Video'}, + {type: 'Image'}, + {type: 'Document'}, + {type: 'Image'}, + {type: 'Document'}, + ]); + + const topFiles = await files + .aggregate([ + {$group: {_id: '$type', count: {$sum: 1}}}, + {$sort: {count: -1}}, + ]) + .toArray(); + + expect(topFiles).toEqual([ + {_id: 'Document', count: 3}, + {_id: 'Image', count: 2}, + {_id: 'Video', count: 1}, + ]); +}); +``` + +Here's the code of +[full working example](https://github.com/vladgolubev/jest-mongodb). diff --git a/website/versioned_docs/version-22.3/MoreResources.md b/website/versioned_docs/version-22.3/MoreResources.md new file mode 100644 index 000000000000..3a47bba502b9 --- /dev/null +++ b/website/versioned_docs/version-22.3/MoreResources.md @@ -0,0 +1,39 @@ +--- +id: version-22.3-more-resources +title: More Resources +original_id: more-resources +--- + +By now you should have a good idea of how Jest can make it easy to test your +applications. If you're interested in learning more, here's some related stuff +you might want to check out. + +### Browse the docs + +* Learn about [Snapshot Testing](SnapshotTesting.md), + [Mock Functions](MockFunctions.md), and more in our in-depth guides. +* Migrate your existing tests to Jest by following our + [migration guide](MigrationGuide.md). +* Learn how to [configure Jest](Configuration.md). +* Look at the full [API Reference](GlobalAPI.md). +* [Troubleshoot](Troubleshooting.md) problems with Jest. + +### Learn by example + +You will find a number of example test cases in the +[`examples`](https://github.com/facebook/jest/tree/master/examples) folder on +GitHub. You can also learn from the excellent tests used by the +[React](https://github.com/facebook/react/tree/master/src/renderers/__tests__), +[Relay](https://github.com/facebook/relay/tree/master/packages/react-relay/modern/__tests__), +and +[React Native](https://github.com/facebook/react-native/tree/master/Libraries/Animated/src/__tests__) +projects. + +### Join the community + +Ask questions and find answers from other Jest users like you. +[Reactiflux](http://www.reactiflux.com/) is a Discord chat where a lot of Jest +discussion happens. Check out the [#jest](https://discord.gg/MWRhKCj) channel. + +Follow the [Jest Twitter account](https://twitter.com/fbjest) and +[blog](/jest/blog/) to find out what's happening in the world of Jest. diff --git a/website/versioned_docs/version-22.3/Puppeteer.md b/website/versioned_docs/version-22.3/Puppeteer.md new file mode 100644 index 000000000000..496f49652500 --- /dev/null +++ b/website/versioned_docs/version-22.3/Puppeteer.md @@ -0,0 +1,103 @@ +--- +id: version-22.3-puppeteer +title: Using with puppeteer +original_id: puppeteer +--- + +With the [Global Setup/Teardown](Configuration.md#globalsetup-string) and +[Async Test Environment](Configuration.md#testenvironment-string) APIs, Jest can +work smoothly with [puppeteer](https://github.com/GoogleChrome/puppeteer). + +## A jest-puppeteer example + +The basic idea is to: + +1. launch & file the websocket endpoint of puppeteer with Global Setup +2. connect to puppeteer from each Test Environment +3. close puppeteer with Global Teardown + +Here's an example of the GlobalSetup script + +```js +// setup.js +module.exports = async function() { + const browser = await puppeteer.launch(); + // store the browser instance so we can teardown it later + global.__BROWSER__ = browser; + + // file the wsEndpoint for TestEnvironments + mkdirp.sync(DIR); + fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint()); +}; +``` + +Then we need a custom Test Environment for puppeteer + +```js +// puppeteer_environment.js +class PuppeteerEnvironment extends NodeEnvironment { + constructor(config) { + super(config); + } + + async setup() { + await super.setup(); + // get the wsEndpoint + const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8'); + if (!wsEndpoint) { + throw new Error('wsEndpoint not found'); + } + + // connect to puppeteer + this.global.__BROWSER__ = await puppeteer.connect({ + browserWSEndpoint: wsEndpoint, + }); + } + + async teardown() { + await super.teardown(); + } + + runScript(script) { + return super.runScript(script); + } +} +``` + +Finally we can close the puppeteer instance and clean-up the file + +```js +// teardown.js +module.exports = async function() { + // close the browser instance + await global.__BROWSER__.close(); + + // clean-up the wsEndpoint file + rimraf.sync(DIR); +}; +``` + +With all the things set up, we can now write our tests like this: + +```js +// test.js +describe( + '/ (Home Page)', + () => { + let page; + beforeAll(async () => { + page = await global.__BROWSER__.newPage(); + await page.goto('https://google.com'); + }, timeout); + + it('should load without error', async () => { + const text = await page.evaluate(() => document.body.textContent); + expect(text).toContain('google'); + }); + }, + timeout, +); +``` + +Here's the code of +[full working example](https://github.com/xfumihiro/jest-puppeteer-example). diff --git a/website/versioned_docs/version-22.3/SetupAndTeardown.md b/website/versioned_docs/version-22.3/SetupAndTeardown.md new file mode 100644 index 000000000000..ad97a201d4dd --- /dev/null +++ b/website/versioned_docs/version-22.3/SetupAndTeardown.md @@ -0,0 +1,222 @@ +--- +id: version-22.3-setup-teardown +title: Setup and Teardown +original_id: setup-teardown +--- + +Often while writing tests you have some setup work that needs to happen before +tests run, and you have some finishing work that needs to happen after tests +run. Jest provides helper functions to handle this. + +### Repeating Setup For Many Tests + +If you have some work you need to do repeatedly for many tests, you can use +`beforeEach` and `afterEach`. + +For example, let's say that several tests interact with a database of cities. +You have a method `initializeCityDatabase()` that must be called before each of +these tests, and a method `clearCityDatabase()` that must be called after each +of these tests. You can do this with: + +```js +beforeEach(() => { + initializeCityDatabase(); +}); + +afterEach(() => { + clearCityDatabase(); +}); + +test('city database has Vienna', () => { + expect(isCity('Vienna')).toBeTruthy(); +}); + +test('city database has San Juan', () => { + expect(isCity('San Juan')).toBeTruthy(); +}); +``` + +`beforeEach` and `afterEach` can handle asynchronous code in the same ways that +[tests can handle asynchronous code](TestingAsyncCode.md) - they can either take +a `done` parameter or return a promise. For example, if +`initializeCityDatabase()` returned a promise that resolved when the database +was initialized, we would want to return that promise: + +```js +beforeEach(() => { + return initializeCityDatabase(); +}); +``` + +### One-Time Setup + +In some cases, you only need to do setup once, at the beginning of a file. This +can be especially bothersome when the setup is asynchronous, so you can't just +do it inline. Jest provides `beforeAll` and `afterAll` to handle this situation. + +For example, if both `initializeCityDatabase` and `clearCityDatabase` returned +promises, and the city database could be reused between tests, we could change +our test code to: + +```js +beforeAll(() => { + return initializeCityDatabase(); +}); + +afterAll(() => { + return clearCityDatabase(); +}); + +test('city database has Vienna', () => { + expect(isCity('Vienna')).toBeTruthy(); +}); + +test('city database has San Juan', () => { + expect(isCity('San Juan')).toBeTruthy(); +}); +``` + +### Scoping + +By default, the `before` and `after` blocks apply to every test in a file. You +can also group tests together using a `describe` block. When they are inside a +`describe` block, the `before` and `after` blocks only apply to the tests within +that `describe` block. + +For example, let's say we had not just a city database, but also a food +database. We could do different setup for different tests: + +```js +// Applies to all tests in this file +beforeEach(() => { + return initializeCityDatabase(); +}); + +test('city database has Vienna', () => { + expect(isCity('Vienna')).toBeTruthy(); +}); + +test('city database has San Juan', () => { + expect(isCity('San Juan')).toBeTruthy(); +}); + +describe('matching cities to foods', () => { + // Applies only to tests in this describe block + beforeEach(() => { + return initializeFoodDatabase(); + }); + + test('Vienna <3 sausage', () => { + expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true); + }); + + test('San Juan <3 plantains', () => { + expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true); + }); +}); +``` + +Note that the top-level `beforeEach` is executed before the `beforeEach` inside +the `describe` block. It may help to illustrate the order of execution of all +hooks. + +```js +beforeAll(() => console.log('1 - beforeAll')); +afterAll(() => console.log('1 - afterAll')); +beforeEach(() => console.log('1 - beforeEach')); +afterEach(() => console.log('1 - afterEach')); +test('', () => console.log('1 - test')); +describe('Scoped / Nested block', () => { + beforeAll(() => console.log('2 - beforeAll')); + afterAll(() => console.log('2 - afterAll')); + beforeEach(() => console.log('2 - beforeEach')); + afterEach(() => console.log('2 - afterEach')); + test('', () => console.log('2 - test')); +}); + +// 1 - beforeAll +// 1 - beforeEach +// 1 - test +// 1 - afterEach +// 2 - beforeAll +// 1 - beforeEach +// 2 - beforeEach +// 2 - test +// 2 - afterEach +// 1 - afterEach +// 2 - afterAll +// 1 - afterAll +``` + +### Order of execution of describe and test blocks + +Jest executes all describe handlers in a test file _before_ it executes any of +the actual tests. This is another reason to do setup and teardown in `before*` +and `after*` handlers rather in the describe blocks. Once the describe blocks +are complete, by default Jest runs all the tests serially in the order they were +encountered in the collection phase, waiting for each to finish and be tidied up +before moving on. + +Consider the following illustrative test file and output: + +```js +describe('outer', () => { + console.log('describe outer-a'); + + describe('describe inner 1', () => { + console.log('describe inner 1'); + test('test 1', () => { + console.log('test for describe inner 1'); + expect(true).toEqual(true); + }); + }); + + console.log('describe outer-b'); + + test('test 1', () => { + console.log('test for describe outer'); + expect(true).toEqual(true); + }); + + describe('describe inner 2', () => { + console.log('describe inner 2'); + test('test for describe inner 2', () => { + console.log('test for describe inner 2'); + expect(false).toEqual(false); + }); + }); + + console.log('describe outer-c'); +}); + +// describe outer-a +// describe inner 1 +// describe outer-b +// describe inner 2 +// describe outer-c +// test for describe inner 1 +// test for describe outer +// test for describe inner 2 +``` + +### General Advice + +If a test is failing, one of the first things to check should be whether the +test is failing when it's the only test that runs. In Jest it's simple to run +only one test - just temporarily change that `test` command to a `test.only`: + +```js +test.only('this will be the only test that runs', () => { + expect(true).toBe(false); +}); + +test('this test will not run', () => { + expect('A').toBe('A'); +}); +``` + +If you have a test that often fails when it's run as part of a larger suite, but +doesn't fail when you run it alone, it's a good bet that something from a +different test is interfering with this one. You can often fix this by clearing +some shared state with `beforeEach`. If you're not sure whether some shared +state is being modified, you can also try a `beforeEach` that just logs data. diff --git a/website/versioned_docs/version-22.3/SnapshotTesting.md b/website/versioned_docs/version-22.3/SnapshotTesting.md new file mode 100644 index 000000000000..33b1ae2f7c7d --- /dev/null +++ b/website/versioned_docs/version-22.3/SnapshotTesting.md @@ -0,0 +1,236 @@ +--- +id: version-22.3-snapshot-testing +title: Snapshot Testing +original_id: snapshot-testing +--- + +Snapshot tests are a very useful tool whenever you want to make sure your UI +does not change unexpectedly. + +A typical snapshot test case for a mobile app renders a UI component, takes a +screenshot, then compares it to a reference image stored alongside the test. The +test will fail if the two images do not match: either the change is unexpected, +or the screenshot needs to be updated to the new version of the UI component. + +## Snapshot Testing with Jest + +A similar approach can be taken when it comes to testing your React components. +Instead of rendering the graphical UI, which would require building the entire +app, you can use a test renderer to quickly generate a serializable value for +your React tree. Consider this +[example test](https://github.com/facebook/jest/blob/master/examples/snapshot/__tests__/link.react.test.js) +for a simple +[Link component](https://github.com/facebook/jest/blob/master/examples/snapshot/Link.react.js): + +```javascript +import React from 'react'; +import Link from '../Link.react'; +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + const tree = renderer + .create(Facebook) + .toJSON(); + expect(tree).toMatchSnapshot(); +}); +``` + +The first time this test is run, Jest creates a +[snapshot file](https://github.com/facebook/jest/blob/master/examples/snapshot/__tests__/__snapshots__/link.react.test.js.snap) +that looks like this: + +```javascript +exports[`renders correctly 1`] = ` + + Facebook + +`; +``` + +The snapshot artifact should be committed alongside code changes, and reviewed +as part of your code review process. Jest uses +[pretty-format](https://github.com/facebook/jest/tree/master/packages/pretty-format) +to make snapshots human-readable during code review. On subsequent test runs +Jest will simply compare the rendered output with the previous snapshot. If they +match, the test will pass. If they don't match, either the test runner found a +bug in your code that should be fixed, or the implementation has changed and the +snapshot needs to be updated. + +More information on how snapshot testing works and why we built it can be found +on the +[release blog post](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html). +We recommend reading +[this blog post](http://benmccormick.org/2016/09/19/testing-with-jest-snapshots-first-impressions/) +to get a good sense of when you should use snapshot testing. We also recommend +watching this +[egghead video](https://egghead.io/lessons/javascript-use-jest-s-snapshot-testing-feature?pl=testing-javascript-with-jest-a36c4074) +on Snapshot Testing with Jest. + +### Updating Snapshots + +It's straightforward to spot when a snapshot test fails after a bug has been +introduced. When that happens, go ahead and fix the issue and make sure your +snapshot tests are passing again. Now, let's talk about the case when a snapshot +test is failing due to an intentional implementation change. + +One such situation can arise if we intentionally change the address the Link +component in our example is pointing to. + +```javascript +// Updated test case with a Link to a different address +it('renders correctly', () => { + const tree = renderer + .create(Instagram) + .toJSON(); + expect(tree).toMatchSnapshot(); +}); +``` + +In that case, Jest will print this output: + +![](/jest/img/content/failedSnapshotTest.png) + +Since we just updated our component to point to a different address, it's +reasonable to expect changes in the snapshot for this component. Our snapshot +test case is failing because the snapshot for our updated component no longer +matches the snapshot artifact for this test case. + +To resolve this, we will need to update our snapshot artifacts. You can run Jest +with a flag that will tell it to re-generate snapshots: + +```bash +jest --updateSnapshot +``` + +Go ahead and accept the changes by running the above command. You may also use +the equivalent single-character `-u` flag to re-generate snapshots if you +prefer. This will re-generate snapshot artifacts for all failing snapshot tests. +If we had any additional failing snapshot tests due to an unintentional bug, we +would need to fix the bug before re-generating snapshots to avoid recording +snapshots of the buggy behavior. + +If you'd like to limit which snapshot test cases get re-generated, you can pass +an additional `--testNamePattern` flag to re-record snapshots only for those +tests that match the pattern. + +You can try out this functionality by cloning the +[snapshot example](https://github.com/facebook/jest/tree/master/examples/snapshot), +modifying the `Link` component, and running Jest. + +### Interactive Snapshot Mode + +Failed snapshots can also be updated interactively in watch mode: + +![](/jest/img/content/interactiveSnapshot.png) + +Once you enter Interactive Snapshot Mode, Jest will step you through the failed +snapshots one test suite at a time and give you the opportunity to review the +failed output. + +From here you can choose to update that snapshot or skip to the next: + +![](/jest/img/content/interactiveSnapshotUpdate.gif) + +### Tests Should Be Deterministic + +Your tests should be deterministic. That is, running the same tests multiple +times on a component that has not changed should produce the same results every +time. You're responsible for making sure your generated snapshots do not include +platform specific or other non-deterministic data. + +For example, if you have a +[Clock](https://github.com/facebook/jest/blob/master/examples/snapshot/Clock.react.js) +component that uses `Date.now()`, the snapshot generated from this component +will be different every time the test case is run. In this case we can +[mock the Date.now() method](MockFunctions.md) to return a consistent value +every time the test is run: + +```js +Date.now = jest.fn(() => 1482363367071); +``` + +Now, every time the snapshot test case runs, `Date.now()` will return +`1482363367071` consistently. This will result in the same snapshot being +generated for this component regardless of when the test is run. + +### Snapshots are not written automatically on Continuous Integration systems (CI) + +As of Jest 20, snapshots in Jest are not automatically written when Jest is run +in a CI system without explicitly passing `--updateSnapshot`. It is expected +that all snapshots are part of the code that is run on CI and since new +snapshots automatically pass, they should not pass a test run on a CI system. It +is recommended to always commit all snapshots and to keep them in version +control. + +## Frequently Asked Questions + +### Should snapshot files be committed? + +Yes, all snapshot files should be committed alongside the modules they are +covering and their tests. They should be considered as part of a test, similar +to the value of any other assertion in Jest. In fact, snapshots represent the +state of the source modules at any given point in time. In this way, when the +source modules are modified, Jest can tell what changed from the previous +version. It can also provide a lot of additional context during code review in +which reviewers can study your changes better. + +### Does snapshot testing only work with React components? + +[React](TutorialReact.md) and [React Native](TutorialReactNative.md) components +are a good use case for snapshot testing. However, snapshots can capture any +serializable value and should be used anytime the goal is testing whether the +output is correct. The Jest repository contains many examples of testing the +output of Jest itself, the output of Jest's assertion library as well as log +messages from various parts of the Jest codebase. See an example of +[snapshotting CLI output](https://github.com/facebook/jest/blob/master/integration-tests/__tests__/console.test.js) +in the Jest repo. + +### What's the difference between snapshot testing and visual regression testing? + +Snapshot testing and visual regression testing are two distinct ways of testing +UIs, and they serve different purposes. Visual regression testing tools take +screenshots of web pages and compare the resulting images pixel by pixel. With +Snapshot testing values are serialized, stored within text files and compared +using a diff algorithm. There are different trade-offs to consider and we listed +the reasons why snapshot testing was built in the +[Jest blog](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html#why-snapshot-testing). + +### Does snapshot testing substitute unit testing? + +Snapshot testing is only one of more than 20 assertions that ship with Jest. The +aim of snapshot testing is not to replace existing unit tests, but providing +additional value and making testing painless. In some scenarios, snapshot +testing can potentially remove the need for unit testing for a particular set of +functionalities (e.g. React components), but they can work together as well. + +### What is the performance of snapshot testing regarding speed and size of the generated files? + +Jest has been rewritten with performance in mind, and snapshot testing is not an +exception. Since snapshots are stored within text files, this way of testing is +fast and reliable. Jest generates a new file for each test file that invokes the +`toMatchSnapshot` matcher. The size of the snapshots is pretty small: For +reference, the size of all snapshot files in the Jest codebase itself is less +than 300 KB. + +### How do I resolve conflicts within snapshot files? + +Snapshot files must always represent the current state of the modules they are +covering. Therefore, if you are merging two branches and encounter a conflict in +the snapshot files, you can either resolve the conflict manually or to update +the snapshot file by running Jest and inspecting the result. + +### Is it possible to apply test-driven development principles with snapshot testing? + +Although it is possible to write snapshot files manually, that is usually not +approachable. Snapshots help figuring out whether the output of the modules +covered by tests is changed, rather than giving guidance to design the code in +the first place. + +### Does code coverage work with snapshots testing? + +Yes, just like with any other test. diff --git a/website/versioned_docs/version-22.3/TestingAsyncCode.md b/website/versioned_docs/version-22.3/TestingAsyncCode.md new file mode 100644 index 000000000000..f8f8073b219f --- /dev/null +++ b/website/versioned_docs/version-22.3/TestingAsyncCode.md @@ -0,0 +1,160 @@ +--- +id: version-22.3-asynchronous +title: Testing Asynchronous Code +original_id: asynchronous +--- + +It's common in JavaScript for code to run asynchronously. When you have code +that runs asynchronously, Jest needs to know when the code it is testing has +completed, before it can move on to another test. Jest has several ways to +handle this. + +### Callbacks + +The most common asynchronous pattern is callbacks. + +For example, let's say that you have a `fetchData(callback)` function that +fetches some data and calls `callback(data)` when it is complete. You want to +test that this returned data is just the string `'peanut butter'`. + +By default, Jest tests complete once they reach the end of their execution. That +means this test will _not_ work as intended: + +```js +// Don't do this! +test('the data is peanut butter', () => { + function callback(data) { + expect(data).toBe('peanut butter'); + } + + fetchData(callback); +}); +``` + +The problem is that the test will complete as soon as `fetchData` completes, +before ever calling the callback. + +There is an alternate form of `test` that fixes this. Instead of putting the +test in a function with an empty argument, use a single argument called `done`. +Jest will wait until the `done` callback is called before finishing the test. + +```js +test('the data is peanut butter', done => { + function callback(data) { + expect(data).toBe('peanut butter'); + done(); + } + + fetchData(callback); +}); +``` + +If `done()` is never called, the test will fail, which is what you want to +happen. + +### Promises + +If your code uses promises, there is a simpler way to handle asynchronous tests. +Just return a promise from your test, and Jest will wait for that promise to +resolve. If the promise is rejected, the test will automatically fail. + +For example, let's say that `fetchData`, instead of using a callback, returns a +promise that is supposed to resolve to the string `'peanut butter'`. We could +test it with: + +```js +test('the data is peanut butter', () => { + expect.assertions(1); + return fetchData().then(data => { + expect(data).toBe('peanut butter'); + }); +}); +``` + +Be sure to return the promise - if you omit this `return` statement, your test +will complete before `fetchData` completes. + +If you expect a promise to be rejected use the `.catch` method. Make sure to add +`expect.assertions` to verify that a certain number of assertions are called. +Otherwise a fulfilled promise would not fail the test. + +```js +test('the fetch fails with an error', () => { + expect.assertions(1); + return fetchData().catch(e => expect(e).toMatch('error')); +}); +``` + +### `.resolves` / `.rejects` + +##### available in Jest **20.0.0+** + +You can also use the `.resolves` matcher in your expect statement, and Jest will +wait for that promise to resolve. If the promise is rejected, the test will +automatically fail. + +```js +test('the data is peanut butter', () => { + expect.assertions(1); + return expect(fetchData()).resolves.toBe('peanut butter'); +}); +``` + +Be sure to return the assertion—if you omit this `return` statement, your test +will complete before `fetchData` completes. + +If you expect a promise to be rejected use the `.rejects` matcher. It works +analogically to the `.resolves` matcher. If the promise is fulfilled, the test +will automatically fail. + +```js +test('the fetch fails with an error', () => { + expect.assertions(1); + return expect(fetchData()).rejects.toMatch('error'); +}); +``` + +### Async/Await + +Alternatively, you can use `async` and `await` in your tests. To write an async +test, just use the `async` keyword in front of the function passed to `test`. +For example, the same `fetchData` scenario can be tested with: + +```js +test('the data is peanut butter', async () => { + expect.assertions(1); + const data = await fetchData(); + expect(data).toBe('peanut butter'); +}); + +test('the fetch fails with an error', async () => { + expect.assertions(1); + try { + await fetchData(); + } catch (e) { + expect(e).toMatch('error'); + } +}); +``` + +Of course, you can combine `async` and `await` with `.resolves` or `.rejects` +(available in Jest **20.0.0+**). + +```js +test('the data is peanut butter', async () => { + expect.assertions(1); + await expect(fetchData()).resolves.toBe('peanut butter'); +}); + +test('the fetch fails with an error', async () => { + expect.assertions(1); + await expect(fetchData()).rejects.toMatch('error'); +}); +``` + +In these cases, `async` and `await` are effectively just syntactic sugar for the +same logic as the promises example uses. + +None of these forms is particularly superior to the others, and you can mix and +match them across a codebase or even in a single file. It just depends on which +style makes your tests simpler. diff --git a/website/versioned_docs/version-22.3/TestingFrameworks.md b/website/versioned_docs/version-22.3/TestingFrameworks.md new file mode 100644 index 000000000000..fdf933080787 --- /dev/null +++ b/website/versioned_docs/version-22.3/TestingFrameworks.md @@ -0,0 +1,39 @@ +--- +id: version-22.3-testing-frameworks +title: Testing Web Frameworks +original_id: testing-frameworks +--- + +Although Jest may be considered a React-specific test runner, in fact it is a +universal testing platform, with the ability to adapt to any JavaScript library +or framework. In this section we'd like to link to community posts and articles +about integrating Jest into other popular JS libraries. + +## Vue.js + +* [Testing Vue.js components with Jest](https://alexjoverm.github.io/series/Unit-Testing-Vue-js-Components-with-the-Official-Vue-Testing-Tools-and-Jest/) + by Alex Jover Morales ([@alexjoverm](https://twitter.com/alexjoverm)) +* [Jest for all: Episode 1 — Vue.js](https://medium.com/@kentaromiura_the_js_guy/jest-for-all-episode-1-vue-js-d616bccbe186#.d573vrce2) + by Cristian Carlesso ([@kentaromiura](https://twitter.com/kentaromiura)) + +## AngularJS + +* [Testing an AngularJS app with Jest](https://medium.com/aya-experience/testing-an-angularjs-app-with-jest-3029a613251) + by Matthieu Lux ([@Swiip](https://twitter.com/Swiip)) +* [Running AngularJS Tests with Jest](https://engineering.talentpair.com/running-angularjs-tests-with-jest-49d0cc9c6d26) + by Ben Brandt ([@benjaminbrandt](https://twitter.com/benjaminbrandt)) + +## Angular + +* [Testing Angular faster with Jest](https://www.xfive.co/blog/testing-angular-faster-jest/) + by Michał Pierzchała ([@thymikee](https://twitter.com/thymikee)) + +## MobX + +* [How to Test React and MobX with Jest](https://semaphoreci.com/community/tutorials/how-to-test-react-and-mobx-with-jest) + by Will Stern ([@willsterndev](https://twitter.com/willsterndev)) + +## Redux + +* [Writing Tests](http://redux.js.org/docs/recipes/WritingTests.html) by Redux + docs diff --git a/website/versioned_docs/version-22.3/TimerMocks.md b/website/versioned_docs/version-22.3/TimerMocks.md new file mode 100644 index 000000000000..6aad2822ff33 --- /dev/null +++ b/website/versioned_docs/version-22.3/TimerMocks.md @@ -0,0 +1,182 @@ +--- +id: version-22.3-timer-mocks +title: Timer Mocks +original_id: timer-mocks +--- + +The native timer functions (i.e., `setTimeout`, `setInterval`, `clearTimeout`, +`clearInterval`) are less than ideal for a testing environment since they depend +on real time to elapse. Jest can swap out timers with functions that allow you +to control the passage of time. +[Great Scott!](https://www.youtube.com/watch?v=5gVv10J4nio) + +```javascript +// timerGame.js +'use strict'; + +function timerGame(callback) { + console.log('Ready....go!'); + setTimeout(() => { + console.log('Times up -- stop!'); + callback && callback(); + }, 1000); +} + +module.exports = timerGame; +``` + +```javascript +// __tests__/timerGame-test.js +'use strict'; + +jest.useFakeTimers(); + +test('waits 1 second before ending the game', () => { + const timerGame = require('../timerGame'); + timerGame(); + + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000); +}); +``` + +Here we enable fake timers by calling `jest.useFakeTimers();`. This mocks out +setTimeout and other timer functions with mock functions. + +## Run All Timers + +Another test we might want to write for this module is one that asserts that the +callback is called after 1 second. To do this, we're going to use Jest's timer +control APIs to fast-forward time right in the middle of the test: + +```javascript +test('calls the callback after 1 second', () => { + const timerGame = require('../timerGame'); + const callback = jest.fn(); + + timerGame(callback); + + // At this point in time, the callback should not have been called yet + expect(callback).not.toBeCalled(); + + // Fast-forward until all timers have been executed + jest.runAllTimers(); + + // Now our callback should have been called! + expect(callback).toBeCalled(); + expect(callback).toHaveBeenCalledTimes(1); +}); +``` + +## Run Pending Timers + +There are also scenarios where you might have a recursive timer -- that is a +timer that sets a new timer in its own callback. For these, running all the +timers would be an endless loop… so something like `jest.runAllTimers()` is not +desirable. For these cases you might use `jest.runOnlyPendingTimers()`: + +```javascript +// infiniteTimerGame.js +'use strict'; + +function infiniteTimerGame(callback) { + console.log('Ready....go!'); + + setTimeout(() => { + console.log('Times up! 10 seconds before the next game starts...'); + callback && callback(); + + // Schedule the next game in 10 seconds + setTimeout(() => { + infiniteTimerGame(callback); + }, 10000); + }, 1000); +} + +module.exports = infiniteTimerGame; +``` + +```javascript +// __tests__/infiniteTimerGame-test.js +'use strict'; + +jest.useFakeTimers(); + +describe('infiniteTimerGame', () => { + test('schedules a 10-second timer after 1 second', () => { + const infiniteTimerGame = require('../infiniteTimerGame'); + const callback = jest.fn(); + + infiniteTimerGame(callback); + + // At this point in time, there should have been a single call to + // setTimeout to schedule the end of the game in 1 second. + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000); + + // Fast forward and exhaust only currently pending timers + // (but not any new timers that get created during that process) + jest.runOnlyPendingTimers(); + + // At this point, our 1-second timer should have fired it's callback + expect(callback).toBeCalled(); + + // And it should have created a new timer to start the game over in + // 10 seconds + expect(setTimeout).toHaveBeenCalledTimes(2); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000); + }); +}); +``` + +## Advance Timers by Time + +##### renamed from `runTimersToTime` to `advanceTimersByTime` in Jest **22.0.0** + +Another possibility is use `jest.advanceTimersByTime(msToRun)`. When this API is +called, all timers are advanced by `msToRun` milliseconds. All pending +"macro-tasks" that have been queued via setTimeout() or setInterval(), and would +be executed during this time frame, will be executed. Additionally if those +macro-tasks schedule new macro-tasks that would be executed within the same time +frame, those will be executed until there are no more macro-tasks remaining in +the queue that should be run within msToRun milliseconds. + +```javascript +// timerGame.js +'use strict'; + +function timerGame(callback) { + console.log('Ready....go!'); + setTimeout(() => { + console.log('Times up -- stop!'); + callback && callback(); + }, 1000); +} + +module.exports = timerGame; +``` + +```javascript +it('calls the callback after 1 second via advanceTimersByTime', () => { + const timerGame = require('../timerGame'); + const callback = jest.fn(); + + timerGame(callback); + + // At this point in time, the callback should not have been called yet + expect(callback).not.toBeCalled(); + + // Fast-forward until all timers have been executed + jest.advanceTimersByTime(1000); + + // Now our callback should have been called! + expect(callback).toBeCalled(); + expect(callback).toHaveBeenCalledTimes(1); +}); +``` + +Lastly, it may occasionally be useful in some tests to be able to clear all of +the pending timers. For this, we have `jest.clearAllTimers()`. + +The code for this example is available at +[examples/timer](https://github.com/facebook/jest/tree/master/examples/timer). diff --git a/website/versioned_docs/version-22.3/Troubleshooting.md b/website/versioned_docs/version-22.3/Troubleshooting.md new file mode 100644 index 000000000000..0eb0426f1840 --- /dev/null +++ b/website/versioned_docs/version-22.3/Troubleshooting.md @@ -0,0 +1,317 @@ +--- +id: version-22.3-troubleshooting +title: Troubleshooting +original_id: troubleshooting +--- + +Uh oh, something went wrong? Use this guide to resolve issues with Jest. + +### Tests are Failing and You Don't Know Why + +Try using the debugging support built into Node. + +Place a `debugger;` statement in any of your tests, and then, in your project's +directory, run: + +```bash +node --inspect-brk node_modules/.bin/jest --runInBand [any other arguments here] +or on Windows +node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand [any other arguments here] +``` + +This will run Jest in a Node process that an external debugger can connect to. +Note that the process will pause until the debugger has connected to it. + +To debug in Google Chrome (or any Chromium-based browser), simply open your +browser and go to `chrome://inspect` and click on "Open Dedicated DevTools for +Node", which will give you a list of available node instances you can connect +to. Simply click on the address displayed in the terminal (usually something +like `localhost:9229`) after running the above command, and you will be able to +debug Jest using Chrome's DevTools. + +The Chrome Developer Tools will be displayed, and a breakpoint will be set at +the first line of the Jest CLI script (this is done simply to give you time to +open the developer tools and to prevent Jest from executing before you have time +to do so). Click the button that looks like a "play" button in the upper right +hand side of the screen to continue execution. When Jest executes the test that +contains the `debugger` statement, execution will pause and you can examine the +current scope and call stack. + +> Note: the `--runInBand` cli option makes sure Jest runs test in the same +> process rather than spawning processes for individual tests. Normally Jest +> parallelizes test runs across processes but it is hard to debug many processes +> at the same time. + +### Debugging in VS Code + +There are multiple ways to debug Jest tests with +[Visual Studio Code's](https://code.visualstudio.com) built in +[debugger](https://code.visualstudio.com/docs/nodejs/nodejs-debugging). + +To attach the built-in debugger, run your tests as aforementioned: + +```bash +node --inspect-brk node_modules/.bin/jest --runInBand [any other arguments here] +or on Windows +node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand [any other arguments here] +``` + +Then attach VS Code's debugger using the following `launch.json` config: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach", + "port": 9229 + } + ] +} +``` + +To automatically launch and attach to a process running your tests, use the +following configuration: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Jest Tests", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/node_modules/.bin/jest", + "--runInBand" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + } + ] +} +``` + +or the following for Windows: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Jest Tests", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/node_modules/jest/bin/jest.js", + "--runInBand" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + } + ] +} +``` + +If you are using Facebook's +[`create-react-app`](https://github.com/facebookincubator/create-react-app), you +can debug your Jest tests with the following configuration: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug CRA Tests", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/react-scripts", + "args": ["test", "--runInBand", "--no-cache", "--env=jsdom"], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + } + ] +} +``` + +More information on Node debugging can be found +[here](https://nodejs.org/api/debugger.html). + +### Debugging in WebStorm + +The easiest way to debug Jest tests in +[WebStorm](https://www.jetbrains.com/webstorm/) is using +`Jest run/debug configuration`. It will launch tests and automatically attach +debugger. + +In the WebStorm menu `Run` select `Edit Configurations...`. Then click `+` and +select `Jest`. Optionally specify the Jest configuration file, additional +options, and environment variables. Save the configuration, put the breakpoints +in the code, then click the green debug icon to start debugging. + +If you are using Facebook's +[`create-react-app`](https://github.com/facebookincubator/create-react-app), in +the Jest run/debug configuration specify the path to the `react-scripts` package +in the Jest package field and add `--env=jsdom` to the Jest options field. + +### Caching Issues + +The transform script was changed or babel was updated and the changes aren't +being recognized by Jest? + +Retry with [`--no-cache`](CLI.md#cache). Jest caches transformed module files to +speed up test execution. If you are using your own custom transformer, consider +adding a `getCacheKey` function to it: +[getCacheKey in Relay](https://github.com/facebook/relay/blob/58cf36c73769690f0bbf90562707eadb062b029d/scripts/jest/preprocessor.js#L56-L61). + +### Unresolved Promises + +If a promise doesn't resolve at all, this error might be thrown: + +```bash +- Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.` +``` + +Most commonly this is being caused by conflicting Promise implementations. +Consider replacing the global promise implementation with your own, for example +`global.Promise = require.requireActual('promise');` and/or consolidate the used +Promise libraries to a single one. + +If your test is long running, you may want to consider to increase the timeout +by calling `jest.setTimeout` + +```js +jest.setTimeout(10000); // 10 second timeout +``` + +### Watchman Issues + +Try running Jest with [`--no-watchman`](CLI.md#watchman) or set the `watchman` +configuration option to `false`. + +Also see +[watchman troubleshooting](https://facebook.github.io/watchman/docs/troubleshooting.html). + +### Tests are Extremely Slow on Docker and/or Continuous Integration (CI) server. + +While Jest is most of the time extremely fast on modern multi-core computers +with fast SSDs, it may be slow on certain setups as our users +[have](https://github.com/facebook/jest/issues/1395) +[discovered](https://github.com/facebook/jest/issues/1524#issuecomment-260246008). + +Based on the +[findings](https://github.com/facebook/jest/issues/1524#issuecomment-262366820), +one way to mitigate this issue and improve the speed by up to 50% is to run +tests sequentially. + +In order to do this you can run tests in the same thread using +[`--runInBand`](CLI.md#runinband): + +```bash +# Using Jest CLI +jest --runInBand + +# Using npm test (e.g. with create-react-app) +npm test -- --runInBand +``` + +Another alternative to expediting test execution time on Continuous Integration +Servers such as Travis-CI is to set the max worker pool to ~_4_. Specifically on +Travis-CI, this can reduce test execution time in half. Note: The Travis CI +_free_ plan available for open source projects only includes 2 CPU cores. + +```bash +# Using Jest CLI +jest --maxWorkers=4 + +# Using npm test (e.g. with create-react-app) +npm test -- --maxWorkers=4 +``` + +### Tests are slow when leveraging automocking + +Whether via [`automock: true`](configuration.html#automock-boolean) in config or +lots of +[`jest.mock('my-module')`](jest-object.html#jestmockmodulename-factory-options) +calls in tests, automocking has a performance cost that can add up in large +projects. The more dependencies a module has, the more work Jest has to do to +mock it. Something that can offset this performance cost significantly is adding +a code transformer that moves `import` or `require` calls from the top of a +module, where they are always executed, down into the body of the module, where +they are usually not executed. This can lower the number of modules Jest has to +load when running your tests by a considerable amount. + +To transform `import` statements, there is +[babel-plugin-transform-inline-imports-commonjs](https://github.com/zertosh/babel-plugin-transform-inline-imports-commonjs), +and to transform `require` statements, there is +[Facebook's `inline-requires` babel plugin](https://github.com/facebook/fbjs/blob/master/packages/babel-preset-fbjs/plugins/inline-requires.js), +which is part of the `babel-preset-fbjs` package. + +### I'm using npm3 and my node_modules aren't properly loading. + +Upgrade `jest-cli` to `0.9.0` or above. + +### I'm using babel and my unmocked imports aren't working? + +Upgrade `jest-cli` to `0.9.0` or above. + +Explanation: + +```js +jest.dontMock('foo'); + +import foo from './foo'; +``` + +In ES6, import statements get hoisted before all other + +```js +const foo = require('foo'); +jest.dontMock('foo'); // Oops! +``` + +In Jest 0.9.0, a new API `jest.unmock` was introduced. Together with a plugin +for babel, this will now work properly when using `babel-jest`: + +```js +jest.unmock('./foo'); // Use unmock! + +import foo from './foo'; + +// foo is not mocked! +``` + +See the [Getting Started]GettingStarted.md#using-babel) guide on how to enable +babel support. + +### I upgraded to Jest 0.9.0 and my tests are now failing? + +Jest is now using Jasmine 2 by default. It should be easy to upgrade using the +Jasmine [upgrade guide](http://jasmine.github.io/2.0/introduction.html). + +If you would like to continue using Jasmine 1, set the `testRunner` config +option to `jasmine1` or pass `--testRunner=jasmine1` as a command line option. + +### Compatibility issues + +Jest takes advantage of new features added to Node 6. We recommend that you +upgrade to the latest stable release of Node. The minimum supported version is +`v6.0.0`. Versions `0.x.x` and `4.x.x` are not supported. + +### `coveragePathIgnorePatterns` seems to not have any effect. + +Make sure you are not using the `babel-plugin-istanbul` plugin. Jest wraps +Istanbul, and therefore also tells Istanbul what files to instrument with +coverage collection. When using `babel-plugin-istanbul`, every file that is +processed by Babel will have coverage collection code, hence it is not being +ignored by `coveragePathIgnorePatterns`. + +### Still unresolved? + +See [Help](/jest/help.html). diff --git a/website/versioned_docs/version-22.3/TutorialAsync.md b/website/versioned_docs/version-22.3/TutorialAsync.md new file mode 100644 index 000000000000..c67e65c18cf5 --- /dev/null +++ b/website/versioned_docs/version-22.3/TutorialAsync.md @@ -0,0 +1,190 @@ +--- +id: version-22.3-tutorial-async +title: An Async Example +original_id: tutorial-async +--- + +First, enable Babel support in Jest as documented in the +[Getting Started](GettingStarted.md#using-babel) guide. + +Let's implement a simple module that fetches user data from an API and returns +the user name. + +```js +// user.js +import request from './request'; + +export function getUserName(userID) { + return request('/users/' + userID).then(user => user.name); +} +``` + +In the above implementation we expect the `request.js` module to return a +promise. We chain a call to `then` to receive the user name. + +Now imagine an implementation of `request.js` that goes to the network and +fetches some user data: + +```js +// request.js +const http = require('http'); + +export default function request(url) { + return new Promise(resolve => { + // This is an example of an http request, for example to fetch + // user data from an API. + // This module is being mocked in __mocks__/request.js + http.get({path: url}, response => { + let data = ''; + response.on('data', _data => (data += _data)); + response.on('end', () => resolve(data)); + }); + }); +} +``` + +Because we don't want to go to the network in our test, we are going to create a +manual mock for our `request.js` module in the `__mocks__` folder (the folder is +case-sensitive, `__MOCKS__` will not work). It could look something like this: + +```js +// __mocks__/request.js +const users = { + 4: {name: 'Mark'}, + 5: {name: 'Paul'}, +}; + +export default function request(url) { + return new Promise((resolve, reject) => { + const userID = parseInt(url.substr('/users/'.length), 10); + process.nextTick( + () => + users[userID] + ? resolve(users[userID]) + : reject({ + error: 'User with ' + userID + ' not found.', + }), + ); + }); +} +``` + +Now let's write a test for our async functionality. + +```js +// __tests__/user-test.js +jest.mock('../request'); + +import * as user from '../user'; + +// The assertion for a promise must be returned. +it('works with promises', () => { + expect.assertions(1); + return user.getUserName(4).then(data => expect(data).toEqual('Mark')); +}); +``` + +We call `jest.mock('../request')` to tell Jest to use our manual mock. `it` +expects the return value to be a Promise that is going to be resolved. You can +chain as many Promises as you like and call `expect` at any time, as long as you +return a Promise at the end. + +### `.resolves` + +##### available in Jest **20.0.0+** + +There is a less verbose way using `resolves` to unwrap the value of a fulfilled +promise together with any other matcher. If the promise is rejected, the +assertion will fail. + +```js +it('works with resolves', () => { + expect.assertions(1); + return expect(user.getUserName(5)).resolves.toEqual('Paul'); +}); +``` + +### `async`/`await` + +Writing tests using the `async`/`await` syntax is easy. Here is how you'd write +the same examples from before: + +```js +// async/await can be used. +it('works with async/await', async () => { + expect.assertions(1); + const data = await user.getUserName(4); + expect(data).toEqual('Mark'); +}); + +// async/await can also be used with `.resolves`. +it('works with async/await and resolves', async () => { + expect.assertions(1); + await expect(user.getUserName(5)).resolves.toEqual('Paul'); +}); +``` + +To enable async/await in your project, install +[`babel-preset-env`](http://babeljs.io/docs/plugins/preset-env/) and enable the +feature in your `.babelrc` file. + +### Error handling + +Errors can be handled using the `.catch` method. Make sure to add +`expect.assertions` to verify that a certain number of assertions are called. +Otherwise a fulfilled promise would not fail the test: + +```js +// Testing for async errors using Promise.catch. +test('tests error with promises', async () => { + expect.assertions(1); + return user.getUserName(2).catch(e => + expect(e).toEqual({ + error: 'User with 2 not found.', + }), + ); +}); + +// Or using async/await. +it('tests error with async/await', async () => { + expect.assertions(1); + try { + await user.getUserName(1); + } catch (e) { + expect(e).toEqual({ + error: 'User with 1 not found.', + }); + } +}); +``` + +### `.rejects` + +##### available in Jest **20.0.0+** + +The`.rejects` helper works like the `.resolves` helper. If the promise is +fulfilled, the test will automatically fail. + +```js +// Testing for async errors using `.rejects`. +it('tests error with rejects', () => { + expect.assertions(1); + return expect(user.getUserName(3)).rejects.toEqual({ + error: 'User with 3 not found.', + }); +}); + +// Or using async/await with `.rejects`. +it('tests error with async/await and rejects', async () => { + expect.assertions(1); + await expect(user.getUserName(3)).rejects.toEqual({ + error: 'User with 3 not found.', + }); +}); +``` + +The code for this example is available at +[examples/async](https://github.com/facebook/jest/tree/master/examples/async). + +If you'd like to test timers, like `setTimeout`, take a look at the +[Timer mocks](TimerMocks.md) documentation. diff --git a/website/versioned_docs/version-22.3/TutorialReact.md b/website/versioned_docs/version-22.3/TutorialReact.md new file mode 100644 index 000000000000..19703e0ac2f7 --- /dev/null +++ b/website/versioned_docs/version-22.3/TutorialReact.md @@ -0,0 +1,337 @@ +--- +id: version-22.3-tutorial-react +title: Testing React Apps +original_id: tutorial-react +--- + +At Facebook, we use Jest to test [React](http://facebook.github.io/react/) +applications. + +## Setup + +### Setup with Create React App + +If you are just getting started with React, we recommend using +[Create React App](https://github.com/facebookincubator/create-react-app). It is +ready to use and +[ships with Jest](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#running-tests)! +You don't need to do any extra steps for setup, and can head straight to the +next section. + +### Setup without Create React App + +If you have an existing application you'll need to install a few packages to +make everything work well together. We are using the `babel-jest` package and +the `react` babel preset to transform our code inside of the test environment. +Also see [using babel](GettingStarted.md#using-babel). + +Run + +```bash +npm install --save-dev jest babel-jest babel-preset-env babel-preset-react react-test-renderer +``` + +Your `package.json` should look something like this (where `` +is the actual latest version number for the package). Please add the scripts and +jest configuration entries: + +```json +// package.json + "dependencies": { + "react": "", + "react-dom": "" + }, + "devDependencies": { + "babel-jest": "", + "babel-preset-env": "", + "babel-preset-react": "", + "jest": "", + "react-test-renderer": "" + }, + "scripts": { + "test": "jest" + } +``` + +```json +// .babelrc +{ + "presets": ["env", "react"] +} +``` + +**And you're good to go!** + +### Snapshot Testing + +Let's create a [snapshot test](SnapshotTesting.md) for a Link component that +renders hyperlinks: + +```javascript +// Link.react.js +import React from 'react'; + +const STATUS = { + HOVERED: 'hovered', + NORMAL: 'normal', +}; + +export default class Link extends React.Component { + constructor(props) { + super(props); + + this._onMouseEnter = this._onMouseEnter.bind(this); + this._onMouseLeave = this._onMouseLeave.bind(this); + + this.state = { + class: STATUS.NORMAL, + }; + } + + _onMouseEnter() { + this.setState({class: STATUS.HOVERED}); + } + + _onMouseLeave() { + this.setState({class: STATUS.NORMAL}); + } + + render() { + return ( + + {this.props.children} + + ); + } +} +``` + +Now let's use React's test renderer and Jest's snapshot feature to interact with +the component and capture the rendered output and create a snapshot file: + +```javascript +// Link.react.test.js +import React from 'react'; +import Link from '../Link.react'; +import renderer from 'react-test-renderer'; + +test('Link changes the class when hovered', () => { + const component = renderer.create( + Facebook, + ); + let tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + + // manually trigger the callback + tree.props.onMouseEnter(); + // re-rendering + tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + + // manually trigger the callback + tree.props.onMouseLeave(); + // re-rendering + tree = component.toJSON(); + expect(tree).toMatchSnapshot(); +}); +``` + +When you run `npm test` or `jest`, this will produce an output file like this: + +```javascript +// __tests__/__snapshots__/Link.react.test.js.snap +exports[`Link changes the class when hovered 1`] = ` + + Facebook + +`; + +exports[`Link changes the class when hovered 2`] = ` + + Facebook + +`; + +exports[`Link changes the class when hovered 3`] = ` + + Facebook + +`; +``` + +The next time you run the tests, the rendered output will be compared to the +previously created snapshot. The snapshot should be committed along code +changes. When a snapshot test fails, you need to inspect whether it is an +intended or unintended change. If the change is expected you can invoke Jest +with `jest -u` to overwrite the existing snapshot. + +The code for this example is available at +[examples/snapshot](https://github.com/facebook/jest/tree/master/examples/snapshot). + +#### Snapshot Testing with Mocks, Enzyme and React 16 + +There's a caveat around snapshot testing when using Enzyme and React 16+. If you +mock out a module using the following style: + +```js +jest.mock('../SomeDirectory/SomeComponent', () => 'SomeComponent'); +``` + +Then you will see warnings in the console: + +```bash +Warning: is using uppercase HTML. Always use lowercase HTML tags in React. + +# Or: +Warning: The tag is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter. +``` + +React 16 triggers these warnings due to how it checks element types, and the +mocked module fails these checks. Your options are: + +1. Render as text. This way you won't see the props passed to the mock component + in the snapshot, but it's straightforward: + ```js + jest.mock('./SomeComponent', () => () => 'SomeComponent'); + ``` +2. Render as a custom element. DOM "custom elements" aren't checked for anything + and shouldn't fire warnings. They are lowercase and have a dash in the name. + ```js + jest.mock('./Widget', () => 'mock-widget'); + ``` +3. Use `react-test-renderer`. The test renderer doesn't care about element types + and will happily accept e.g. `SomeComponent`. You could check snapshots using + the test renderer, and check component behavior separately using Enzyme. + +### DOM Testing + +If you'd like to assert, and manipulate your rendered components you can use +[Enzyme](http://airbnb.io/enzyme/) or React's +[TestUtils](http://facebook.github.io/react/docs/test-utils.html). We use Enzyme +for this example. + +You have to run `npm install --save-dev enzyme` to use Enzyme. If you are using +a React below version 15.5.0, you will also need to install +`react-addons-test-utils`. + +Let's implement a simple checkbox which swaps between two labels: + +```javascript +// CheckboxWithLabel.js + +import React from 'react'; + +export default class CheckboxWithLabel extends React.Component { + constructor(props) { + super(props); + this.state = {isChecked: false}; + + // bind manually because React class components don't auto-bind + // http://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding + this.onChange = this.onChange.bind(this); + } + + onChange() { + this.setState({isChecked: !this.state.isChecked}); + } + + render() { + return ( + + ); + } +} +``` + +We use Enzyme's +[shallow renderer](http://airbnb.io/enzyme/docs/api/shallow.html) in this +example. + +```javascript +// __tests__/CheckboxWithLabel-test.js + +import React from 'react'; +import {shallow} from 'enzyme'; +import CheckboxWithLabel from '../CheckboxWithLabel'; + +test('CheckboxWithLabel changes the text after click', () => { + // Render a checkbox with label in the document + const checkbox = shallow(); + + expect(checkbox.text()).toEqual('Off'); + + checkbox.find('input').simulate('change'); + + expect(checkbox.text()).toEqual('On'); +}); +``` + +The code for this example is available at +[examples/enzyme](https://github.com/facebook/jest/tree/master/examples/enzyme). + +### Custom transformers + +If you need more advanced functionality, you can also build your own +transformer. Instead of using babel-jest, here is an example of using babel: + +```javascript +// custom-transformer.js +'use strict'; + +const babel = require('babel-core'); +const jestPreset = require('babel-preset-jest'); + +module.exports = { + process(src, filename) { + if (babel.util.canCompile(filename)) { + return babel.transform(src, { + filename, + presets: [jestPreset], + retainLines: true, + }).code; + } + return src; + }, +}; +``` + +Don't forget to install the `babel-core` and `babel-preset-jest` packages for +this example to work. + +To make this work with Jest you need to update your Jest configuration with +this: `"transform": {"\\.js$": "path/to/custom-transformer.js"}`. + +If you'd like to build a transformer with babel support, you can also use +babel-jest to compose one and pass in your custom configuration options: + +```javascript +const babelJest = require('babel-jest'); + +module.exports = babelJest.createTransformer({ + presets: ['my-custom-preset'], +}); +``` diff --git a/website/versioned_docs/version-22.3/TutorialReactNative.md b/website/versioned_docs/version-22.3/TutorialReactNative.md new file mode 100644 index 000000000000..5b5ae40a69e6 --- /dev/null +++ b/website/versioned_docs/version-22.3/TutorialReactNative.md @@ -0,0 +1,273 @@ +--- +id: version-22.3-tutorial-react-native +title: Testing React Native Apps +original_id: tutorial-react-native +--- + +At Facebook, we use Jest to test +[React Native](http://facebook.github.io/react-native/) applications. + +Get a deeper insight into testing a working React Native app example by reading +the following series: +[Part 1: Jest – Snapshot come into play](https://blog.callstack.io/unit-testing-react-native-with-the-new-jest-i-snapshots-come-into-play-68ba19b1b9fe#.12zbnbgwc) +and +[Part 2: Jest – Redux Snapshots for your Actions and Reducers](https://blog.callstack.io/unit-testing-react-native-with-the-new-jest-ii-redux-snapshots-for-your-actions-and-reducers-8559f6f8050b). + +## Setup + +Starting from react-native version 0.38, a Jest setup is included by default +when running `react-native init`. The following configuration should be +automatically added to your package.json file: + +```json +// package.json + "scripts": { + "test": "jest" + }, + "jest": { + "preset": "react-native" + } +``` + +_Note: If you are upgrading your react-native application and previously used +the `jest-react-native` preset, remove the dependency from your `package.json` +file and change the preset to `react-native` instead._ + +Simply run `npm test` to run tests with Jest. + +## Snapshot Test + +Let's create a [snapshot test](SnapshotTesting.md) for a small intro component +with a few views and text components and some styles: + +```javascript +// Intro.js +import React, {Component} from 'react'; +import {StyleSheet, Text, View} from 'react-native'; + +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + backgroundColor: '#F5FCFF', + flex: 1, + justifyContent: 'center', + }, + instructions: { + color: '#333333', + marginBottom: 5, + textAlign: 'center', + }, + welcome: { + fontSize: 20, + margin: 10, + textAlign: 'center', + }, +}); + +export default class Intro extends Component { + render() { + return ( + + Welcome to React Native! + + This is a React Native snapshot test. + + + ); + } +} +``` + +Now let's use React's test renderer and Jest's snapshot feature to interact with +the component and capture the rendered output and create a snapshot file: + +```javascript +// __tests__/Intro-test.js +import React from 'react'; +import Intro from '../Intro'; + +import renderer from 'react-test-renderer'; + +test('renders correctly', () => { + const tree = renderer.create().toJSON(); + expect(tree).toMatchSnapshot(); +}); +``` + +When you run `npm test` or `jest`, this will produce an output file like this: + +```javascript +// __tests__/__snapshots__/Intro-test.js.snap +exports[`Intro renders correctly 1`] = ` + + + Welcome to React Native! + + + This is a React Native snapshot test. + + +`; +``` + +The next time you run the tests, the rendered output will be compared to the +previously created snapshot. The snapshot should be committed along code +changes. When a snapshot test fails, you need to inspect whether it is an +intended or unintended change. If the change is expected you can invoke Jest +with `jest -u` to overwrite the existing snapshot. + +The code for this example is available at +[examples/react-native](https://github.com/facebook/jest/tree/master/examples/react-native). + +## Preset configuration + +The preset sets up the environment and is very opinionated and based on what we +found to be useful at Facebook. All of the configuration options can be +overwritten just as they can be customized when no preset is used. + +### Environment + +`react-native` ships with a Jest preset, so the `jest.preset` field of your +`package.json` should point to `react-native`. The preset is a node environment +that mimics the environment of a React Native app. Because it doesn't load any +DOM or browser APIs, it greatly improves Jest's startup time. + +### transformIgnorePatterns customization + +The +[`transformIgnorePatterns`](configuration.html#transformignorepatterns-array-string) +option can be used to whitelist or blacklist files from being transformed with +babel. Many react-native npm modules unfortunately don't pre-compile their +source code before publishing. + +By default the jest-react-native preset only processes the project's own source +files and react-native. If you have npm dependencies that have to be transformed +you can customize this configuration option by whitelisting modules other than +react-native: + +```json +"transformIgnorePatterns": [ + "node_modules/(?!(react-native|my-project|react-native-button)/)" +] +``` + +### setupFiles + +If you'd like to provide additional configuration for every test file, the +[`setupFiles` configuration option](configuration.html#setupfiles-array) can be +used to specify setup scripts. + +### moduleNameMapper + +The +[`moduleNameMapper`](configuration.html#modulenamemapper-object-string-string) +can be used to map a module path to a different module. By default the preset +maps all images to an image stub module but if a module cannot be found this +configuration option can help: + +```json +"moduleNameMapper": { + "my-module.js": "/path/to/my-module.js" +} +``` + +## Tips + +### Mock native modules using jest.mock + +The Jest preset built into `react-native` comes with a few default mocks that +are applied on a react-native repository. However some react-native components +or third party components rely on native code to be rendered. In such cases, +Jest's manual mocking system can help to mock out the underlying implementation. + +For example, if your code depends on a third party native video component called +`react-native-video` you might want to stub it out with a manual mock like this: + +```js +jest.mock('react-native-video', () => 'Video'); +``` + +This will render the component as `