I'm writing tests for a React component. It's a timer that starts counting down when you press a button, then stops when you press the same button. I have a test case that tries to press the pause button, wait a second, then press the pause button again, checking the timer to make sure that a second has elapsed:
Timer.test.js
render(<Timer />)
const pauseButton = screen.getByText('pause')
const timerOutput = screen.getAllByRole('heading')[1]
describe('Timer', () => {
test('Timer starts counting down when unpaused', done => {
function fetchTime(callback) {
fireEvent.click(pauseButton)
setTimeout(
fireEvent.click(pauseButton),
1250
)
return callback(timerOutput)
}
function callback(data) {
try {
expect(data).toHaveTextContent('24:59')
done()
} catch(error) {
done(error)
}
}
fetchTime(callback)
})
})
The problem is, the test doesn't seem to be hitting click on pauseButton the way I want it to. Jest tells me in the terminal when I run my test that timerOutput turns out to be '25:00' rather than '24:59', and it seems as if the component failed the test. But this is a problem with the test, not the component; when I run the app in my browser and press the button myself, it works the way it should. How do I get this test to work properly, and hit the buttons the way I want it to?
It's difficult to have an accurate answer with few information about the component itself.
First I would recommend use
asyncarrow function insidetest()whenever you need to handle async calls so you don't rely in callback hell.Besides that, I would try to use
jest.useFakeTimers()so you can advance the setTimeout timer in order to test properly. It seems that your secondfireEvent.clicknever gets fired since the test checks it synchronously.And I just noticed you requested the
timerOutputat first but didn't request it after the click events.I would suggest something like:
Indeed, the expect statement would be better from a user perspective assertion, like:
Since you don't matter about the HTML elements that contains that text content