Gathering detailed insights and metrics for jest-styled-components
Gathering detailed insights and metrics for jest-styled-components
Gathering detailed insights and metrics for jest-styled-components
Gathering detailed insights and metrics for jest-styled-components
styled-components
CSS for the <Component> Age. Style components your way with speed, strong typing, and flexibility.
babel-plugin-styled-components
Improve the debugging experience and add server-side rendering support to styled-components
@mui/styled-engine
styled() API wrapper package for emotion.
polished
A lightweight toolset for writing styles in Javascript.
🔧 💅 Jest utilities for Styled Components
npm install jest-styled-components
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
1,584 Stars
348 Commits
145 Forks
35 Watching
8 Branches
147 Contributors
Updated on 09 Nov 2024
Minified
Minified + Gzipped
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
5.7%
151,627
Compared to previous day
Last week
13.6%
767,433
Compared to previous week
Last month
9%
3,013,332
Compared to previous month
Last year
6.5%
34,607,342
Compared to previous year
1
1
28
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.
1yarn add --dev jest-styled-components
1import React from 'react' 2import styled from 'styled-components' 3import renderer from 'react-test-renderer' 4import 'jest-styled-components' 5 6const Button = styled.button` 7 color: red; 8` 9 10test('it works', () => { 11 const tree = renderer.create(<Button />).toJSON() 12 expect(tree).toMatchSnapshot() 13 expect(tree).toHaveStyleRule('color', 'red') 14})
If you don't want to import the library in every test file, it's recommended to use the global installation method.
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:
1import styled from 'styled-components' 2 3const Button = styled.button` 4 color: red; 5`
Which we cover with the following test:
1import React from 'react' 2import renderer from 'react-test-renderer' 3 4test('it works', () => { 5 const tree = renderer.create(<Button />).toJSON() 6 expect(tree).toMatchSnapshot() 7})
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:
1exports[`it works 1`] = ` 2<button 3 className="sc-bdVaJa rOCEJ" 4/> 5`;
Consequently, changing the color to green:
1const Button = styled.button` 2 color: green; 3`
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).
1- Snapshot 2+ Received 3 4 <button 5- className="sc-bdVaJa rOCEJ" 6+ className="sc-bdVaJa hUzqNt" 7 />
Here's where Jest Styled Components comes to rescue.
We import the package into our test file:
1import '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:
1- Snapshot 2+ Received 3 4+.c0 { 5+ color: green; 6+} 7+ 8 <button 9- className="sc-bdVaJa rOCEJ" 10+ className="c0" 11 />
This is the resulting snapshot:
1exports[`it works 1`] = ` 2.c0 { 3 color: green; 4} 5 6<button 7 className="c0" 8/> 9`;
Now, suppose we change the color again to blue:
1const Button = styled.button` 2 color: blue; 3`
Thanks to Jest Styled Components, Jest is now able to provide the exact information and make our testing experience even more delightful 💖:
1- Snapshot 2+ Received 3 4 .c0 { 5- color: green; 6+ color: blue; 7 } 8 9 <button 10 className="c0" 11 />
enzyme-to-json is necessary to generate snapshots using Enzyme's shallow or full DOM rendering.
1yarn add --dev enzyme-to-json
It can be enabled globally in the package.json
:
1"jest": { 2 "snapshotSerializers": [ 3 "enzyme-to-json/serializer" 4 ] 5}
Or imported in each test:
1import toJson from 'enzyme-to-json' 2 3// ... 4 5expect(toJson(wrapper)).toMatchSnapshot()
Jest Styled Components works with shallow rendering:
1import { shallow } from 'enzyme' 2 3test('it works', () => { 4 const wrapper = shallow(<Button />) 5 expect(wrapper).toMatchSnapshot() 6})
And full DOM rendering as well:
1import { mount } from 'enzyme' 2 3test('it works', () => { 4 const wrapper = mount(<Button />) 5 expect(wrapper).toMatchSnapshot() 6})
To generate snapshots with react-testing-library, you can follow the example below:
1import { render } from '@testing-library/react' 2 3test('it works', () => { 4 const { container } = render(<Button />) 5 expect(container.firstChild).toMatchSnapshot() 6})
The snapshots will contain
class
instead ofclassName
because the snapshots are of DOM elements
In some scenarios, testing components that depend on a theme can be tricky, especially when using Enzyme's shallow rendering.
For example:
1const Button = styled.button` 2 color: ${props => props.theme.main}; 3` 4 5const theme = { 6 main: 'mediumseagreen', 7}
The recommended solution is to pass the theme as a prop:
1const wrapper = shallow(<Button theme={theme} />)
The following function might also help for shallow rendering:
1const shallowWithTheme = (tree, theme) => { 2 const context = shallow(<ThemeProvider theme={theme} />) 3 .instance() 4 .getChildContext() 5 return shallow(tree, { context }) 6} 7 8const wrapper = shallowWithTheme(<Button />, theme)
and for full DOM rendering:
1const mountWithTheme = (tree, theme) => { 2 const context = shallow(<ThemeProvider theme={theme} />) 3 .instance() 4 .getChildContext() 5 6 return mount(tree, { 7 context, 8 childContextTypes: ThemeProvider.childContextTypes, 9 }) 10}
To generate snapshots of Preact components, add the following configuration:
1"jest": { 2 "moduleNameMapper": { 3 "^react$": "preact-compat" 4 } 5}
And render the components with preact-render-to-json:
1import React from 'react' 2import styled from 'styled-components' 3import render from 'preact-render-to-json' 4import 'jest-styled-components' 5 6const Button = styled.button` 7 color: red; 8` 9 10test('it works', () => { 11 const tree = render(<Button />) 12 expect(tree).toMatchSnapshot() 13})
The snapshots will contain
class
instead ofclassName
. Learn more.
The serializer can be imported separately from jest-styled-components/serializer
.
This makes it possible to use this package with specific-snapshot and other libraries.
1import React from 'react' 2import styled from 'styled-components' 3import renderer from 'react-test-renderer' 4import { styleSheetSerializer } from "jest-styled-components/serializer" 5import { addSerializer } from "jest-specific-snapshot" 6 7addSerializer(styleSheetSerializer) 8 9const Button = styled.button` 10 color: red; 11` 12 13test('it works', () => { 14 const tree = renderer.create(<Button />).toJSON() 15 expect(tree).toMatchSpecificSnapshot("./Button.snap") 16})
The serializer can be configured to control the snapshot output.
1import { render } from '@testing-library/react' 2import { setStyleSheetSerializerOptions } from 'jest-styled-components/serializer' 3 4setStyleSheetSerializerOptions({ 5 addStyles: false, 6 classNameFormatter: (index) => `styled${index}` 7}); 8 9test('it works', () => { 10 const { container } = render(<Button />) 11 expect(container.firstChild).toMatchSnapshot() 12})
The toHaveStyleRule
matcher is useful to test if a given rule is applied to a component.
The first argument is the expected property, the second is the expected value which can be a String, RegExp, Jest asymmetric matcher or undefined
.
When used with a negated ".not" modifier the second argument is optional and can be omitted.
1const Button = styled.button` 2 color: red; 3 border: 0.05em solid ${props => props.transparent ? 'transparent' : 'black'}; 4 cursor: ${props => !props.disabled && 'pointer'}; 5 opacity: ${props => props.disabled && '.65'}; 6` 7 8test('it applies default styles', () => { 9 const tree = renderer.create(<Button />).toJSON() 10 expect(tree).toHaveStyleRule('color', 'red') 11 expect(tree).toHaveStyleRule('border', '0.05em solid black') 12 expect(tree).toHaveStyleRule('cursor', 'pointer') 13 expect(tree).not.toHaveStyleRule('opacity') // equivalent of the following two 14 expect(tree).not.toHaveStyleRule('opacity', expect.any(String)) 15 expect(tree).toHaveStyleRule('opacity', undefined) 16}) 17 18test('it applies styles according to passed props', () => { 19 const tree = renderer.create(<Button disabled transparent />).toJSON() 20 expect(tree).toHaveStyleRule('border', expect.stringContaining('transparent')) 21 expect(tree).toHaveStyleRule('cursor', undefined) 22 expect(tree).toHaveStyleRule('opacity', '.65') 23})
The matcher supports an optional third options
parameter which makes it possible to search for rules nested within an At-rule (see media and supports) or to add modifiers to the class selector. This feature is supported in React only, and more options are coming soon.
1const Button = styled.button` 2 @media (max-width: 640px) { 3 &:hover { 4 color: red; 5 } 6 } 7` 8 9test('it works', () => { 10 const tree = renderer.create(<Button />).toJSON() 11 expect(tree).toHaveStyleRule('color', 'red', { 12 media: '(max-width:640px)', 13 modifier: ':hover', 14 }) 15})
If a rule is nested within another styled-component, the modifier
option can be used with the css
helper to target the nested rule.
1const Button = styled.button` 2 color: red; 3` 4 5const ButtonList = styled.div` 6 display: flex; 7 8 ${Button} { 9 flex: 1 0 auto; 10 } 11` 12 13import { css } from 'styled-components'; 14 15test('nested buttons are flexed', () => { 16 const tree = renderer.create(<ButtonList><Button /></ButtonList>).toJSON() 17 expect(tree).toHaveStyleRule('flex', '1 0 auto', { 18 modifier: css`${Button}`, 19 }) 20})
You can take a similar approach when you have classNames that override styles
1const Button = styled.button` 2 background-color: red; 3 4 &.override { 5 background-color: blue; 6 } 7` 8const wrapper = mount(<Button className="override">I am a button!</Button>); 9 10expect(wrapper).toHaveStyleRule('background-color', 'blue', { 11 modifier: '&.override', 12});
This matcher works with trees serialized with react-test-renderer
, react-testing-library
, or those shallow rendered or mounted with Enzyme.
It checks the style rules applied to the root component it receives, therefore to make assertions on components further in the tree they must be provided separately (Enzyme's find might help).
Note: for
react-testing-library
, you'll need to pass the first child to check the top-level component's style. To check the styles of deeper components, you can use one of thegetBy*
methods to find the element (e.g.expect(getByTestId('styled-button')).toHaveStyleRule('color', 'blue')
)
To use the toHaveStyleRule
matcher with React Native, change the import statement to:
1import 'jest-styled-components/native'
It is possible to setup this package for all the tests. For Example: import the library once in the src/setupTests.js
as follows:
1import 'jest-styled-components'
...then add the following to test.config.js
:
1 setupFilesAfterEnv: ['<rootDir>/src/setupTests.js']
If Jest Styled Components is not working, it is likely caused by loading multiple instances of styled-components
. This can happen especially when working with a Lerna monorepo. Starting with styled-components@3.2.0
, a warning will be logged when multiple instances of it are being included and run as part of the Jest tests. Using styled-components@3.1.6
and lower with multiple instances will cause a silent error with unexpected results.
To debug and fix multiple instances of styled-components
see the FAQ on "Why am I getting a warning about several instances of module on the page?".
Please open an issue and discuss with us before submitting a PR.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
SAST tool detected but not run on all commits
Details
Reason
Found 6/15 approved changesets -- score normalized to 4
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
14 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More