Is there a Jest example?
I can't find anything, and couldn't really get it to work in my gatsby project.
I'm using Gatsby with Jest on a project. You didn't say what sort of issues you ran into... Here's what my Jest setup looks like:
https://gist.github.com/m-allanson/3dd343db56951ba852fd09a7e52d6a89
I'm using Gatsby's built-in PostCSS / CSS Modules setup for CSS. I'm also using Storybook, if you're not using that too then you might be able to skip some of that config.
@m-allanson Do you have examples of testing a component?
I use Jest with React all the time, but when I use it with Gatsby, it always goes into the libraries imported inside a component's JS file, and finds issues with them, although the library is not even being used with the component, and I'm only importing that specific component from the file, e.g:
import { HeaderBox } from '../layouts/index'
Hmm I don't think I've had any issues like that. I'm basically just snapshotting everything in /src/components
using Storybook's Storyshots.
@theiliad your configuration needs fine tuning. I'm using jest with my project. No complications with Gatsbyjs.
@nodox Do you have some sample code by any chance?
@theiliad Maybe you can check my settings, Jest is running fine with my Gatsby setup: https://github.com/DesarrolloWebSantaCC/santacc-web/tree/master/test
I wonder if there is a way to inherit Gatsby's Babel configuration in Jest.
This is my quick and dirty way of (more or less) replicating Gatsby's configuration:
npm install --save-dev babel-jest
```js
// test/transformer.js
module.exports = require('babel-jest').createTransformer({
presets: [
// built-in
['env', {
modules: 'commonjs',
targets: {
node: 'current',
},
exclude: ['transform-regenerator', 'transform-es2015-typeof-symbol'],
}],
'stage-0',
'react',
// custom...
],
plugins: [
// built-in
'gatsby/dist/utils/babel-plugin-extract-graphql',
'add-module-exports',
'transform-object-assign',
// custom...
],
})
```js
// jest.config.js
module.exports = {
transform: { '^.+\\.jsx?$': '<rootDir>/test/transformer.js' }
}
Every time you update the above Babel configuration you need to clear Jest's cache:
npx jest --clearCache
I have one issue with Gatsby and Jest and that is when needing to test a component that uses <Link>
(from 'gatsby-link'
)
I get this error
FAIL src/components/header/header.spec.jsx
Header Component
✕ should not be null (23ms)
● Header Component › should not be null
TypeError: Cannot read property 'history' of undefined
10 |
11 | beforeEach(() => {
> 12 | header = mount(<Header/>);
13 | });
14 |
at new GatsbyLink (node_modules/gatsby-link/index.js:107:34)
at node_modules/react-dom/lib/ReactCompositeComponent.js:292:18
at measureLifeCyclePerf (node_modules/react-dom/lib/ReactCompositeComponent.js:73:12)
Component
import React from 'react';
import Link from 'gatsby-link';
import './header.css';
const Header = () => {
return (
<div className="header">
<Link to="/">
<header></header>
<h2 className="caption">A DREAMER BY DESIGN</h2>
</Link>
</div>
);
};
export default Header;
Test
import * as React from 'react';
import { mount, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
import Header from './header';
configure({ adapter: new Adapter() });
describe('Header Component', () => {
let header;
beforeEach(() => {
header = mount(<Header/>);
});
it('should not be null', () => {
expect(header).not.toBeNull();
expect(header.find('.header').length).toEqual(1);
});
});
Otherwise I've had good luck with Jest and Gatsby in my project
@thescientist13 i just mock out that dependency - e.g.
import { a } from 'react-dom-factories';
import omit from 'lodash/omit';
const Link = jest.genMockFromModule('gatsby-link');
Link.default.prototype.render = function(){
const domProps = Object.assign(
{ href: 'GATSBY-LINK-MOCK' },
omit(this.props, ['to', 'onClick'])
);
return a(domProps);
};
module.exports = Link;
it's a bit ham-handed in that you lose visibility into the actual href
but it has gotten me by ok so far 🤷♂️
It probably needs history
from the Router
component which Gatsby uses. Gatsby should maybe expose some kind of test utils for that.
@silvenon , yeah, that sounds about right. I was trying to do something like this but wasn't having luck
I'm stuck on this and have no idea why it doesn't work:
import React from 'react'
import { render, Simulate } from 'react-testing-library'
import Link from 'gatsby-link'
import { createMemoryHistory as createHistory } from 'history'
import { Router } from 'react-router'
describe('link', () => {
beforeAll(() => {
global.___loader = {
enqueue: jest.fn(),
}
})
it('navigates to path on click', () => {
const history = createHistory()
const { getByText, unmount } = render(
<Router history={history}>
<Link to="/path">Click me</Link>
</Router>,
)
Simulate.click(getByText('Click me'))
expect(history.location.pathname).toBe('/path')
unmount()
})
})
The Link
component should call history.push
on click, but it doesn't.
It works if I do history.push('/path')
manually.
I had some luck with using Enzyme
instead of react-test-renderer
.
I was configuring snapshot testing with Jest, and i actually think the issue here is that Gatsby is not exposing the context from react-router
.
This is my test, that i got working:
import Header from '../Header';
describe('Header component', () => {
it('renders correctly', () => {
const rendered = shallow(
<Header />
);
expect(rendered).toMatchSnapshot();
});
});
Enzyme setup:
const enzyme = require('enzyme');
const Adapter = require('enzyme-adapter-react-16');
/**
* React 16 Enzyme adapter
*/
enzyme.configure({ adapter: new Adapter() });
/**
* Make Enzyme functions available in all test files without importing
*/
global.shallow = enzyme.shallow;
global.render = enzyme.render;
global.mount = enzyme.mount;
package.json
"jest": {
"transform": {
".(js|jsx)": "babel-jest"
},
"testRegex": "(\\.(test|spec))\\.(jsx|js)$",
"testPathIgnorePatterns": [
"/node_modules/",
"/.cache/"
],
"setupFiles": [
"./jest-setup.js"
]
},
Hope that can help your use case too.
Figured it out, the Link
component from react-router-dom
used in gatsby-link
checks if event.button === 0
:
Simulate.click(getByText('Click me'), { button: 0 })
Facebooks test utilities currently don't do this by default. facebook/react#12476
@fredjens that explains why I needed to add react-router in my dev dependencies for testing.
@silvenon thanks for this! I had this issue for a while and avoided looking for a solution 😅
I´m stuck here. Trying to test with enzyme and I get this error:
Cannot find module 'react/lib/ReactComponentTreeHook' from 'ReactDebugTool.js'
My package.json:
{
"name": "gatsby-starter-default",
"description": "Gatsby default starter",
"version": "1.0.0",
"author": "Kyle Mathews <[email protected]>",
"dependencies": {
"emotion": "^9.1.0",
"emotion-server": "^9.1.0",
"file-loader": "^1.1.11",
"gatsby": "^1.9.241",
"gatsby-link": "^1.6.39",
"gatsby-plugin-react-helmet": "^2.0.8",
"gatsby-plugin-react-next": "^1.0.11",
"gatsby-plugin-resolve-src": "^1.0.0",
"gatsby-plugin-sass": "^1.0.25",
"gatsby-plugin-sharp": "^1.6.41",
"gatsby-remark-component": "^1.1.3",
"gatsby-remark-images": "^1.5.60",
"gatsby-source-filesystem": "^1.5.27",
"gatsby-transformer-remark": "^1.7.39",
"prop-types": "^15.6.1",
"react-animated-css": "^1.0.4",
"react-emotion": "^9.1.0",
"react-helmet": "^5.2.0",
"rehype-react": "^3.0.2",
"remark-parse": "^5.0.0",
"remark-rehype": "^3.0.0"
},
"keywords": [
"gatsby"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write 'src/**/*.js'",
"test": "jest",
"test:watch": "jest --watch"
},
"devDependencies": {
"babel-eslint": "^7.2.3",
"babel-jest": "^22.4.3",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.3",
"eslint": "^4.9.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-config-prettier": "^2.6.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-react": "^7.4.0",
"jest": "^22.4.3",
"prettier": "^1.11.1",
"react-test-renderer": "^16.3.0"
},
"jest": {
"transform": {
".(js|jsx)": "babel-jest"
},
"testRegex": "(\\.(test|spec))\\.(jsx|js)$",
"testPathIgnorePatterns": [
"/node_modules/",
"/.cache/"
],
"moduleFileExtensions": [
"jsx",
"js"
],
"collectCoverage": true,
"coverageReporters": [
"lcov",
"text",
"html"
],
"setupFiles": [
"./jest-setup.js"
]
}
}
jest-setup.js
const enzyme = require('enzyme')
const Adapter = require('enzyme-adapter-react-16')
enzyme.configure({ adapter: new Adapter() })
global.shallow = enzyme.shallow
global.render = enzyme.render
global.mount = enzyme.mount
Did anyone have a similar problem?
For some reason the react-dom import was from an different version then the react one ( I guess that this happened with the gatsby-react-next ). So a npm i --save react-dom
( updating it to 16.3.0 ) solved the problem.
@ThiagoMiranda You can also alias the gatsby-react-next
version of react
and react-dom
in your jest config.
moduleNameMapper: {
'^react$': `gatsby-plugin-react-next/node_modules/react`,
'^react-dom$': `gatsby-plugin-react-next/node_modules/react-dom`,
},
@silvenon
Thanks for this post, it helped me solve a issue with v2 Gatsby testing! 🎉
FYI, for anyone in the position to migrate to v2, there is a new testing guide up that and there has been a lot of work done to smooth out the testing process for users. Some of it should still be applicable here I think
https://github.com/gatsbyjs/gatsby/pull/6678
I was able to get a pretty good set of unit tests working for a component that uses <Link>
in v2, which unblocked a lot of code paths I hadn't been able to cover before. I left a working example and steps here.
@KyleAMathews / @m-allanson
Any thoughts on how to handle this in terms of v1 support? The issue seem pretty well handled now in v2 (though there still might be some edge cases, admittedly).
The core team is focused on getting v2 out. We'd be happy to support people who'd like to backport (non-breaking) fixes/changes to v1.
Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!
Most helpful comment
It probably needs
history
from theRouter
component which Gatsby uses. Gatsby should maybe expose some kind of test utils for that.