Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ensure babel-preset-gatsby can be used with unit tests #9629

Merged
merged 12 commits into from
Nov 5, 2018
105 changes: 45 additions & 60 deletions docs/docs/unit-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,26 @@ npm install --save-dev jest babel-jest react-test-renderer identity-obj-proxy 'b
```

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"`
section in your `package.json`. You can set up some useful defaults at the same
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:

```json:title=package.json
"jest": {
"transform": {
"^.+\\.jsx?$": "<rootDir>/jest-preprocess.js"
},
"testRegex": "/.*(__tests__\\/.*)|(.*(test|spec))\\.jsx?$",
"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__/fileMock.js"
},
"testPathIgnorePatterns": ["node_modules", ".cache"],
"transformIgnorePatterns": [
"node_modules/(?!(gatsby)/)"
],
"globals": {
"__PATH_PREFIX__": ""
},
"testURL": "http://localhost",
"setupFiles": [
"<rootDir>/loadershim.js"
]
}
```json:title=jest.config.js
module.exports = {
"transform": {
"^.+\\.jsx?$": "<rootDir>/jest-preprocess.js"
},
"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__/fileMock.js"
},
"testPathIgnorePatterns": ["node_modules", ".cache"],
"transformIgnorePatterns": ["node_modules/(?!(gatsby)/)"],
"globals": {
"__PATH_PREFIX__": ""
},
"testURL": "http://localhost",
"setupFiles": ["<rootDir>/loadershim.js"]
}
```

The `transform` section tells Jest that all `js` or `jsx` files need to be
Expand Down Expand Up @@ -150,11 +144,12 @@ import React from "react"
import renderer from "react-test-renderer"
import Bio from "./Bio"

describe("Bio", () =>
describe("Bio", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is quite a bit clearer/real-world, even though both were valid

it("renders correctly", () => {
const tree = renderer.create(<Bio />).toJSON()
expect(tree).toMatchSnapshot()
}))
})
})
```

This is a very simple snapshot test, which uses `react-test-renderer` to render
Expand Down Expand Up @@ -220,39 +215,28 @@ config. First install `ts-jest`:
npm install --save-dev ts-jest
```

Then edit the Jest config in your `package.json` to match this:

```json:title=package.json
"jest": {
"transform": {
"^.+\\.tsx?$": "ts-jest",
"^.+\\.jsx?$": "<rootDir>/jest-preprocess.js"
},
"testRegex": "(/__tests__/.*\\.([tj]sx?)|(\\.|/)(test|spec))\\.([tj]sx?)$",
"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__/fileMock.js"
},
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"testPathIgnorePatterns": ["node_modules", ".cache"],
"transformIgnorePatterns": [
"node_modules/(?!(gatsby)/)"
],
"globals": {
"__PATH_PREFIX__": ""
},
"testURL": "http://localhost",
"setupFiles": [
"<rootDir>/loadershim.js"
]
}
Then update the configuration in `jest.config.js`, like so:

```json:title=jest.config.js
module.exports = {
"transform": {
"^.+\\.tsx?$": "ts-jest",
"^.+\\.jsx?$": "<rootDir>/jest-preprocess.js"
},
"testRegex": "(/__tests__/.*\\.([tj]sx?)|(\\.|/)(test|spec))\\.([tj]sx?)$",
"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__/fileMock.js"
},
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
"testPathIgnorePatterns": ["node_modules", ".cache"],
"transformIgnorePatterns": ["node_modules/(?!(gatsby)/)"],
"globals": {
"__PATH_PREFIX__": ""
},
"testURL": "http://localhost",
"setupFiles": ["<rootDir>/loadershim.js"]
}
```

## Testing components with Router
Expand Down Expand Up @@ -295,7 +279,7 @@ import React from "react"
import renderer from "react-test-renderer"
import BlogIndex from "../pages/index"

describe("BlogIndex", () =>
describe("BlogIndex", () => {
it("renders correctly", () => {
const location = {
pathname: "/",
Expand All @@ -304,6 +288,7 @@ describe("BlogIndex", () =>
const tree = renderer.create(<BlogIndex location={location} />).toJSON()
expect(tree).toMatchSnapshot()
}))
})
```

For more information on testing page components, be sure to read the docs on
Expand Down
3 changes: 3 additions & 0 deletions examples/using-jest/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public
.cache
node_modules
5 changes: 5 additions & 0 deletions examples/using-jest/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "es5"
}
22 changes: 22 additions & 0 deletions examples/using-jest/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2015 gatsbyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17 changes: 17 additions & 0 deletions examples/using-jest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<p align="center">
<a href="https://www.gatsbyjs.org">
<img alt="Gatsby" src="https://www.gatsbyjs.org/monogram.svg" width="60" />
</a>
</p>
<h1 align="center">
using Jest
</h1>

Kick off your next Gatsby app with some great testing practices enabled via [Jest][jest], [react-testing-library][react-testing-library], and of course, [Gatsby][gatsby] 💪

Check out the [unit testing doc][unit-testing-doc] for further info!
Copy link
Contributor

Choose a reason for hiding this comment

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

will this link work? Looks...incomplete to me

Copy link
Contributor

Choose a reason for hiding this comment

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

oh and it's mentioned below too, with the complete link

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah! These are markdown style links, so it's like a table of links that it refers to below. Actually a good practice to get into, I think :) Keeps links in one place so they're easy to edit/re-use!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just as an example if it's helpful!

This is a link to [google][google], and [this link][google] will also refer to the google link! 🎉 

[google]: https://google.com

Copy link
Contributor

Choose a reason for hiding this comment

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

ohhhhhh kewl

Copy link
Contributor

Choose a reason for hiding this comment

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

that seems handy. I'll keep that in mind!


[jest]: https://jestjs.io/
[react-testing-library]: https://github.com/kentcdodds/react-testing-library
[gatsby]: https://gatsbyjs.org
[unit-testing-doc]: https://www.gatsbyjs.org/docs/unit-testing/
1 change: 1 addition & 0 deletions examples/using-jest/__mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub'
14 changes: 14 additions & 0 deletions examples/using-jest/__mocks__/gatsby.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const React = require('react')
const gatsby = jest.requireActual('gatsby')

module.exports = {
...gatsby,
graphql: jest.fn(),
Link: jest.fn().mockImplementation(({ to, ...rest }) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is kinda janky, but I also think that this should probably be added to the docs/unit-testing.md document!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(also just for clarity here, gatsby-link errors out in Jest, so this is a way to side step that issue)

React.createElement('a', {
...rest,
href: to,
})
),
StaticQuery: jest.fn(),
}
30 changes: 30 additions & 0 deletions examples/using-jest/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module.exports = {
siteMetadata: {
title: 'Gatsby Default Starter',
},
plugins: [
'gatsby-plugin-react-helmet',
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
'gatsby-transformer-sharp',
'gatsby-plugin-sharp',
{
resolve: `gatsby-plugin-manifest`,
options: {
name: 'gatsby-starter-default',
short_name: 'starter',
start_url: '/',
background_color: '#663399',
theme_color: '#663399',
display: 'minimal-ui',
icon: 'src/images/gatsby-icon.png', // This path is relative to the root of the site.
},
},
'gatsby-plugin-offline',
],
}
5 changes: 5 additions & 0 deletions examples/using-jest/jest-preprocess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const babelOptions = {
presets: ['babel-preset-gatsby'],
}

module.exports = require('babel-jest').createTransformer(babelOptions)
18 changes: 18 additions & 0 deletions examples/using-jest/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
transform: {
'^.+\\.jsx?$': '<rootDir>/jest-preprocess.js',
},
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__/fileMock.js',
},
testPathIgnorePatterns: ['node_modules', '.cache'],
transformIgnorePatterns: ['node_modules/(?!(gatsby)/)'],
globals: {
__PATH_PREFIX__: '',
},
testURL: 'http://localhost',
setupTestFrameworkScriptFile: '<rootDir>/jest.setup.js',
setupFiles: ['<rootDir>/loadershim.js'],
}
2 changes: 2 additions & 0 deletions examples/using-jest/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import 'jest-dom/extend-expect'
import 'react-testing-library/cleanup-after-each'
3 changes: 3 additions & 0 deletions examples/using-jest/loadershim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global.___loader = {
enqueue: jest.fn(),
}
49 changes: 49 additions & 0 deletions examples/using-jest/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "using-jest",
"description": "An example repository demonstrating unit testing a Gatsby application with Jest",
"version": "1.0.0",
"author": "Dustin Schau <dustin@gatsbyjs.com>",
"dependencies": {
"gatsby": "^2.0.19",
"gatsby-image": "^2.0.15",
"gatsby-plugin-manifest": "^2.0.5",
"gatsby-plugin-offline": "^2.0.5",
"gatsby-plugin-react-helmet": "^3.0.0",
"gatsby-plugin-sharp": "^2.0.7",
"gatsby-source-filesystem": "^2.0.4",
"gatsby-transformer-sharp": "^2.1.4",
"react": "^16.5.1",
"react-dom": "^16.5.1",
"react-helmet": "^5.2.0"
},
"keywords": [
"gatsby",
"jest",
"test",
"testing"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"start": "npm run develop",
"format": "prettier --write \"src/**/*.js\"",
"test": "jest"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"babel-core": "^7.0.0-0",
"babel-jest": "^23.6.0",
"babel-preset-gatsby": "^0.1.2",
"identity-obj-proxy": "^3.0.0",
"jest": "^23.6.0",
"jest-dom": "^2.1.0",
"prettier": "^1.14.2",
"react-test-renderer": "^16.6.0",
"react-testing-library": "^5.2.3"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby"
}
}
15 changes: 15 additions & 0 deletions examples/using-jest/src/components/__tests__/header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import { render } from 'react-testing-library'

import Header from '../header'

describe('Header', () => {
it('renders siteTitle', () => {
const siteTitle = 'Hello World'
const { getByTestId } = render(<Header siteTitle={siteTitle} />)

const title = getByTestId('title')

expect(title).toHaveTextContent(siteTitle)
})
})
30 changes: 30 additions & 0 deletions examples/using-jest/src/components/__tests__/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'
import { render } from 'react-testing-library'
import { StaticQuery } from 'gatsby' // mocked

import Image from '../image'

beforeEach(() => {
StaticQuery.mockImplementationOnce(({ render }) =>
render({
placeholderImage: {
childImageSharp: {
fluid: {
aspectRatio: 1,
sizes: '100 200 300',
src: 'pretend-i-am-a-base64-encoded-image',
srcSet: 'asdfasdf',
},
},
},
})
)
})

describe('Image', () => {
it('renders an image', () => {
const { container } = render(<Image />)

expect(container.querySelector('picture')).toBeInTheDocument()
})
})
Loading