Skip to content

itsdevdom/create-react-app-typescript-cypress-unit-integration-tests-setup

Repository files navigation

create-react-app-typescript-cypress-unit-integration-tests-setup

Running unit & integration tests with Cypress in a TypeScript React project based on create-react-app.




How to setup Cypress for unit & integration tests

This project is an example React application that uses Cypress Component Testing for the organization, writing and execution of unit / integration tests. You can clone it and play around with it (see Commands). The following sub-chapters explain how to setup Cypress Component Testing in a create-react-app project, including code coverage output and support for the Testing Library.


1. Update dependencies

First of all, we need a few new dependencies. In particular:

  • Cypress itself (cypress)
  • Compatibility with Create React App (@cypress/react, @cypress/webpack-dev-server, html-webpack-plugin)
  • Support for code coverage (@cypress/code-coverage, @cypress/instrument-cra)

Add all those dependencies to your package.json file, remove all Jest-related dependencies, and re-install them. For example:

  {
    "devDependencies": {
-     "@testing-library/jest-dom": "5.14.x",
-     "@testing-library/react": "12.0.x",
-     "@testing-library/user-event": "13.2.x",
-     "@types/jest": "26.0.x",
+     "@cypress/code-coverage": "3.9.x",
+     "@cypress/instrument-cra": "1.4.x",
+     "@cypress/react": "5.9.x",
+     "@cypress/webpack-dev-server": "1.5.x",
+     "cypress": "8.3.x",
+     "html-webpack-plugin": "4.5.x",
    }
  }

2. Remove Jest setup

You might find an ESLint configuration in your package.json file. If so, remove any Jest-related options from it. For example:

  "eslintConfig": {
    "extends": [
      "react-app",
-     "react-app/jest"
    ]
  },

In addition, the setupTests.ts file within the src folder is also no longer required and can be deleted. For example:

- // jest-dom adds custom jest matchers for asserting on DOM nodes.
- // allows you to do things like:
- // expect(element).toHaveTextContent(/react/i)
- // learn more: https://github.com/testing-library/jest-dom
- import '@testing-library/jest-dom';

3. Setup Cypress

3.1 Update scripts

First, let's change our test scripts to use Cypress instead of Jest. Within the root folder, update your package.json file:

  {
    "scripts": {
-     "test": "react-scripts test",
+     "test": "cypress run-ct"
+     "test:runner": "cypress open-ct"
    }
  }

In detail:

  • The test script executes all tests in headless mode - optimal for CI systems
  • The test:runner script opens up the Cypress Test Runner and let's you choose specific tests to run - perfect for local development and debugging

Note: Watching test files and re-executing tests only works with the test:runner script, and is enabeld by default (cypress#3665).

3.2 Configure TypeScript

Now, we want to enable type safety & type support for our Cypress tests. Within the root folder, extend your tsconfig.json file:

  {
    "compilerOptions": {
+     "types": ["cypress"]
    }
  }

3.3 Configure Cypress

First, we need to do some basic Cypress configuration, such as where to find unit / integration tests or how to run them.

Within the root folder, create a file named cypress.json and add the following content:

+ {
+   "testFiles": "**/*.test.{ts,tsx}",
+   "componentFolder": "src",
+   "video": false
+ }

Then, we need to configure Cypress to use the same dev server (Webpack) configuration that Create React App uses, and also to collect and save code coverage.

Within the folder cypress/plugins, create a file named index.ts and add the following content:

+ /// <reference types="cypress" />
+
+ import injectDevServer from '@cypress/react/plugins/react-scripts';
+ import installCoverageTask from '@cypress/code-coverage/task';
+ import '@cypress/instrument-cra';
+
+ const pluginConfig: Cypress.PluginConfig = (on, config) => {
+   if (config.testingType === 'component') {
+     injectDevServer(on, config);
+   }
+   installCoverageTask(on, config);
+   return config;
+ };
+
+ export default pluginConfig;

Within the folder cypress/support, create a file named index.ts and add the following content:

+ /// <reference types="cypress" />
+
+ import '@cypress/code-coverage/support'

3.4 Extend gitignore

Cypress has its own directory structure and output formats. Within your root folder, extend the .gitignore to exclude them:

  # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

  # dependencies
  /node_modules
  /.pnp
  .pnp.js

  # testing
  /coverage
+ /.nyc_output
+ cypress/results/*
+ cypress/reports/*
+ cypress/screenshots/*
+ cypress/videos/*

  # production
  /build

  # misc
  .DS_Store
  .env.local
  .env.development.local
  .env.test.local
  .env.production.local

  npm-debug.log*
  yarn-debug.log*
  yarn-error.log*

4. Rewrite tests (unit / integration)

Mounting test setups and asserting expectations works similarly between Cypress and Jest, but uses a different syntax. For example, the App.test.tsx requires the following changes:

- import { render, screen } from '@testing-library/react';
+ import { mount } from '@cypress/react'
  import App from './App';

- test('renders learn react link', () => {
+ it('renders learn react link', () => {
-   render(<App />);
+   mount(<App >);

-   const linkElement = screen.getByText(/learn react/i);
+   cy.get('a').should('exist');
  });




Bonus: How to use the Testing Library

The Testing Library is very popuplar within the React community, and these days is also available for various other frameworks and libraries - amongst them Cypress. The following sub-chapters explain how to set it all up.


1. Install dependencies

Add the dependency to your package.json file and install it. For example:

  {
    "devDependencies": {
+     "@testing-library/cypress": "8.0.x",
    }
  }

2. Configure Cypress

2.1 Configure TypeScript

Within the root folder, extend your tsconfig.json file:

  {
    "compilerOptions": {
-     "types": ["cypress"]
+     "types": ["cypress", "@testing-library/cypress"]
    }
  }

2.2. Configure Cypress

Within the folder cypress/support, open the index.ts file and add Testing Library commands:

  /// <reference types="cypress" />

  import '@cypress/code-coverage/support'
+ import '@testing-library/cypress/add-commands';

3. Rewrite tests (unit & integration)

You can now switch from the Cypress queries to Testing Library ones. For example, the App.test.tsx can now be changed the following way:

  import { screen } from '@testing-library/react';
  import { mount } from '@cypress/react'
  import App from './App';

  it('renders learn react link', () => {
    mount(<App >);

-   cy.get('a').should('exist');
+   cy.findByText(/learn react/i).should('exist');
  });




Commands

The following commands are available:

Command Description CI
npm start Creates a development build, running in watch mode
npm run build Creates a production build ✔️
npm run test Executes all unit tests ✔️
npm run test:runner Opens the test runner, allowing for specific unit test executions