Open helenzhou6 opened 6 years ago
You're probably not working on this anymore, but I just had to write a test for a time-based function at work so I thought I'd drop this in in case you hadn't seen it: https://facebook.github.io/jest/docs/en/timer-mocks.html
You can mock timers in Jest so you don't actually have to wait
Thanks buddy! I was trying to play with the jest faketimers and couldn't fully figure it out, but I will definitely get one done eventually!
I think you can do
jest.useFakeTimers();
jest.advanceTimersByTime(10000); // or however much time you need to have passed
and any timeouts etc in your code should have run.
I just spent a good while trying to use jest.useFakeTimers(); jest.advanceTimersByTime(10000);
and the methods listed here with no luck 😅
I found the article is testing a function that has a simple timer with a callback, and it tests whether the callback function has been called or not, which seems different to our function (where we just want certain things to run after a set time).
Okay I figured it out. The main problem was that apparently Jest's fake timers don't handle the Date object. Luckily it's quite easy to mock if you're just using Date.now()
.
So what we need to do is mock Date.now()
to return 0 the first time (so the component's start time is 0), then always return 10000 after that.
The second key is jest.runOnlyPendingTimers()
, which will run whatever timers are queued without allowing anymore to start. This seems to avoid a weird issue I was getting where the interval ran 10000 times and then Jest gave up.
So I think what's happening is:
Date.now()
is mockedDate.now()
gets called once and start time set to 0 in the componentsetInterval
in the componentjest.runOnlyPendingTimers()
lets the interval run onceDate.now()
returns 10000test('test TimeGame component win', () => {
jest.useFakeTimers(); // tell Jest to hijack JS timers
Date.now = jest
.fn() // create the mock function
.mockReturnValueOnce(0) // tell the mock to return 0 only the first time it's called
.mockReturnValue(10000); // tell it to return 10000 every other time
const { getByText, getByTestId } = renderIntoDocument(<TimeGame />);
const startButton = getByText('Start');
fireEvent.click(startButton);
jest.runOnlyPendingTimers(); // allow the created interval to run once
const stopButton = getByText('Stop');
fireEvent.click(stopButton);
const message = getByTestId('message');
expect(message.textContent).toEqual('WOW you got it spot on!');
});
That is absolutely awesome @oliverjam - and thanks for the explanation too 😍
Not sure if you managed to get round to it, but you can pass in
done()
as a callback in jest:(Thanks for this post)