cypress-react-unit-test
A little helper to unit test React components in the open source Cypress.io E2E test runner v4.5.0+
Jump to: Comparison, Blog posts, Presentations, Install, Examples: basic, advanced, full, external, Mocking, Style options, Code coverage, Visual testing, Common problems, Chat
Survey
Hi there! We are trying to collect feedback from Cypress users who need component testing. Answer a few questions in this survey about component testing to help us 🙏
TLDR
- What is this? This package allows you to use Cypress test runner to unit test your React components with zero effort. Here is a typical component testing, notice there is not external URL shown, since it is mounting the component directly.
Comparison
Feature | Jest / Enzyme / RTL | Cypress + cypress-react-unit-test |
---|
Test runs in real browser | ❌ | ✅ |
Supports shallow mount | ✅ | ❌ |
Supports full mount | ✅ | ✅ |
Test speed | 🏎 | as fast as the app works in the browser |
Test can use additional plugins | maybe | use any Cypress plugin |
Test can interact with component | synthetic limited API | use any Cypress command |
Test can be debugged | via terminal and Node debugger | use browser DevTools |
Built-in time traveling debugger | ❌ | Cypress time traveling debugger |
Re-run tests on file or test change | ✅ | ✅ |
Test output on CI | terminal | terminal, screenshots, videos |
Tests can be run in parallel | ✅ | ✅ via parallelization |
Test against interface | if using @testing-library/react | ✅ and can use @testing-library/cypress |
Spying and stubbing methods | Jest mocks | Sinon library |
Stubbing imports | ✅ | ✅ |
Stubbing clock | ✅ | ✅ |
Code coverage | ✅ | ✅ |
If you are coming from Jest + RTL world, read Test The Interface Not The Implementation.
If you are coming from Enzyme world, check out the enzyme example.
Blog posts
Curious how we keep this library well-tested and all its examples up-to-date? Read the Testing Pyramids blog post.
Presentations
It is better to see something once than to hear about a thousand times. Watch one of the talks below to see this library in action.
Known problems
See issues labeled v4
Install
Requires Node version 8 or above.
npm install --save-dev cypress cypress-react-unit-test
Init
You can use our command line wizard to give you instructions on configuring this plugin. It will try to determine which framework or bundling tool you are using and give you instructions on right configuration.
cypress-react-unit-test init
Or continue with manual installation:
- Include this plugin from your project's
cypress/support/index.js
require('cypress-react-unit-test/support')
- Tell Cypress how your React application is transpiled or bundled (using Webpack), so Cypress can load your components. For example, if you use
react-scripts
(even after ejecting) do:
module.exports = (on, config) => {
require('cypress-react-unit-test/plugins/react-scripts')(on, config)
return config
}
See Recipes for more examples.
- ⚠️ Turn the experimental component support on in your
cypress.json
. You can also specify where component spec files are located. For example, to have them located in src
folder use:
{
"experimentalComponentTesting": true,
"componentFolder": "src"
}
API
mount
is the most important function, allows to mount a given React component as a mini web application and interact with it using Cypress commandscreateMount
factory function that creates new mount
function with default optionsunmount
removes previously mounted component, mostly useful to test how the component cleans up after itselfmountHook
mounts a given React Hook in a test component for full testing, see hooks
example
Examples
import React from 'react'
import { mount } from 'cypress-react-unit-test'
import { HelloWorld } from './hello-world.jsx'
describe('HelloWorld component', () => {
it('works', () => {
mount(<HelloWorld />)
cy.contains('Hello World!').should('be.visible')
})
})
Look at the examples in cypress/component folder. Here is the list of examples showing various testing scenarios.
Basic examples
Spec | Description |
---|
alias | Retrieve mounted component by its name or alias |
alert-spec.js | Component tries to use window.alert |
before-hook | Mount the component from before hook to run multiple tests against it |
counter-set-state | Counter component that uses this.state |
counter-use-hooks | Counter component that uses useState hook |
document-spec | Checks document dimensions from the component |
enzyme | Several specs showing how to recreate Enzyme's setProps , setState , and setContext methods. |
emotion-spec.js | Confirms the component is using @emotion/core and styles are set |
error-boundary-spec.js | Checks if an error boundary component works |
fails-correctly | Cypress test fails correctly when interacting with disabled elements |
pure-component-spec.js | Tests stateless component |
stateless-spec.js | Passes Cypress stub to the component, confirms the component calls it on click |
window-spec.js | In the component test, the spec window and the application's window where the component is running should be the same object |
css | Shows that component with import './Button.css' works |
css modules | Shows that component that using css modules styles works |
network | Confirms we can use cy.route to stub / spy on component's network calls |
no-visit | Component specs cannot call cy.visit |
re-render | Checking how the component re-renders when its props change |
react-book-by-chris-noring | Copied test examples from React Book and adapted for Cypress component tests |
react-tutorial | Tests from official ReactJS tutorial copied and adapted for Cypress component tests |
stub-example | Uses cy.stub as component props |
styles | Add extra styles to the component during testing using style , cssFile or stylesheets mount options |
toggle-example | Testing a toggle component using Cypress DOM commands |
typescript | A spec written in TypeScript, shows how to use import alias |
unmount | Verifies the component's behavior when it is unmounted from the DOM |
use-lodash-fp | Imports and tests methods from lodash/fp dependency |
styled-components | Test components that use styled-components |
plus a few smaller sanity specs in cypress/component/basic folder.
Advanced examples
Full examples
We have several subfolders in examples folder that have complete projects with just their dependencies installed in the root folder.
External examples
This way of component testing has been verified in a number of forked 3rd party projects.
To find more examples, see GitHub topic cypress-react-unit-test-example
Mocking
Using Cypress + cypress-react-unit-test your tests can mock everything:
Options
In most cases, the component already imports its own styles, thus it looks "right" during the test. If you need another CSS, the simplest way is to import it from the spec file:
import './styles/main.css'
import Footer from './Footer'
it('looks right', () => {
mount(<Footer />)
})
You can pass additional styles, css files and external stylesheets to load, see docs/styles.md for the full list of options.
const todo = {
id: '123',
title: 'Write more tests',
}
mount(<Todo todo={todo} />, {
stylesheets: [
'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css',
],
})
Additional configuration
If your React and React DOM libraries are installed in non-standard paths (think monorepo scenario), you can tell this plugin where to find them. In `cypress.json` specify paths like this:
{
"env": {
"cypress-react-unit-test": {
"react": "node_modules/react/umd/react.development.js",
"react-dom": "node_modules/react-dom/umd/react-dom.development.js"
}
}
}
Code coverage
If you are using plugins/cra-v3 it instruments the code on the fly using babel-plugin-istanbul
and generates report using dependency cypress-io/code-coverage (included). If you want to disable code coverage instrumentation and reporting, use --env coverage=false
or CYPRESS_coverage=false
or set in your cypress.json
file
{
"env": {
"coverage": false
}
}
Visual testing
You can use any Cypress Visual Testing plugin to perform visual testing from the component tests. This repo has several example projects, see visual-sudoku, visual-testing-with-percy, visual-testing-with-happo, and visual-testing-with-applitools.
For a larger Do-It-Yourself example with an hour long list of explanation videos, see bahmutov/sudoku repository. I explain how to write visual testing using open source tools in this blog post, video talk, and slides.
Common problems
Node Sass
When using Node Sass styles, tell Cypress to use the system NodeJS rather than its bundled version. In cypress.json
set option:
{
"nodeVersion": "system"
}
Find full example in sass-and-ts folder.
Slower than Jest
When you use cypress-X-unit-test
for component testing, you might notice the tests are slower than using Jest to test the same components. Yes, that's true. A test runner could be made extremely fast if it did nothing, just check out the auchenberg/volkswagen test runner - it is blazing on CI 😉. Of course, Jest does do things, just not inside the real browser environment.
Testing using Jest with its jsdom browser is faster than starting the real browser, loading all libraries, mounting the component and then waiting for the component to actually perform its work in response to the test's actions. But do those tests give you a true confidence that the component is working?
Try this test 🙈
Spoiler: it fails, proof.
const mock = jest.fn()
const { getByRole } = render(
<button style={{ pointerEvents: 'none' }} onClick={mock}>
text
</button>,
)
fireEvent.click(getByRole('button'))
expect(mock).not.toBeCalled()
Cypress test on the other hand fails correctly.
We think that using cypress-X-unit-test
runs tests as fast as your application code is, and often you need to think how to slow down the Cypress Test Runner so it does not run away from the component's code, just see our blog posts dealing with test flake.
From the developer's perspective I would ask myself: which tests do I write faster? What happens when a test fails and I need to debug the failure: which test runner allows me to debug a failed test quicker? While I am partial, I have to say, realistic Cypress tests are easier to write and debug.
Finally, when running tests on the continuous integration service, the true test speed up comes from properly configuring dependencies caching and running tests in parallel - something we have extensively documented and consider a solved problem.
Slow bundling
When you bundle spec file, you are now bundling React, Read DOM and other libraries, which is might be slow. For now, you can disable inline source maps by adding to your Webpack config settings (if available) the following:
const webpackOptions = {
devtool: false,
}
Keep your eye on issue #156 for more information.
Missing code coverage
If you are using your custom Webpack, this plugin might be missing code coverage information because the code was not instrumented. We try to insert the babel-plugin-istanbul
plugin automatically, but your bundling might not use Babel, or configure it differently, preventing plugin insertion. Please let us know by opening an issue with full reproducible details.
See related issue #141. You can also debug the plugin's behavior by running it with DEBUG
environment variable, see #debugging section.
Gatsby.js projects not supported
Currently, this project cannot find Webpack settings used by Gatsby.js, thus it cannot bundle specs and application code correctly. Keep an eye on #307
Context Provider usage
React context provider usage and API described in ./docs/providers-and-composition.md
Chat
We have a chat workspace at https://component-testing.slack.com/, you are welcome to join us.
Development
See docs/development.md
Debugging
You can see verbose logs from this plugin by running with environment variable
DEBUG=cypress-react-unit-test
Because finding and modifying Webpack settings while running this plugin is done by find-webpack module, you might want to enable its debug messages too.
DEBUG=cypress-react-unit-test,find-webpack
Since some objects might be deeply nested, if you see an object that is printed simply { module: { rules: [ [Object] ] }
you can increase the max printed depth
DEBUG=cypress-react-unit-test,find-webpack DEBUG_DEPTH=10
Migration guide
From v3 to v4
The old v3 main
branch is available as branch v3
- the
cy.mount
is now simply import { mount } from 'cypress-react-unit-test'
- the support file is simply
require('cypress-react-unit-test/support')
Related tools
Same feature for unit testing components from other frameworks using Cypress