Skip to content

Commit

Permalink
Improving unit-testing.md (#9825)
Browse files Browse the repository at this point in the history
Following [suggestions](#9795 (comment)) from @shannonbux to improve `unit-testing.md` further

<!--
  Q. Which branch should I use for my pull request?
  A. Use `master` branch (probably).

  Q. Which branch if my change is a bug fix for Gatsby v1?
  A. In this case, you should use the `v1` branch

  Q. Which branch if I'm still not sure?
  A. Use `master` branch. Ask in the PR if you're not sure and a Gatsby maintainer will be happy to help :)

  Note: We will only accept bug fixes for Gatsby v1. New features should be added to Gatsby v2.

  Learn more about contributing: https://www.gatsbyjs.org/docs/how-to-contribute/
-->
  • Loading branch information
RobinCsl authored and DSchau committed Nov 12, 2018
1 parent ad142af commit 8f32dd6
Showing 1 changed file with 41 additions and 29 deletions.
70 changes: 41 additions & 29 deletions docs/docs/unit-testing.md
Expand Up @@ -15,8 +15,10 @@ 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.

For this guide, you will be starting with `gatsby-starter-blog`, but the
concepts should be the same or very similar for your site.
_Note: For this guide, you will be starting with `gatsby-starter-blog`, 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. You need to
install Babel 7 as it's required by Jest.
Expand All @@ -25,6 +27,8 @@ install Babel 7 as it's required by Jest.
npm install --save-dev jest babel-jest react-test-renderer identity-obj-proxy 'babel-core@^7.0.0-0' @babel/core babel-preset-gatsby
```

### 2. Creating a configuration file for Jest

Because Gatsby handles its own Babel configuration, you will need to manually
tell Jest to use `babel-jest`. The easiest way to do this is to add a `jest.config.js`. You can set up some useful defaults at the same time:

Expand All @@ -47,10 +51,12 @@ module.exports = {
}
```

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 a minimal config.
Let's 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 = {
Expand All @@ -60,28 +66,28 @@ const babelOptions = {
module.exports = require("babel-jest").createTransformer(babelOptions)
```

Back to the Jest config, you can see the next option is `moduleNameMapper`. This
section works a bit like webpack rules, and tells Jest how to handle imports.
You are mainly concerned here with mocking static file imports, which Jest can't
handle. A mock is a dummy module that is used instead of the real module inside
tests. It is good when you have something that you can't or don't want to test.
You can mock anything, and here you are mocking assets rather than code. For
stylesheets you need to use the package `identity-obj-proxy`. For all other assets
you need to use a manual mock called `fileMock.js`. You need to create this yourself.
The convention is to create a directory called `__mocks__` in the root directory
for this. Note the pair of double underscores in the name.
- The next option is `moduleNameMapper`. This
section works a bit like webpack rules, and tells Jest how to handle imports.
You are mainly concerned here with mocking static file imports, which Jest can't
handle. A mock is a dummy module that is used instead of the real module inside
tests. It is good when you have something that you can't or don't want to test.
You can mock anything, and here you are mocking assets rather than code. For
stylesheets you need to use the package `identity-obj-proxy`. For all other assets
you need to use a manual mock called `fileMock.js`. You need to create this yourself.
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__/fileMock.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.
- The next config setting is `testPathIgnorePatterns`. You are telling Jest to ignore
any tests in the `node_modules` or `.cache` directories.

The next option is very important, and is different from what you'll find in other
Jest guides. The reason that you need `transformIgnorePatterns` is because Gastby
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:
- The next option is very important, and is different from what you'll find in other
Jest guides. The reason that you need `transformIgnorePatterns` is because Gastby
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:

```
/my-blog/node_modules/gatsby/cache-dir/gatsby-browser-entry.js:1
Expand All @@ -94,24 +100,28 @@ 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.
- 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`).
- 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.
- 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(),
}
```

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

#### Mocking `gastby`

Finally it's a good idea to mock the `gatsby` module itself. This may not be
needed at first, but will make things a lot easier if you want to test
components that use `Link` or GraphQL.
Expand All @@ -135,6 +145,8 @@ module.exports = {

This mocks the `graphql()` function, `Link` component, and `StaticQuery` component.

#### Mocking `location` from `Router`

One more issue that you may encounter is that some components expect to be able
to use the `location` prop that is passed in by `Router`. You can fix this by
manually passing in the prop:
Expand Down

1 comment on commit 8f32dd6

@shannonbux
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

Please sign in to comment.