A little helper to unit test React components in the open source Cypress.io E2E test runner ALPHA
-
What is this? This package allows you to use Cypress test runner to unit test your React components with zero effort.
-
How is this different from Enzyme? It is similar in functionality BUT runs the component in the real browser with full power of Cypress E2E test runner: live GUI, full API, screen recording, CI support, cross-platform.
- some DOM events are not working when running all tests at once #4
- cannot mock server XHR for injected components #5
- cannot spy on
window.alert#6
Requires Node version 8 or above.
npm install --save-dev cypress cypress-react-unit-testIf you need help configuring bundler, see preprocessors info
Include this plugin from cypress/support/index.js
import 'cypress-react-unit-test'This adds a new command cy.mount that can mount a React component. It also overloads cy.get to accept in addition to selectors React component, returning it. See examples below.
// load Cypress TypeScript definitions for IntelliSense /// <reference types="cypress" /> // import the component you want to test import { HelloState } from '../../src/hello-x.jsx' import React from 'react' describe('HelloState component', () => { it('works', () => { // mount the component under test cy.mount(<HelloState />) // start testing! cy.contains('Hello Spider-man!') // mounted component can be selected via its name, function, or JSX // e.g. '@HelloState', HelloState, or <HelloState /> cy.get(HelloState).invoke('setState', { name: 'React' }) cy.get(HelloState) .its('state') .should('deep.equal', { name: 'React' }) // check if GUI has rerendered cy.contains('Hello React!') }) })You can add individual style to the mounted component by passing its text as an option
it('can be passed as an option', () => { const style = ` .component-button { display: inline-flex; width: 25%; flex: 1 0 auto; } .component-button.orange button { background-color: #F5923E; color: white; } ` cy.mount(<Button name="Orange" orange />, { style }) cy.get('.orange button').should( 'have.css', 'background-color', 'rgb(245, 146, 62)', ) })Often your component rely on global CSS style imported from the root index.js or app.js file
// index.js import './styles.css' // bootstrap applicationYou can read the CSS file and pass it as style option yourself
cy.readFile('cypress/integration/Button.css').then(style => { cy.mount(<Button name="Orange" orange />, { style }) })You can even let Cypress read the file and inject the style
const cssFile = 'cypress/integration/Button.css' cy.mount(<Button name="Orange" orange />, { cssFile })See cypress/integration/inject-style-spec.js for more examples.
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" } } }How can we use features that require transpilation? By using @cypress/webpack-preprocessor - see the plugin configuration in cypress/plugins/index.js
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 } }If you are using Create-React-App v3 or react-scripts, and want to reuse the built in webpack before ejecting, this module ships with Cypress preprocessor in plugins folder. From the cypress.json point at the shipped plugin in the node_modules.
{ "pluginsFile": "node_modules/cypress-react-unit-test/plugins/cra-v3", "supportFile": "node_modules/cypress-react-unit-test/support" }See example repo bahmutov/try-cra-with-unit-test
If you already have a plugins file, you can use a file preprocessor that points at CRA's webpack
// your project's Cypress plugin file const craFilePreprocessor = require('cypress-react-unit-test/plugins/cra-v3/file-preprocessor') module.exports = on => { on('file:preprocessor', craFilePreprocessor()) }Bonus: re-using the config means if you create your application using create-react-app --typescript, then TypeScript transpile just works out of the box. See bahmutov/try-cra-app-typescript.
All components are in src folder. All tests are in cypress/integration folder.
- hello-world-spec.js - testing the simplest React component from hello-world.jsx
- hello-x-spec.js - testing React component with props and state hello-x.jsx
- counter-spec.js clicks on the component and confirms the result
- stateless-spec.js shows testing a stateless component from stateless.jsx
- transpiled-spec.js shows testing a component with class properties syntax from transpiled.jsx
- error-boundary-spec.js shows testing a component acting as an error boundary from error-boundary.jsx
- users-spec.js shows how to observe XHR requests, mock server responses for component users.jsx
- alert-spec.js shows how to spy on
window.alertcalls from your component stateless-alert.jsx
- bahmutov/calculator tests multiple components: calculator App, Button, Display.
To get started with this repo, compile the plugin's code and the examples code
npm run transpile npm run build npm run cy:open- run TypeScript compiler in watch mode with
npx tsc -w - run Cypress with
npx cypress openand select the spec you want to work with - edit
lib/index.tswhere all the magic happens
Uses Percy.io visual diffing service as a GitHub pull request check.
Same feature for unit testing components from other frameworks using Cypress
