scenario

When writing unit tests for React projects using Jest, you encountered test scenarios such as clicking a button (see details) and then switching to a specified routing page (details page). Based on the idea of BDD, combined with Jest and React-testing -Library, this paper summarizes the writing ideas and problems of unit tests in this scenario.

// Component.tsx

import React from 'react'
import { useHistory } from 'react-router-dom'

const Component = () = > {
    const history = useHistory()
    const handleClick = (evt: React.MouseEvent) = > {
        history.push(`/pageDetails? id=The ${1}`)}return (
        <div>
            <button onClick={handleClick}>Check the details</button>
        </div>)}export default Component
Copy the code

Train of thought

Simulate the assertion after clicking a button by locating it to a button element

  • The function corresponding to the click event is called
  • The current route is the route after we specify the jumppathname
  • Routes carry parameters, for examplesearchIs the parameter of our simulation.
// component.test.js

import React from 'react'
import { render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event'
import {createMemoryHistory} from 'history'
import Component from './component'

describe('Test Component Page'.() = > {
  it('Click view Details button to jump to details page'.() = > {
      render(<Component />)
      const history = createMemoryHistory()
      
      // Position the element to simulate button clicking
      act(() = > {
        userEvent.click(screen.getByText('Details'))})/ / assertions
      expect(history.location.pathname).toBe("/pageDetails") // Assert to specify a route
      expect(history.location.search).toBe("? id=1") // Assertion takes parameters
  })
Copy the code

Problems encountered

  • When you run a written unit test directly, clicking the button invokes the function bound to our component’s real codehandleClick. Tests failExpected: "/pageDetails"; Received: "/".
  • The problem is that
    • createMemoryHistoryThe default path is retrieved at execution time/
  • The first option is to place the click-to-jump function in a unit test, creating a mock function and then running the test. Refer to the code below for implementation.
  • Plan two can also be usedRouterThe parcelComponentThe component,RouterthepropsThe incominghistoryAfter the simulation click, assert again. referencecreateMemoryHistory

Scheme one code implementation

// component.test.js

import React from 'react'
import { render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event'
import {createMemoryHistory} from 'history'
import Component from './component'

describe('Test Component Page'.() = > {
    it('Click view Details button to jump to details page'.() = > {
        render(<Component />)

        const history = createMemoryHistory()
        const clickHandler = jest.fn(evt= > { // Create a mock click event function
          evt.preventDefault()
          evt.stopPropagation()
          history.push('/pageDetails? id=1')
        })
        screen.getByText('View details').onclick = evt= > clickHandler(evt) // Bind the mock click event function to the button

        act(() = > {
          userEvent.click(screen.getByText('Details'))
        })

        expect(clickHandler).toHaveBeenCalled() // Assert that the click event is called
        expect(history.location.pathname).toBe("/pageDetails") // Assert to specify a route
        expect(history.location.search).toBe("? id=6") // Assertion takes parameters})})Copy the code

reference

createMemoryHistory