Search code examples
javascriptreactjsjestjscreate-react-app

jest.runAllTimers() throws TypeError


I'm trying to run the following test using the built-in react-scripts test script in create-react-app:

Timer.test.js

render(<Timer />)
const pauseButton = screen.getByText('pause')
const timerOutput = screen.getAllByRole('heading')[1]

describe('Timer', () => {
  test('renders Timer component', () => {
    expect(screen.getByText(/session/i)).toBeInTheDocument()
    expect(screen.getByText(/25/)).toBeInTheDocument()
  })

  test('counts down when unpaused', async () => {
    jest.useFakeTimers()
    fireEvent.click(pauseButton)
    setTimeout(
      fireEvent.click(pauseButton),
      1125
    )
    jest.runAllTimers()
    expect(timerOutput).toHaveTextContent('24:59')
  })
})

Jest seems to be working fine until it gets to jest.runAllTimers(), when I get the following error:

 TypeError: callback.apply is not a function

      23 |       1125
      24 |     )
    > 25 |     jest.runAllTimers()
         |          ^
      26 |     expect(timerOutput).toHaveTextContent('24:59')
      27 |   })
      28 | 

      at node_modules/@jest/fake-timers/build/jestFakeTimers.js:524:25
      at callback (node_modules/@jest/fake-timers/build/jestFakeTimers.js:516:29)
      at FakeTimers._runTimerHandle (node_modules/@jest/fake-timers/build/jestFakeTimers.js:560:9)
      at FakeTimers.runAllTimers (node_modules/@jest/fake-timers/build/jestFakeTimers.js:193:12)
      at Object.<anonymous> (src/features/Timer.test.js:25:10)

I have no idea what's going on. Why won't it finish running the test?


Solution

  • The error you're getting is probably because of setTimeout usage. setTimeout accepts a function as first argument but you are giving it whatever the return type of fireEvent.click(pauseButton). Change the code to:

    test('counts down when unpaused', async () => {
        jest.useFakeTimers();
        fireEvent.click(pauseButton)
        setTimeout(() =>  fireEvent.click(pauseButton), 1125);
                // ^ NOTE HERE
        jest.runAllTimers();
        expect(timerOutput).toHaveTextContent('24:59');
      })