question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Response not returned if using `jest.useFakeTimers()`

See original GitHub issue

Environment

Name Version
msw 0.21.3
node 12
OS Linux / OSX

Request handlers

import { setupServer } from 'msw/node'
import { rest } from 'msw'

const server = setupServer(
    rest.post(
        '/api/test',
        async (req, res, ctx) => res(
            ctx.json({ test: 'hello' })
        ),
    ),
);

server.listen()

Actual request

const res = await fetch("/api/test", {
      method: "POST",
      body: JSON.stringify({}),
});
const obj = await res.json();
expect(obj).toMatchInlineSnapshot(`
    Object {
        "test": "hello",
    }
`);

Current behavior

Using jest.useFakeTimers() the response is not returned by the server provided by msw.

The handler is called correctly, but the response hangs.

Expected behavior

Use jest.useFakeTimers() into some tests without affecting msw.

Screenshots

> jest

 FAIL  src/example.test.js (5.762 s)
  SOAP Utils
    ✕ Test (5012 ms)

  ● SOAP Utils › Test

    : Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error:

      1 | describe("SOAP Utils", () => {
    > 2 |   test(`Test`, async () => {
        |   ^
      3 |     const res = await fetch("/api/test", {
      4 |       method: "POST",
      5 |       body: JSON.stringify({}),

      at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (src/example.test.js:2:3)
      at Object.<anonymous> (src/example.test.js:1:1)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 handlers.js |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   1 passed, 1 total
Time:        6.267 s
Ran all test suites.

Here You can find a repository to reproduce the issue: https://github.com/bud-mo/msw-example

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
kettanaitocommented, Nov 7, 2020

If you swap whatwg-fetch with another request issuing library you can see the test passing, although still using fake timers and MSW. Here’s your test using native http module to make a request (no setTimeout calls):

import http from 'http'

test(`Test`, (done) => {
  let resBody = ''

  // Resolving against the current location, because relative URLs don't exist in NodeJS.
  const req = http.request(new URL('/api/test', location.href), {
    method: 'POST',
  })

  req.on('response', (res) => {
    res.on('data', (chunk) => (resBody += chunk))
    res.on('end', () => {
      const resBodyObject = JSON.parse(resBody)
      expect(resBodyObject).toMatchInlineSnapshot(`
      Object {
        "test": "hello",
      }
    `)

      done()
    })
  })

  req.write(JSON.stringify({}))
  req.end()
})

Suggestions

I don’t think this is the issue with MSW. I suggest you to:

  • Raise the issue in the whatwg-fetch or jest repositories, the problem lies in fake timers + fetch polyfill + (potentially) async/await syntax.
  • Replace whatwg-fetch polyfill with a compatible implementation that doesn’t rely on setTimeout.
  • Figure out how to progress whatwg-fetch timers when using fake timers in Jest.

I’m always willing to reopen the issue if we find sufficient proof it’s MSW problem.

1reaction
bud-mocommented, Nov 9, 2020

@kettanaito I ended up using node-fetch.

In my case is easy to use because I am wrapping the fetch to inject some auth headers to each request, so I have mocked that function to use the fetch provided by node-fetch, I only need to add the new URL('/api/test', location.href) line and it works great.

For documentation purpose I think we can provide an example with a simple fetch wrapper around node-fetch.

I created a branch with an updated working example with a possible solution, this patch can be a starting point: https://github.com/bud-mo/msw-example/commit/b4ba10f1fcbed65b6acf314b8a7a3fda92ee2792

Read more comments on GitHub >

github_iconTop Results From Across the Web

useFakeTimers not working in jest/testing-library
I'm rendering an element that makes use ...
Read more >
Timer Mocks
useFakeTimers() . This is replacing the original implementation of setTimeout() and other timer functions. Timers can be restored to their ...
Read more >
API Reference
When a test function returns a promise, the runner will wait until it is ... You cannot use this syntax, when using Vitest...
Read more >
React Testing Library and the “not wrapped in act” Errors
With react-testing-libraryit("should render and update a counter", () => { ... When its response comes back, setPerson will be invoked, but at this...
Read more >
Testing Recipes
This page assumes you're using Jest as a test runner. If you use a different test runner, ... The rest of these examples...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found