Skip to content

Commit

Permalink
chore: Upgrade to Jest 29 (#37408)
Browse files Browse the repository at this point in the history
* dep updates

* update docs

* 27 to 28 migration

* 28 to 29 migration

* remove not-needed workaround

* wip test fixes

* more fixes

* typo

* more test fixes

* maybe fix wordpress?

* wordpress shouldn't need the moduleNameMapper ?!

* fix wordpress imports
  • Loading branch information
LekoArts committed Jan 9, 2023
1 parent a0910c7 commit 315edc6
Show file tree
Hide file tree
Showing 32 changed files with 897 additions and 898 deletions.
10 changes: 10 additions & 0 deletions .jestSetup.js
@@ -1 +1,11 @@
process.env.GATSBY_SHOULD_TRACK_IMAGE_CDN_URLS = "true"

// See https://github.com/inrupt/solid-client-authn-js/issues/1676
if (
typeof globalThis.TextEncoder === "undefined" ||
typeof globalThis.TextDecoder === "undefined"
) {
const utils = require("util");
globalThis.TextEncoder = utils.TextEncoder;
globalThis.TextDecoder = utils.TextDecoder;
}
17 changes: 5 additions & 12 deletions docs/docs/how-to/testing/testing-react-components.md
Expand Up @@ -2,7 +2,7 @@
title: Testing React Components
---

_The recommended testing framework is [Jest](https://jestjs.io/). This guide assumes that you followed the [Unit testing](/docs/how-to/testing/unit-testing) guide to set up Jest._
_The recommended testing framework is [Jest](https://jestjs.io/). This guide assumes that you followed the [Unit testing](/docs/how-to/testing/unit-testing) guide to set up Jest and that you are using Jest 29 or above._

The [@testing-library/react](https://github.com/testing-library/react-testing-library) by Kent C. Dodds has risen in popularity since its release and is a great replacement for [enzyme](https://github.com/airbnb/enzyme). You can write unit and integration tests and it encourages you to query the DOM in the same way the user would. Hence the guiding principle:

Expand All @@ -15,13 +15,7 @@ It provides light utility functions on top of `react-dom` and `react-dom/test-ut
Install the library as one of your project's `devDependencies`. Optionally you may install `jest-dom` to use its [custom jest matchers](https://github.com/testing-library/jest-dom#custom-matchers).

```shell
npm install --save-dev @testing-library/react @testing-library/jest-dom
```

If you are using Jest 28, you also need to install `jest-environment-jsdom`:

```shell
npm install --save-dev jest-environment-jsdom
npm install --save-dev @testing-library/react @testing-library/jest-dom jest-environment-jsdom
```

Create the file `setup-test-env.js` at the root of your project. Insert this code into it:
Expand All @@ -32,7 +26,7 @@ import "@testing-library/jest-dom"

This file gets run automatically by Jest before every test and therefore you don't need to add the imports to every single test file.

Lastly you need to tell Jest where to find this file. Open your `jest.config.js` and add this entry to the bottom after 'setupFiles':
Lastly you need to tell Jest where to find this file. Open your `jest.config.js` and add this entry to the bottom after `setupFiles`:

```js:title=jest.config.js
module.exports = {
Expand All @@ -41,12 +35,11 @@ module.exports = {
}
```

> **Note:** The [Jest 27](https://jestjs.io/blog/2021/05/25/jest-27#flipping-defaults) configuration `testEnvironment` default value changed to `node`,
> you need to change it to `jsdom` for React Testing Library to work properly
**Please note:** The `testEnvironment` default is `node`. If you don't want to switch it globally you can use a `@jest-environment` comment, see [testEnvironment docs](https://jestjs.io/docs/configuration/#testenvironment-string).

## Usage

Let's create a little example test using the newly added library. If you haven't done so already, read the [unit testing guide](/docs/how-to/testing/unit-testing) — essentially you'll use `@testing-library/react` instead of `react-test-renderer` now. There are a lot of options when it comes to selectors, this example chooses `getByTestId` here. It also utilizes `toHaveTextContent` from `jest-dom`:
Let's create a little example test using the newly added library. If you haven't done so already, read the [unit testing guide](/docs/how-to/testing/unit-testing). There are a lot of options when it comes to selectors, this example chooses `getByTestId` here. It also utilizes `toHaveTextContent` from `jest-dom`:

```js
import React from "react"
Expand Down
117 changes: 32 additions & 85 deletions docs/docs/how-to/testing/unit-testing.md
Expand Up @@ -18,17 +18,16 @@ which was created by Facebook. While Jest is a general-purpose JavaScript unit
testing framework, it has lots of features that make it work particularly well
with React.

_Note: For this guide, you will be starting with `gatsby-starter-default`, but the
concepts should be the same or very similar for your site._

### 1. Installing dependencies

First, you need to install Jest and some more required packages. Install babel-jest and babel-preset-gatsby to ensure that the babel preset(s) that are used match what are used internally for your Gatsby site.

```shell
npm install --save-dev jest babel-jest react-test-renderer babel-preset-gatsby identity-obj-proxy
npm install --save-dev jest babel-jest babel-preset-gatsby identity-obj-proxy
```

**Please note:** This guide assumes you're using Jest 29 or above.

### 2. Creating a configuration file for Jest

Because Gatsby handles its own Babel configuration, you will need to manually
Expand All @@ -42,12 +41,6 @@ module.exports = {
moduleNameMapper: {
".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`,
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `<rootDir>/__mocks__/file-mock.js`,
"^gatsby-page-utils/(.*)$": `gatsby-page-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
"^gatsby-core-utils/(.*)$": `gatsby-core-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
"^gatsby-plugin-utils/(.*)$": [
`gatsby-plugin-utils/dist/$1`,
`gatsby-plugin-utils/$1`,
], // Workaround for https://github.com/facebook/jest/issues/9771
},
testPathIgnorePatterns: [`node_modules`, `\\.cache`, `<rootDir>.*/public`],
transformIgnorePatterns: [`node_modules/(?!(gatsby|gatsby-script|gatsby-link)/)`],
Expand All @@ -61,25 +54,20 @@ module.exports = {
}
```

> **Note:** If you're using Jest 28 or above, you can skip adding the `moduleNameMapper` options for `gatsby-page-utils`, `gatsby-core-utils`, and `gatsby-plugin-utils`. The mentioned bug was fixed in Jest 28.
Go over the content of this configuration file:

- The `transform` section tells Jest that all `js` or `jsx` files need to be
transformed using a `jest-preprocess.js` file in the project root. Go ahead and
create this file now. This is where you set up your Babel config. You can start
with the following minimal config:

```js:title=jest-preprocess.js
const babelOptions = {
presets: ["babel-preset-gatsby"],
}

module.exports = require("babel-jest").default.createTransformer(babelOptions)
```
```js:title=jest-preprocess.js
const babelOptions = {
presets: ["babel-preset-gatsby"],
}

> **Note:** If you're using Jest 26.6.3 or below, the last line has to be changed to
> `module.exports = require("babel-jest").createTransformer(babelOptions)`
module.exports = require("babel-jest").default.createTransformer(babelOptions)
```

- The next option is `moduleNameMapper`. This
section works a bit like webpack rules and tells Jest how to handle imports.
Expand All @@ -92,9 +80,9 @@ module.exports = require("babel-jest").default.createTransformer(babelOptions)
The convention is to create a directory called `__mocks__` in the root directory
for this. Note the pair of double underscores in the name.

```js:title=__mocks__/file-mock.js
module.exports = "test-file-stub"
```
```js:title=__mocks__/file-mock.js
module.exports = "test-file-stub"
```

- The next config setting is `testPathIgnorePatterns`. You are telling Jest to ignore
any tests in the `node_modules` or `.cache` directories.
Expand All @@ -104,34 +92,29 @@ module.exports = "test-file-stub"
includes un-transpiled ES6 code. By default Jest doesn't try to transform code
inside `node_modules`, so you will get an error like this:

```text
/my-app/node_modules/gatsby/cache-dir/gatsby-browser-entry.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from "react"
^^^^^^
SyntaxError: Unexpected token import
```
```text
/my-app/node_modules/gatsby/cache-dir/gatsby-browser-entry.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from "react"
^^^^^^
SyntaxError: Unexpected token import
```

This is because `gatsby-browser-entry.js` isn't being transpiled before running
in Jest. You can fix this by changing the default `transformIgnorePatterns` to
exclude the `gatsby` module.
This is because `gatsby-browser-entry.js` isn't being transpiled before running
in Jest. You can fix this by changing the default `transformIgnorePatterns` to
exclude the `gatsby` module.

- The `globals` section sets `__PATH_PREFIX__`, which is usually set by Gatsby,
and which some components need.

- You need to set `testURL` to a valid URL, because some DOM APIs such as
`localStorage` are unhappy with the default (`about:blank`).

> Note: if you're using Jest 23.5.0 or later, `testURL` will default to `http://localhost` so you can skip this setting.
- There's one more global that you need to set, but as it's a function you can't
set it here in the JSON. The `setupFiles` array lets you list files that will be
included before all tests are run, so it's perfect for this.

```js:title=loadershim.js
global.___loader = {
enqueue: jest.fn(),
}
```
```js:title=loadershim.js
global.___loader = {
enqueue: jest.fn(),
}
```

### 3. Useful mocks to complete your testing environment

Expand Down Expand Up @@ -179,35 +162,9 @@ This mocks the `graphql()` function, [`Link` component](/docs/reference/built-in

## Writing tests

A full guide to unit testing is beyond the scope of this guide, but you can
start with a snapshot test to check that everything is working.

First, create the test file. You can either put these in a `__tests__`
directory, or put them elsewhere (usually next to the component itself), with
the extension `.spec.js` or `.test.js`. The decision comes down to your own
preference. In this guide, you will use the `__tests__` folder convention. To test the header component, create a `header.js` file in `src/components/__tests__/`:

```js:title=src/components/__tests__/header.js
import React from "react"
import renderer from "react-test-renderer"

import Header from "../header"
This guide explains how you can set up Jest with Gatsby, if you want to know how to write tests we highly recommend checking out the [Testing React components](/docs/how-to/testing/testing-react-components/) guide. It explains how to install `@testing-library/react` which is our recommended utility for Jest.

describe("Header", () => {
it("renders correctly", () => {
const tree = renderer
.create(<Header siteTitle="Default Starter" />)
.toJSON()
expect(tree).toMatchSnapshot()
})
})
```

This is a very brief snapshot test, which uses `react-test-renderer` to render
the component, and then generates a snapshot of it on the first run. It then
compares future snapshots against this, which means you can quickly check for
regressions. Visit [the Jest docs](https://jestjs.io/docs/en/getting-started) to
learn more about other tests that you can write.
Visit [the Jest docs](https://jestjs.io/docs/en/getting-started) to learn more about other tests that you can write.

## Running tests

Expand All @@ -216,32 +173,23 @@ script for `test`, which just outputs an error message. Change this to use the
`jest` executable that you now have available, like so:

```json:title=package.json
{
"scripts": {
"test": "jest"
}
}
```

This means you can now run tests by typing `npm test`. If you want you could
also run with a flag that triggers watch mode to watch files and run tests when they are changed: `npm test -- --watch`.

Run the tests again now and it should all work! You may get a message about
the snapshot being written. This is created in a `__snapshots__` directory next
to your tests. If you take a look at it, you will see that it is a JSON
representation of the `<Header />` component. You should check your snapshot files
into a source control system (for example, a GitHub repo) so that any changes are tracked in history.
This is particularly important to remember if you are using a continuous
integration system such as Travis or CircleCI to run tests, as these will fail if the snapshot is not checked into source control.

If you make changes that mean you need to update the snapshot, you can do this
by running `npm test -- -u`.

## Using TypeScript

If you are using TypeScript, you need to install typings packages and make
two changes to your config.

```shell
npm install --save-dev @types/jest @types/react-test-renderer @babel/preset-typescript
npm install @types/jest @babel/preset-typescript --save-dev
```

Update the transform in `jest.config.js` to run `jest-preprocess` on files in your project's root directory.
Expand Down Expand Up @@ -296,8 +244,7 @@ const paths = pathsToModuleNameMapper(compilerOptions.paths, {

If you need to make changes to your Babel config, you can edit the config in `jest-preprocess.js`. You may need to enable some of the plugins used by Gatsby. See [the Gatsby Babel config guide](/docs/how-to/custom-configuration/babel) for some examples.

For more information on Jest testing, visit
[the Jest site](https://jestjs.io/docs/en/getting-started).
For more information on Jest testing, visit [the Jest site](https://jestjs.io/docs/en/getting-started). Also read our [Testing React components](/docs/how-to/testing/testing-react-components/) guide.

For an example encapsulating all of these techniques and a full unit test suite with [@testing-library/react][react-testing-library], check out the [using-jest][using-jest] example.

Expand Down
8 changes: 0 additions & 8 deletions integration-tests/artifacts/jest.config.js
@@ -1,11 +1,3 @@
module.exports = {
testPathIgnorePatterns: [`/node_modules/`, `__tests__/fixtures`, `.cache`],
moduleNameMapper: {
"^gatsby-page-utils/(.*)$": `gatsby-page-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
"^gatsby-core-utils/(.*)$": `gatsby-core-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
"^gatsby-plugin-utils/(.*)$": [
`gatsby-plugin-utils/dist/$1`,
`gatsby-plugin-utils/$1`,
], // Workaround for https://github.com/facebook/jest/issues/9771
},
}
2 changes: 1 addition & 1 deletion integration-tests/artifacts/package.json
Expand Up @@ -19,6 +19,6 @@
},
"devDependencies": {
"fs-extra": "^10.1.0",
"jest": "^27.2.1"
"jest": "^29.3.1"
}
}
4 changes: 4 additions & 0 deletions integration-tests/cache-resilience/jest.config.js
@@ -1,6 +1,10 @@
const path = require(`path`)

module.exports = {
snapshotFormat: {
escapeString: true,
printBasicPrototype: true
},
testPathIgnorePatterns: [`/node_modules/`, `\\.cache`, `test.js`],
snapshotSerializers: [
`jest-serializer-path`,
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/cache-resilience/package.json
Expand Up @@ -21,10 +21,10 @@
"fs-extra": "^9.0.1",
"gatsby-core-utils": "^3.0.0-next.0",
"glob": "^7.1.6",
"jest": "^27.2.1",
"jest": "^29.3.1",
"jest-serializer-path": "^0.1.15",
"lodash": "^4.17.20",
"slash": "^3.0.0",
"snapshot-diff": "^0.6.1"
"snapshot-diff": "^0.10.0"
}
}
2 changes: 1 addition & 1 deletion integration-tests/esm-in-gatsby-files/package.json
Expand Up @@ -20,7 +20,7 @@
"babel-preset-gatsby-package": "^2.4.0",
"execa": "^4.0.1",
"fs-extra": "^10.1.0",
"jest": "^27.2.1",
"jest": "^29.3.1",
"node-fetch": "^2.6.0",
"typescript": "^4.8.4"
}
Expand Down
4 changes: 4 additions & 0 deletions integration-tests/functions/jest.config.js
@@ -1,4 +1,8 @@
module.exports = {
snapshotFormat: {
escapeString: true,
printBasicPrototype: true
},
testPathIgnorePatterns: [
`/node_modules/`,
`__tests__/fixtures`,
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/functions/package.json
Expand Up @@ -20,10 +20,10 @@
"test": "npm-run-all -s build test-prod test-dev"
},
"devDependencies": {
"babel-jest": "^27.4.5",
"babel-jest": "^29.3.1",
"babel-preset-gatsby-package": "^2.4.0",
"fs-extra": "^10.0.0",
"jest": "^27.2.1",
"jest": "^29.3.1",
"npm-run-all": "4.1.5",
"start-server-and-test": "^1.11.3"
},
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/gatsby-cli/package.json
Expand Up @@ -6,15 +6,15 @@
"test": "jest --runInBand"
},
"devDependencies": {
"babel-jest": "^27.2.1",
"babel-jest": "^29.3.1",
"babel-preset-gatsby-package": "next",
"del-cli": "^3.0.1",
"execa": "^4.0.1",
"fs-extra": "^9.0.0",
"gatsby": "next",
"gatsby-cli": "next",
"gatsby-core-utils": "next",
"jest": "^27.2.1",
"jest": "^29.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"strip-ansi": "^6.0.1",
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/gatsby-pipeline/package.json
Expand Up @@ -32,7 +32,7 @@
"gatsby-core-utils": "latest",
"md5-file": "^5.0.0",
"node-fetch": "^2.6.0",
"jest": "^27.2.1",
"jest": "^29.3.1",
"tree-kill": "^1.2.2"
},
"repository": {
Expand Down
11 changes: 4 additions & 7 deletions integration-tests/gatsby-source-wordpress/jest.config.js
@@ -1,11 +1,8 @@
module.exports = {
snapshotFormat: {
escapeString: true,
printBasicPrototype: true
},
testPathIgnorePatterns: [`/node_modules/`, `__tests__/fixtures`, `.cache`],
bail: true,
moduleNameMapper: {
"^gatsby-core-utils/(.*)$": `gatsby-core-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
"^gatsby-plugin-utils/(.*)$": [
`gatsby-plugin-utils/dist/$1`,
`gatsby-plugin-utils/$1`,
], // Workaround for https://github.com/facebook/jest/issues/9771
},
}
2 changes: 1 addition & 1 deletion integration-tests/gatsby-source-wordpress/package.json
Expand Up @@ -24,7 +24,7 @@
"devDependencies": {
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"jest": "^27.2.1",
"jest": "^29.3.1",
"node-fetch": "^2.6.1",
"rimraf": "^3.0.2"
}
Expand Down

0 comments on commit 315edc6

Please sign in to comment.