6

I'm writing a Jest test for code that depends on a websocket library.

The websocket library is mocked. I want to send a message, wait for async actions to complete, and check the response.

it('sends a message and gets a response', () => {
  processor(ws).sendMessage()  // do a bunch of async stuff, call websocket.sendMessage()
  setTimeout(() => {
    expect(ws.getResponse()).toEqual('all done')
  }, 100)
})

Unfortunately because Jest mocks setTimeout, setTimeout fails. If I run jest.runAllTimers(), the timeout happens instantaneously, so fails to pick up the message.

Any idea how to convince jest to unmock setTimeout, or a Jasmine workaround?

Allyl Isocyanate
  • 13,306
  • 17
  • 79
  • 130

2 Answers2

10

You can add following code before test cases. It works for me in Jest v14.1.0 -

  jest.useRealTimers()
zc05
  • 126
  • 1
  • 4
0

You shouldn't wait during your test (using setTimeout). Instead, use waitFor which is designed for exactly this use case. It will keep running the test until it passes or a timeout is reached (default of 1 second). Write your test like this:

import {waitFor} from '@testing-library/react';

it('sends a message and gets a response', () => {
  processor(ws).sendMessage()`  // do a bunch of async stuff, call websocket.sendMessage()
  waitFor(() => {
    expect(ws.getResponse()).toEqual('all done');
  });
});

If by the end of the timeout the expect still doesn't pass, the test will fail. If the expect succeeds in just 0.01 seconds, the test won't take any longer to proceed.

lmat - Reinstate Monica
  • 7,289
  • 6
  • 48
  • 62