How to test components in React with Jest

Testing React components ensures your UI behaves correctly and prevents regressions when refactoring or adding new features. As the creator of CoreUI with over 12 years of React experience since 2014, I’ve built comprehensive test suites for production applications. Jest is a JavaScript testing framework that provides fast test execution, snapshot testing, and built-in mocking capabilities. This approach creates maintainable test suites that verify component behavior and output.

Use Jest to test React components with render tests, snapshot tests, and behavior assertions.

Install Jest:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom

Configure package.json:

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  },
  "jest": {
    "testEnvironment": "jsdom",
    "setupFilesAfterEnv": ["<rootDir>/jest.setup.js"]
  }
}

Create jest.setup.js:

import '@testing-library/jest-dom'

Example component:

// Button.jsx
export default function Button({ onClick, children, disabled = false, variant = 'primary' }) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`btn btn-${variant}`}
    >
      {children}
    </button>
  )
}

Test file:

// Button.test.jsx
import { render, screen } from '@testing-library/react'
import Button from './Button'

describe('Button', () => {
  it('renders with text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('applies variant class', () => {
    render(<Button variant='secondary'>Test</Button>)
    const button = screen.getByRole('button')
    expect(button).toHaveClass('btn-secondary')
  })

  it('handles disabled state', () => {
    render(<Button disabled>Disabled</Button>)
    expect(screen.getByRole('button')).toBeDisabled()
  })

  it('calls onClick handler', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click</Button>)
    screen.getByRole('button').click()
    expect(handleClick).toHaveBeenCalledTimes(1)
  })

  it('matches snapshot', () => {
    const { container } = render(<Button>Snapshot</Button>)
    expect(container.firstChild).toMatchSnapshot()
  })
})

Testing more complex components:

// UserCard.jsx
export default function UserCard({ user, onDelete }) {
  if (!user) return <div>No user data</div>

  return (
    <div className='user-card'>
      <img src={user.avatar} alt={user.name} />
      <h3>{user.name}</h3>
      <p>{user.email}</p>
      {onDelete && (
        <button onClick={() => onDelete(user.id)}>Delete</button>
      )}
    </div>
  )
}

// UserCard.test.jsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import UserCard from './UserCard'

describe('UserCard', () => {
  const mockUser = {
    id: 1,
    name: 'John Doe',
    email: '[email protected]',
    avatar: 'https://example.com/avatar.jpg'
  }

  it('renders user data', () => {
    render(<UserCard user={mockUser} />)
    expect(screen.getByText('John Doe')).toBeInTheDocument()
    expect(screen.getByText('[email protected]')).toBeInTheDocument()
    expect(screen.getByAltText('John Doe')).toHaveAttribute('src', mockUser.avatar)
  })

  it('shows message when no user', () => {
    render(<UserCard user={null} />)
    expect(screen.getByText('No user data')).toBeInTheDocument()
  })

  it('calls onDelete with user id', async () => {
    const handleDelete = jest.fn()
    render(<UserCard user={mockUser} onDelete={handleDelete} />)

    await userEvent.click(screen.getByText('Delete'))
    expect(handleDelete).toHaveBeenCalledWith(1)
  })

  it('hides delete button when no handler', () => {
    render(<UserCard user={mockUser} />)
    expect(screen.queryByText('Delete')).not.toBeInTheDocument()
  })
})

Best Practice Note

Jest with jsdom environment allows testing without a browser. Use describe blocks to group related tests. Test both rendering and behavior. Snapshot tests catch unexpected UI changes. Use jest.fn() for mock functions to verify they’re called correctly. Testing Library encourages testing how users interact with components. Run tests in watch mode during development for instant feedback. This is how we test CoreUI React components—comprehensive Jest suites covering rendering, props, user interactions, and edge cases for production-ready UI libraries.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author