Unit testing React components in Cypress without CRA and react-scripts

So you have an app or component library that you have created without create-react-app and you want to unit test it using Cypress. I had to go through some hassle to get that working with a custom webpack configuration, but it’s finally working, and here is my solution.

npm install --save-dev cypress @cypress/react

Additional installation instructions can be found here.

{
"testFiles": "**/*.spec.js",
"experimentalComponentTesting": true,
"componentFolder": "./src",
"nodeVersion": "system",
"env": {
"webpackFilename": "./webpack.tests.config.js"
}
}
  • testFiles specifies a pattern for files that contain your tests
  • experimentalComponentTesting enables unit testing support. Though it says experimental, it’s quite stable now
  • componentFolder is akin integrationFolder and specifies where your unit and integration tests reside. You could keep your unit tests inside your ./src folder and have one to one mapping to your components, i.e. src/Button/Button.js and src/Button/Button.spec.js
  • nodeVersion tells Cypress to use the node version of the system it runs on, and not use the bundled version. This might be necessary if you are using node-sass and other binaries that are platform specific.
  • env.webpackFilename specifies the localtion of the webpack config you want to use for your tests. Cypress will transpile your components on the fly, hence you may need to have a different configuration that what you use to build your project. Think Storybook.

All the configuration options are defined here.

Update ./cypress/support/index.js and import directives needed for Cypress to mount your unit tests into the Cypress DOM.

// ./cypress/support/index.jsimport '@cypress/react/support';

Update ./cypress/plugins/index.js and tell Cypress how to process your test files.

// ./cypress/plugins/index.jsmodule.exports = (on, config) => {
require('@cypress/react/plugins/load-webpack')(on, config);
return config;
};

load-webpack plugin will transpile your components files during testing using webpack config you have specified in env.webpackFilename .

// ./src/Button.spec.jsimport React from 'react';
import Button from './Button';
import { mount } from '@cypress/react';
describe('Button', () => {
it('should handle onClick', () => {
const onClick = cy.stub().as('onClick');

mount(
<Button onClick={onClick}>Click me</Button>,
);

cy.findByRole('button', { name: 'Click me' }).click();

cy.get('@onClick').should('have.been.calledOnce');
});
});

You can now run your tests with ./node_modules/.bin/cypress open or ./node_modules/.bin/cypress run .

Running components tests in an actual DOM boosts confidence in the reliability of your tests. You can run them in multiple browsers. You can create functional tests combining multiple components together to see how they interact with each other, how user interacts with them using the mouse and the keyboard, and you can stub your dependencies to avoid complex cy.intercept definitions.

And added bonus, is that Cypress automatically generates test coverage reports, so you don’t have to instrument anything.

Full-stack developer, passionate about front-end frameworks, design systems and UX.