Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing with setTimeout #9

Open
helenzhou6 opened this issue May 24, 2018 · 6 comments
Open

Testing with setTimeout #9

helenzhou6 opened this issue May 24, 2018 · 6 comments
Assignees

Comments

@helenzhou6
Copy link
Contributor

Not sure if you managed to get round to it, but you can pass in done() as a callback in jest:

it('mock setTimeout test', (done) => {
  setTimeout(() => {
    console.log('TIME IS UP');
    done();
  }, 1000);
});

(Thanks for this post)

iPhatty added a commit that referenced this issue May 24, 2018
@iPhatty iPhatty self-assigned this May 25, 2018
@oliverjam
Copy link

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

@iPhatty
Copy link
Collaborator

iPhatty commented May 31, 2018

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!

@oliverjam
Copy link

oliverjam commented May 31, 2018

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.

@helenzhou6
Copy link
Contributor Author

helenzhou6 commented Jun 2, 2018

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).

jest.setTimeout(11000);
setTimeout(() => {
const stopButton = getByText('Stop');
fireEvent.click(stopButton);
const message = getByTestId('message')
expect(message.textContent).toEqual("WOW you got it spot on!")
done();
}, 10000)

@oliverjam
Copy link

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:

  1. Jest hijacks the timers
  2. Date.now() is mocked
  3. Start button is clicked
  4. Date.now() gets called once and start time set to 0 in the component
  5. Timer is created with setInterval in the component
  6. jest.runOnlyPendingTimers() lets the interval run once
  7. Date.now() returns 10000
  8. Stop button is clicked
  9. Component's render method sees newTime is 10000
  10. Success 🎉
test('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!');
});

@helenzhou6
Copy link
Contributor Author

That is absolutely awesome @oliverjam - and thanks for the explanation too 😍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants