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

JEST + Gatsby #2932

Closed
theiliad opened this issue Nov 15, 2017 · 22 comments
Closed

JEST + Gatsby #2932

theiliad opened this issue Nov 15, 2017 · 22 comments

Comments

@theiliad
Copy link
Contributor

Is there a Jest example?

I can't find anything, and couldn't really get it to work in my gatsby project.

@m-allanson
Copy link
Contributor

m-allanson commented Nov 16, 2017

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.

@theiliad
Copy link
Contributor Author

@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'

@m-allanson
Copy link
Contributor

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.

@nodox
Copy link
Contributor

nodox commented Nov 17, 2017

@theiliad your configuration needs fine tuning. I'm using jest with my project. No complications with Gatsbyjs.

@theiliad
Copy link
Contributor Author

@nodox Do you have some sample code by any chance?

@miguelcalderon
Copy link
Contributor

@theiliad Maybe you can check my settings, Jest is running fine with my Gatsby setup: https://github.com/DesarrolloWebSantaCC/santacc-web/tree/master/test

@silvenon
Copy link

silvenon commented Mar 6, 2018

I wonder if there is a way to inherit Gatsby's Babel configuration in Jest.

@silvenon
Copy link

silvenon commented Mar 6, 2018

This is my quick and dirty way of (more or less) replicating Gatsby's configuration:

npm install --save-dev babel-jest
// 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...
  ],
})
// 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

@thescientist13
Copy link
Contributor

thescientist13 commented Mar 26, 2018

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

@busticated
Copy link
Contributor

@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 🤷‍♂️

@silvenon
Copy link

It probably needs history from the Router component which Gatsby uses. Gatsby should maybe expose some kind of test utils for that.

@thescientist13
Copy link
Contributor

@silvenon , yeah, that sounds about right. I was trying to do something like this but wasn't having luck

@silvenon
Copy link

silvenon commented Mar 28, 2018

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.

@fredjens
Copy link

fredjens commented Mar 28, 2018

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.

@silvenon
Copy link

silvenon commented Mar 28, 2018

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

@nodox
Copy link
Contributor

nodox commented Mar 29, 2018

@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 😅

@ThiagoMiranda
Copy link

ThiagoMiranda commented Apr 3, 2018

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?

Update

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.

@shwanton
Copy link

@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`,
  },

@thescientist13
Copy link
Contributor

thescientist13 commented Jul 28, 2018

@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
#6678

@thescientist13
Copy link
Contributor

thescientist13 commented Jul 28, 2018

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).

@KyleAMathews
Copy link
Contributor

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.

@KyleAMathews
Copy link
Contributor

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests