DEV Community

Cover image for Testing a React Application with Vitest and React Testing Library
Manjush
Manjush

Posted on

Testing a React Application with Vitest and React Testing Library

This guide covers how to set up testing for a React application using Vitest, focusing on building an accordion component and applying Test Driven Development (TDD) principles. We will be using default counter app provided by vite.

We are going to configure vitest and implement test cases. I will be using pnpm as package manager for this but you can use yarn or npm as well.
Here are some test cases we are going to write for App (Counter App) component using React Testing Library and Vitest:

  1. Ensure the logos are rendered correctly with the correct links.
  2. Ensure the initial count is displayed correctly.
  3. Ensure the count increments when the button is clicked.
  4. Ensure the text content is displayed correctly.

Initializing the React Project

We can initialize the vite project using the following commands and fill in project details:

## For pnpm:
pnpm create vite

# For NPM
npm create vite@latest 

## For yarn 
yarn create vite

cd <YOUR_PROJECT_NAME>
pnpm install
Enter fullscreen mode Exit fullscreen mode

This should have your project setup. You can run project and access it locally.

Adding dependencies for Testing:

Install Vitest, jsdom and @testing-library/react as a development dependencies:

pnpm install -D vitest jsdom @testing-library/react
Enter fullscreen mode Exit fullscreen mode

Updating Configurations:

Setup setupTests file:

Create a test setup file at setupTests.ts in the tests folder of your project or in the src directory, whichever you prefer. Implement it as follows:

import { afterEach } from 'vitest'
import { cleanup } from '@testing-library/react'
import '@testing-library/jest-dom/vitest'

afterEach(() => {
  cleanup();
})
Enter fullscreen mode Exit fullscreen mode

Updating vite.config.ts:

One advantage of Vitest is its use of the same configuration as Vite. This alignment ensures that the test environment mirrors the build environment, enhancing the reliability of the tests.

We will update the configuration to the following code to include js-dom, which facilitates testing:

test: {
    globals: true,
    environment: 'jsdom',

    setupFiles: './src/tests/setupTests.ts',
  }
Enter fullscreen mode Exit fullscreen mode

So final vite config will look something like this:

/// <reference types="vitest" />
/// <reference types="vite/client" />

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',

    setupFiles: './src/tests/setupTests.ts',
  },
})
Enter fullscreen mode Exit fullscreen mode

Add the Test Script:

We need to add the vitest command to the package.json to start the testing script.

"scripts": {
    // ...rest of scripts
    "test": "vitest"
  },
Enter fullscreen mode Exit fullscreen mode

once this is done, we can implement test cases for our component.

Writing Tests for the Counter App:

Create App.test.tsx in tests folder with following contents:

import { describe, it, expect } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import App from '../App'

describe('App component', () => {
  it('renders Vite and React logos with correct links', () => {
    render(<App />)

    const viteLogo = screen.getByRole('img', { name: /Vite logo/i });
    const reactLogo = screen.getByAltText('React logo')

    expect(viteLogo).toBeInTheDocument()
    expect(reactLogo).toBeInTheDocument()

    expect(viteLogo.closest('a')).toHaveAttribute('href', 'https://vitejs.dev')
    expect(reactLogo.closest('a')).toHaveAttribute('href', 'https://react.dev')
  })

  it('renders the initial count correctly', () => {
    render(<App />)
    const button = screen.getByRole('button', { name: /count is 0/i })
    expect(button).toBeInTheDocument()
  })

  it('increments count when button is clicked', () => {
    render(<App />)
    const button = screen.getByRole('button', { name: /count is 0/i })
    fireEvent.click(button)
    expect(button).toHaveTextContent('count is 1')
  })

  it('renders text content correctly', () => {
    render(<App />)

    const title = screen.getByText('Vite \+ React')
    const editText = screen.getByText((content, _) => content.includes('Edit') && content.includes('save to test HMR'))
    const docsText = screen.getByText('Click on the Vite and React logos to learn more')

    expect(title).toBeInTheDocument()
    expect(editText).toBeInTheDocument()
    expect(docsText).toBeInTheDocument()
  })
})
Enter fullscreen mode Exit fullscreen mode

Running Tests:

You can run tests by running:

pnpm run test
Enter fullscreen mode Exit fullscreen mode

From the code example provided, we have demonstrated how Vitest integrates seamlessly with the React Testing Library. As previously mentioned, these libraries work in harmony: Vitest facilitates the creation of test suites, test cases, and test execution, while the React Testing Library enables thorough testing of React components by simulating user interactions with our application.

You can access full project here:
GitHub

Top comments (0)