From caaeacf6c081dfb9a3671b705fbe4c667680e57f Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Tue, 13 Feb 2018 01:47:18 +0200 Subject: [PATCH 1/5] add versioned documentation to the website --- website/package.json | 3 +- website/pages/en/versions.js | 107 ++ website/versioned_docs/version-22.2.2/CLI.md | 328 +++++ .../version-22.2.2/Configuration.md | 1112 +++++++++++++++++ .../version-22.2.2/Es6ClassMocks.md | 318 +++++ .../version-22.2.2/ExpectAPI.md | 1060 ++++++++++++++++ .../version-22.2.2/GettingStarted.md | 156 +++ .../version-22.2.2/GlobalAPI.md | 413 ++++++ .../version-22.2.2/JestObjectAPI.md | 484 +++++++ .../version-22.2.2/JestPlatform.md | 197 +++ .../version-22.2.2/ManualMocks.md | 157 +++ .../version-22.2.2/MigrationGuide.md | 48 + .../version-22.2.2/MockFunctionAPI.md | 328 +++++ .../version-22.2.2/MockFunctions.md | 279 +++++ .../version-22.2.2/MoreResources.md | 41 + .../version-22.2.2/Puppeteer.md | 103 ++ .../version-22.2.2/SetupAndTeardown.md | 222 ++++ .../version-22.2.2/SnapshotTesting.md | 236 ++++ .../version-22.2.2/TestingAsyncCode.md | 160 +++ .../version-22.2.2/TestingFrameworks.md | 39 + .../version-22.2.2/TimerMocks.md | 182 +++ .../version-22.2.2/Troubleshooting.md | 317 +++++ .../version-22.2.2/TutorialAsync.md | 190 +++ .../version-22.2.2/TutorialReact.md | 337 +++++ .../version-22.2.2/TutorialReactNative.md | 286 +++++ .../version-22.2.2/TutorialjQuery.md | 80 ++ .../version-22.2.2/UsingMatchers.md | 175 +++ .../versioned_docs/version-22.2.2/Webpack.md | 281 +++++ .../version-22.2.2-sidebars.json | 37 + website/versions.json | 1 + 30 files changed, 7676 insertions(+), 1 deletion(-) create mode 100644 website/pages/en/versions.js create mode 100644 website/versioned_docs/version-22.2.2/CLI.md create mode 100644 website/versioned_docs/version-22.2.2/Configuration.md create mode 100644 website/versioned_docs/version-22.2.2/Es6ClassMocks.md create mode 100644 website/versioned_docs/version-22.2.2/ExpectAPI.md create mode 100644 website/versioned_docs/version-22.2.2/GettingStarted.md create mode 100644 website/versioned_docs/version-22.2.2/GlobalAPI.md create mode 100644 website/versioned_docs/version-22.2.2/JestObjectAPI.md create mode 100644 website/versioned_docs/version-22.2.2/JestPlatform.md create mode 100644 website/versioned_docs/version-22.2.2/ManualMocks.md create mode 100644 website/versioned_docs/version-22.2.2/MigrationGuide.md create mode 100644 website/versioned_docs/version-22.2.2/MockFunctionAPI.md create mode 100644 website/versioned_docs/version-22.2.2/MockFunctions.md create mode 100644 website/versioned_docs/version-22.2.2/MoreResources.md create mode 100644 website/versioned_docs/version-22.2.2/Puppeteer.md create mode 100644 website/versioned_docs/version-22.2.2/SetupAndTeardown.md create mode 100644 website/versioned_docs/version-22.2.2/SnapshotTesting.md create mode 100644 website/versioned_docs/version-22.2.2/TestingAsyncCode.md create mode 100644 website/versioned_docs/version-22.2.2/TestingFrameworks.md create mode 100644 website/versioned_docs/version-22.2.2/TimerMocks.md create mode 100644 website/versioned_docs/version-22.2.2/Troubleshooting.md create mode 100644 website/versioned_docs/version-22.2.2/TutorialAsync.md create mode 100644 website/versioned_docs/version-22.2.2/TutorialReact.md create mode 100644 website/versioned_docs/version-22.2.2/TutorialReactNative.md create mode 100644 website/versioned_docs/version-22.2.2/TutorialjQuery.md create mode 100644 website/versioned_docs/version-22.2.2/UsingMatchers.md create mode 100644 website/versioned_docs/version-22.2.2/Webpack.md create mode 100644 website/versioned_sidebars/version-22.2.2-sidebars.json create mode 100644 website/versions.json 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..723db95dd0fd --- /dev/null +++ b/website/pages/en/versions.js @@ -0,0 +1,107 @@ +/** + * 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.2.2/CLI.md b/website/versioned_docs/version-22.2.2/CLI.md new file mode 100644 index 000000000000..fe1a0e801af7 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/CLI.md @@ -0,0 +1,328 @@ +--- +id: version-22.2.2-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.2.2/Configuration.md b/website/versioned_docs/version-22.2.2/Configuration.md new file mode 100644 index 000000000000..748017643583 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/Configuration.md @@ -0,0 +1,1112 @@ +--- +id: version-22.2.2-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. + +### `mapCoverage` [boolean] + +##### available in Jest **20.0.0+** + +Default: `false` + +If you have [transformers](#transform-object-string-string) configured that emit +source maps, Jest will use them to try and map code coverage against the +original source code when writing [reports](#coveragereporters-array-string) and +checking [thresholds](#coveragethreshold-object). This is done on a best-effort +basis as some compile-to-JavaScript languages may provide more accurate source +maps than others. This can also be resource-intensive. If Jest is taking a long +time to calculate coverage at the end of a test run, try setting this option to +`false`. + +Both inline source maps and source maps returned directly from a transformer are +supported. Source map URLs are not supported because Jest may not be able to +locate them. To return source maps from a transformer, the `process` function +can return an object like the following. The `map` property may either be the +source map object, or the source map object as a string. + +```js +return { + code: 'the code', + map: 'the source map', +}; +``` + +### `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.2.2/Es6ClassMocks.md b/website/versioned_docs/version-22.2.2/Es6ClassMocks.md new file mode 100644 index 000000000000..0dae72c18a73 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/Es6ClassMocks.md @@ -0,0 +1,318 @@ +--- +id: version-22.2.2-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.2.2/ExpectAPI.md b/website/versioned_docs/version-22.2.2/ExpectAPI.md new file mode 100644 index 000000000000..ae1417376195 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/ExpectAPI.md @@ -0,0 +1,1060 @@ +--- +id: version-22.2.2-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.2.2/GettingStarted.md b/website/versioned_docs/version-22.2.2/GettingStarted.md new file mode 100644 index 000000000000..6a11824f0b2c --- /dev/null +++ b/website/versioned_docs/version-22.2.2/GettingStarted.md @@ -0,0 +1,156 @@ +--- +id: version-22.2.2-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.2.2/GlobalAPI.md b/website/versioned_docs/version-22.2.2/GlobalAPI.md new file mode 100644 index 000000000000..0504de9fc449 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/GlobalAPI.md @@ -0,0 +1,413 @@ +--- +id: version-22.2.2-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.2.2/JestObjectAPI.md b/website/versioned_docs/version-22.2.2/JestObjectAPI.md new file mode 100644 index 000000000000..4fa894542c40 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/JestObjectAPI.md @@ -0,0 +1,484 @@ +--- +id: version-22.2.2-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 run 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.2.2/JestPlatform.md b/website/versioned_docs/version-22.2.2/JestPlatform.md new file mode 100644 index 000000000000..f59b4d15dbee --- /dev/null +++ b/website/versioned_docs/version-22.2.2/JestPlatform.md @@ -0,0 +1,197 @@ +--- +id: version-22.2.2-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.2.2/ManualMocks.md b/website/versioned_docs/version-22.2.2/ManualMocks.md new file mode 100644 index 000000000000..b8064269f198 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/ManualMocks.md @@ -0,0 +1,157 @@ +--- +id: version-22.2.2-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.2.2/MigrationGuide.md b/website/versioned_docs/version-22.2.2/MigrationGuide.md new file mode 100644 index 000000000000..eae7f4d927da --- /dev/null +++ b/website/versioned_docs/version-22.2.2/MigrationGuide.md @@ -0,0 +1,48 @@ +--- +id: version-22.2.2-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.2.2/MockFunctionAPI.md b/website/versioned_docs/version-22.2.2/MockFunctionAPI.md new file mode 100644 index 000000000000..36000787edc9 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/MockFunctionAPI.md @@ -0,0 +1,328 @@ +--- +id: version-22.2.2-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.2.2/MockFunctions.md b/website/versioned_docs/version-22.2.2/MockFunctions.md new file mode 100644 index 000000000000..81f13e9e8b21 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/MockFunctions.md @@ -0,0 +1,279 @@ +--- +id: version-22.2.2-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.2.2/MoreResources.md b/website/versioned_docs/version-22.2.2/MoreResources.md new file mode 100644 index 000000000000..f3e5777fd661 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/MoreResources.md @@ -0,0 +1,41 @@ +--- +id: version-22.2.2-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://discordapp.com/channels/102860784329052160/103622435865104384) +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.2.2/Puppeteer.md b/website/versioned_docs/version-22.2.2/Puppeteer.md new file mode 100644 index 000000000000..55eb0abc4ca3 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/Puppeteer.md @@ -0,0 +1,103 @@ +--- +id: version-22.2.2-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.2.2/SetupAndTeardown.md b/website/versioned_docs/version-22.2.2/SetupAndTeardown.md new file mode 100644 index 000000000000..88b38ca21965 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/SetupAndTeardown.md @@ -0,0 +1,222 @@ +--- +id: version-22.2.2-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.2.2/SnapshotTesting.md b/website/versioned_docs/version-22.2.2/SnapshotTesting.md new file mode 100644 index 000000000000..73eeb0725f68 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/SnapshotTesting.md @@ -0,0 +1,236 @@ +--- +id: version-22.2.2-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.2.2/TestingAsyncCode.md b/website/versioned_docs/version-22.2.2/TestingAsyncCode.md new file mode 100644 index 000000000000..3fb72cd65489 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TestingAsyncCode.md @@ -0,0 +1,160 @@ +--- +id: version-22.2.2-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.2.2/TestingFrameworks.md b/website/versioned_docs/version-22.2.2/TestingFrameworks.md new file mode 100644 index 000000000000..7050c90080c9 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TestingFrameworks.md @@ -0,0 +1,39 @@ +--- +id: version-22.2.2-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.2.2/TimerMocks.md b/website/versioned_docs/version-22.2.2/TimerMocks.md new file mode 100644 index 000000000000..c63ead51f482 --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TimerMocks.md @@ -0,0 +1,182 @@ +--- +id: version-22.2.2-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.2.2/Troubleshooting.md b/website/versioned_docs/version-22.2.2/Troubleshooting.md new file mode 100644 index 000000000000..967b55dcca0f --- /dev/null +++ b/website/versioned_docs/version-22.2.2/Troubleshooting.md @@ -0,0 +1,317 @@ +--- +id: version-22.2.2-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.2.2/TutorialAsync.md b/website/versioned_docs/version-22.2.2/TutorialAsync.md new file mode 100644 index 000000000000..1f1cb31668eb --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TutorialAsync.md @@ -0,0 +1,190 @@ +--- +id: version-22.2.2-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.2.2/TutorialReact.md b/website/versioned_docs/version-22.2.2/TutorialReact.md new file mode 100644 index 000000000000..fd28af0fabec --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TutorialReact.md @@ -0,0 +1,337 @@ +--- +id: version-22.2.2-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.2.2/TutorialReactNative.md b/website/versioned_docs/version-22.2.2/TutorialReactNative.md new file mode 100644 index 000000000000..4b08d47690da --- /dev/null +++ b/website/versioned_docs/version-22.2.2/TutorialReactNative.md @@ -0,0 +1,286 @@ +--- +id: version-22.2.2-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-native'; +import React from 'react'; +import Intro from '../Intro'; + +// Note: test renderer must be required after react-native. +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 `