Next.js Testing with Jest and Testing Library (working note)

Anh-Thi Dinh
draft
⚠️
This is a quick & dirty draft, for me only!

References

Basic

You should find your elements in the test the same way users will find them! For example, testing-library doesn’t have getById for an input because users don’t care about an id of an element, they find that element by its placeholder text instead.
Use data-testid and .getByTestId().
1// .tsx
2<input
3  data-testid="ulid-input"
4/>
1// .test.tsx
2const input = screen.getByTestId('ulid-input')

Watch test only 1 file

yarn test (jest --watch in package.json) then press p to filter based on file name regex.

Expect to be / not to be in document

  • Expect not to be in the documentqueryBy instead of findBy because queryBy returns a null (no error) whereas findBy throws an error instead!
    • 1const nameInput = screen.queryByPlaceholderText('Enter name...')
      2expect(nameInput).not.toBeInTheDocument()
  • Expect to be in the docyment → can use either queryBy or findBy!

Find an element

  • Find an image → getByAltText
  • Find an input
    • 1<label htmlFor="abc">Text Input</label>
      2<input id="abc" ... />
      1import {screen} from '@testing-library/dom'
      2const inputNode = screen.getByLabelText('Text Input')
  • Dropdown options → check this SO.
    • Idea: Add data-testid to options, then get the options by getAllByTestId, then check the sected option.
      • 1<option data-testid="select-option" key={item.key} value={item.key}>
        2  {item.label}
        3</option>
        4
        5// in test
        6// 
        7const options = getAllByTestId(container, 'select-option')
        8expect(options[0].selected).toBeFalsy();
        9expect(options[1].selected).toBeTruthy();
    • Can use getByDisplayValue for selected option.

Mocking

Mocking fetch

1global.fetch = jest.fn()
2
3it('...', async () => {
4	jest.spyOn(global, 'fetch').mockImplementation(() =>
5    Promise.resolve({
6      status: 401,
7      json: () => Promise.resolve({ message: 'Invalid API key' })
8    } as Response)
9  )
10})
 

Mocking an external library

1// main
2import {
3  NIL as NIL_UUID,
4  validate as uuidValidate,
5  v1 as uuidv1,
6  v3 as uuidv3,
7  v4 as uuidv4,
8  v5 as uuidv5
9} from 'uuid'
1// globally
2jest.mock('uuid', () => ({
3  NIL: '00000000-0000-0000-0000-000000000000',
4  validate: jest.fn(),
5  v1: jest.fn().mockReturnValue('b1d82820-866b-11ee-b7d9-7f085416ca4d'),
6  v3: jest.fn().mockReturnValue('c87ee674-4ddc-3efe-a74e-dfe25da5d7b3'),
7  v4: jest.fn().mockReturnValue('4dc3ae1d-a39e-49f3-b73e-e0cf2e3ca6ce'),
8  v5: jest.fn().mockReturnValue('4ebd0208-8328-5d69-8c44-ec50939c0967')
9}))
1// locally
2import uuid from 'uuid'
3
4jest.mock('uuid', () => ({
5  NIL: '00000000-0000-0000-0000-000000000000',
6  validate: jest.fn(),
7  v1: jest.fn(),
8  v3: jest.fn(),
9  v4: jest.fn(),
10  v5: jest.fn()
11}))
12
13it('....', () => {
14	jest.spyOn(uuid, 'validate').mockReturnValueOnce(false)
15})

Troubleshooting