README
Jest Styled Components
A set of utilities for testing Styled Components with Jest. This package improves the snapshot testing experience and provides a brand new matcher to make expectations on the style rules.
Quick Start
Installation
yarn add --dev jest-styled-components
Usage
import React from 'react'
import styled from 'styled-components'
import renderer from 'react-test-renderer'
import 'jest-styled-components'
const Button = styled.button`
color: red;
`
test('it works', () => {
const tree = renderer.create(<Button />).toJSON()
expect(tree).toMatchSnapshot()
expect(tree).toHaveStyleRule('color', 'red')
})
If you don't want to import the library in every test file, it's recommended to use the global installation method.
Table of Contents
Snapshot Testing
Jest snapshot testing is an excellent way to test React components (or any serializable value) and make sure things don't change unexpectedly. It works with Styled Components but there are a few problems that this package addresses and solves.
For example, suppose we create this styled Button:
import styled from 'styled-components'
const Button = styled.button`
color: red;
`
Which we cover with the following test:
import React from 'react'
import renderer from 'react-test-renderer'
test('it works', () => {
const tree = renderer.create(<Button />).toJSON()
expect(tree).toMatchSnapshot()
})
When we run our test command, Jest generates a snapshot containing a few class names (which we didn't set) and no information about the style rules:
exports[`it works 1`] = `
<button
className="sc-bdVaJa rOCEJ"
/>
`;
Consequently, changing the color to green:
const Button = styled.button`
color: green;
`
Results in the following diff, where Jest can only tell us that the class names are changed. Although we can assume that if the class names are changed the style rules are also changed, this is not optimal (and is not always true).
- Snapshot
+ Received
<button
- className="sc-bdVaJa rOCEJ"
+ className="sc-bdVaJa hUzqNt"
/>
Here's where Jest Styled Components comes to rescue.
We import the package into our test file:
import 'jest-styled-components'
When we rerun the test, the output is different: the style rules are included in the snapshot, and the hashed class names are substituted with placeholders that make the diffs less noisy:
- Snapshot
+ Received
+.c0 {
+ color: green;
+}
+
<button
- className="sc-bdVaJa rOCEJ"
+ className="c0"
/>
This is the resulting snapshot:
exports[`it works 1`] = `
.c0 {
color: green;
}
<button
className="c0"
/>
`;
Now, suppose we change the color again to blue:
const Button = styled.button`
color: blue;
`
Thanks to Jest Styled Components, Jest is now able to provide the exact information and make our testing experience even more delightful 💖:
- Snapshot
+ Received
.c0 {
- color: green;
+ color: blue;
}
<button
className="c0"
/>
Enzyme
enzyme-to-json is necessary to generate snapshots using Enzyme's shallow or full DOM rendering.
yarn add --dev enzyme-to-json
It can be enabled globally in the package.json
:
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}
Or imported in each test:
import toJson from 'enzyme-to-json'
// ...
expect(toJson(wrapper)).toMatchSnapshot()
Jest Styled Components works with shallow rendering:
import { shallow } from 'enzyme'
test('it works', () => {
const wrapper = shallow(<Button />)
expect(wrapper).toMatchSnapshot()
})
And full DOM rendering as well:
import { mount } from 'enzyme'
test('it works', () => {
const wrapper = mount(<Button />)
expect(wrapper).toMatchSnapshot()
})
react-testing-library
To generate snapshots with react-testing-library, you can follow the example below:
import { render } from '@testing-library/react'
test('it works', () => {
const { container } = render(<Button />)
expect(container.firstChild).toMatchSnapshot()
})
The snapshots will contain
class
instead ofclassName
because the snapshots are of DOM elements
Theming
In some scenarios, testing components that depend on a theme can be tricky, especially when using Enzyme's shallow rendering.
For example:
const Button = styled.button`
color: ${props => props.theme.main};
`
const theme = {
main: 'mediumseagreen',
}
The recommended solution is to pass the theme as a prop:
const wrapper = shallow(<Button theme={theme} />)
The following function might also help for shallow rendering:
const shallowWithTheme = (tree, theme) => {
const context = shallow(<ThemeProvider theme={theme} />)
.instance()
.getChildContext()
return shallow(tree, { context })
}
const wrapper = shallowWithTheme(<Button />, theme)
and for full DOM rendering:
const mountWithTheme = (tree, theme) => {
const context = shallow(<ThemeProvider theme={theme} />)
.instance()
.getChildContext()
return mount(tree, {
context,
childContextTypes: ThemeProvider.childContextTypes,
})
}
Preact
To generate snapshots of Preact components, add the following configuration:
"jest": {
"moduleNameMapper": {
"^react