DEV Community

Rajae Robinson
Rajae Robinson

Posted on • Originally published at bluesockets.com

React.js Vitest Unit Testing (Husky, lint-staged, ESLint, Prettier)

Creating a React application with Vite has become the preferred way over using create-react-app due to its faster and simpler development environment. However, unlike create-react-app, Vite doesn't come with the necessary packages for unit testing React applications out of the box.

In this guide, we will walk through setting up unit testing for a production-ready React + Typescript Vite application. We'll use the lightweight and fast Vitest testing framework along with the React Testing Library. Additionally, we'll configure linting and formatting using ESLint and Prettier to catch issues early. Lastly, we'll implement Husky and lint-staged to automatically run tests and linting on git commits before code is pushed. By the end, you'll have a robust testing setup to catch bugs, prevent regressions, and maintain code quality standards.

Assuming you already have your React Vite project set up (using npm create vite@latest), the first step is to install Vitest:

npm install -D vitest
Enter fullscreen mode Exit fullscreen mode

Then, update your package.json file with a test script:

"scripts": {
  "test": "vitest"
}
Enter fullscreen mode Exit fullscreen mode

Now, you can write your first test file, for example, src/components/Example/Example.test.ts:

import { describe, expect, it } from 'vitest';

describe('Example', () => {
 it('adds 1 + 2 to equal 3', () => {
   expect(1 + 2).toBe(3);
 });
});
Enter fullscreen mode Exit fullscreen mode

Run the tests with:

npm run test
Enter fullscreen mode Exit fullscreen mode

Vitest will automatically detect and run the tests, providing a fast and straightforward starting point for testing React applications.

Setting up Vitest with React Testing Library

To test the UI of your React components, you need to interact with the DOM. Here, React Testing Library comes into play. Install the required packages:

npm i -D jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
Enter fullscreen mode Exit fullscreen mode

Update your Vite configuration file (vite.config.ts):

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    css: true,
  },
});
Enter fullscreen mode Exit fullscreen mode

Create the setup file specified in the configuration (src/test/setup.ts):

import '@testing-library/jest-dom';
Enter fullscreen mode Exit fullscreen mode

Now, you can test the UI of your React application. For example:

import { test } from 'vitest';
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders welcome message', () => {
 render(<App />);
 expect(screen.getByText('Learn React')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

Creating a Custom Render for App Providers

If your React application uses the Context API and relies on providers, it's efficient to create a custom render function with the necessary providers. Create a file utils/test-utils.tsx:

import { cleanup, render } from '@testing-library/react';
import { afterEach } from 'vitest';

afterEach(() => {
 cleanup();
});

const AppProviders = ({ children }: { children: React.ReactNode }) => {
 return (
   <ThemeProvider theme="light">
     {children}
   </ThemeProvider>
 );
}

function customRender(ui: React.ReactElement, options = {}) {
 return render(ui, {
   wrapper: AppProviders,
   ...options,
 });
}

export * from '@testing-library/react';
export { default as userEvent } from '@testing-library/user-event';
export { customRender as render };
Enter fullscreen mode Exit fullscreen mode

Now, use this custom render function in your tests when necessary.

Configuring ESLint and Prettier

For maintaining code quality and consistency, use ESLint for linting and Prettier for formatting. If not already installed, add the necessary packages:

npm install eslint-plugin-react --save-dev
npm install --save-dev --save-exact prettier
npm install -D eslint-config-prettier
Enter fullscreen mode Exit fullscreen mode

Update your ESLint config file:

module.exports = {
 extends: [
   'eslint:recommended',
   'plugin:@typescript-eslint/recommended',
   'plugin:react-hooks/recommended',
   'plugin:react/recommended',
   'plugin:react/jsx-runtime',
   'eslint-config-prettier',
 ],
 //...
};
Enter fullscreen mode Exit fullscreen mode

Create a Prettier configuration file (.prettierrc):

{
 "semi": true,
 "singleQuote": true
}
Enter fullscreen mode Exit fullscreen mode

Now, ESLint, Prettier, and tests will automatically run before any commits, ensuring code quality and consistency.

Setting Up Husky and lint-staged

To automate ESLint, Prettier, and testing on commits, use Husky and lint-staged. Install them:

npm install --save-dev husky lint-staged
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
Enter fullscreen mode Exit fullscreen mode

Update your package.json with lint-staged configurations:

{
 "scripts": {
   "test:staged": "vitest --run"
 },
 "lint-staged": {
   "**/*.{js,jsx,ts,tsx}": [
     "npm run lint",
     "prettier --write --ignore-unknown",
     "npm run test:staged"
   ]
 }
}
Enter fullscreen mode Exit fullscreen mode

Now, ESLint, Prettier, and tests will run automatically before commits, ensuring that issues are caught early.

Conclusion

Setting up Vitest, ESLint, Prettier, Husky, and lint-staged provides a solid foundation for unit testing React apps. For more details, refer to the complete blog post on BlueSockets.

Top comments (0)