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

ReferenceError: fetch is not defined #686

Closed
onimougwo opened this issue Apr 8, 2021 · 22 comments
Closed

ReferenceError: fetch is not defined #686

onimougwo opened this issue Apr 8, 2021 · 22 comments
Labels
bug Something isn't working scope:node Related to MSW running in Node

Comments

@onimougwo
Copy link

onimougwo commented Apr 8, 2021

Environment

| msw | 0.28.1 |

Request handlers

I'm currently using msw to mock fetch in my jest test. The component uses the default javascript fetch and works fine with that.

When I run the test without adding node-fetch to my component, the test fails : ReferenceError: fetch is not defined
When I run the test with "const fetch = require("node-fetch");" in my component file, the test works fine (but the component breaks when it's rendered in a browser so it can't be a solution for me)

Also, I noticed that if I don't use node-fetch but I install jest-fetch-mock and I disable it (to still use MSW), then things work
require('jest-fetch-mock').enableMocks() fetchMock.dontMock()

Without node-fetch or jest-fetch-mock it says fetch is not defined (but the component works fine with the javascript fetch)

I'm so confused, installing but not using jest-fetch-mock make the error go away and why do I need all this, why can't I mock the window.fetch with msw ?

@onimougwo onimougwo added bug Something isn't working scope:node Related to MSW running in Node labels Apr 8, 2021
@msutkowski
Copy link
Member

Hey @onimougwo,

This is a configuration issue. You need to include a fetch polyfill (like node-fetch as you mention) in your setupTests file and not in the component. You should just be able to require('node-fetch') or import it, whichever syntax you're using, and things will just work.

@kettanaito
Copy link
Member

kettanaito commented Apr 8, 2021

The first thing to understand is that fetch is a browser-specific API and doesn't exist in Node.js. Jest tests run in Node.js, although they execute your components that may use window.fetch. How this works usually is testing environment polyfills fetch for you (i.e. with node-fetch, whatwg-fetch, or any other compatible polyfills). Most of the frameworks like CRA come with that polyfill built-in, so you rarely pay attention that you need it.

The solution to your issue is to include a suitable fetch polyfill in your testing setup (just as @msutkowski has pointed out).

The other part is this question:

I'm so confused, installing but not using jest-fetch-mock make the error go away and why do I need all this, why can't I mock the window.fetch with msw ?

It'd be much more straightforward to understand and debug any potential MSW issues when you realize it's request client-agnostic. MSW doesn't have any fetch-related logic and doesn't rely on fetch in any way. Seeing errors like "fetch is not defined" may hint to you that it's not a library's problem.

It's the core philosophy and one of the main benefits of MSW: you forget about mocking fetch/axios/etc. Departing from that mentally is also helpful to keep your tests clean and debugging easier.

@pqr
Copy link

pqr commented May 19, 2021

Hey @onimougwo,

This is a configuration issue. You need to include a fetch polyfill (like node-fetch as you mention) in your setupTests file and not in the component. You should just be able to require('node-fetch') or import it, whichever syntax you're using, and things will just work.

I've tried to import node-fetch in setupTests, but my React component still throws an error "ReferenceError: fetch is not defined" when I run tests under node environment.

Not clear how to define fake fetch function globally?

I red all MSW documentation and all examples in repository and did not manage to find example how to test React components (which uses fetch internally) with Jest and MSW .

For example, let's look on this part of documentation "Getting Started -> Integrate -> Node" - https://mswjs.io/docs/getting-started/integrate/node - fetch not mentioned there. I thought that MSW provides some fake fetch automatically, looks like it's not the case. I'm stumped.

I red brilliant article https://kentcdodds.com/blog/stop-mocking-fetch with headline "Stop mocking fetch" and irony is that after I did step by step all code examples in this article I got "ReferenceError: fetch is not defined" - so to stop mocking fetch I do need to mock fetch? I'am completely lost.

Do you have any open-source example how to test React components (which uses fetch internally) with Jest and MSW?

@kettanaito
Copy link
Member

Hey, @pqr. I'm sorry to hear you're having trouble setting up your tests.

You don't find fetch mentions in our docs because this isn't the library's responsibility. You need to polyfill fetch yourself. The problem is that you rarely realize you do, as some tools (like Create React App) do that for you, making you think fetch is automagically available in tests.

In reality, your React component gets rendered in Node.js when you run Jest, and fetch doesn't exist in Node.js—that's the whole reason to polyfill it. I know our examples don't mention this test setup either, but you need to forgive us on this: we write examples that use common tech (such as CRA) and are easy to get started with.

I've added a new usage example that will help you set up Jest and MSW:

@pqr
Copy link

pqr commented May 20, 2021

@kettanaito now I catch the idea! Thank you for complete example without CRA, it has really helped me to figure out the point of fetch polyfill now.

@kettanaito
Copy link
Member

Setting up things is far from easy. I'm glad that there's at least one example of how you can do that. Hope it helps.

@onimougwo
Copy link
Author

Thank you so much @kettanaito

@misha-erm
Copy link

Hey @onimougwo,

This is a configuration issue. You need to include a fetch polyfill (like node-fetch as you mention) in your setupTests file and not in the component. You should just be able to require('node-fetch') or import it, whichever syntax you're using, and things will just work.

@msutkowski I spent a whole day trying to set it up but no success so far. node-fetch requires absolute urls instead of relative ones so it's not possible to just drop it in if you have some tests running in 'jest-environment: node'.

We have a couple of such tests. They use fetch-mock and node environment to not bring the overhead of jsdom. I want to migrate them to msw but can't figure out how

Are you aware of any workarounds for this? Thanks in advance and sorry for posting in a closed issue

@kettanaito
Copy link
Member

Hey, @MikeYermolayev.

Take a look at this Jest + MSW example that uses the most minimal Jest setup there can be. It uses whatwg-fetch as the fetch polyfill. Take a look at how it's written, compare it with your test configuration. Let us know if you need any assistance, we'd be happy to help given a reproduction repository.

@misha-erm
Copy link

@kettanaito yes, I've studied this example. The problem is that I've tried to put tests which use browser API in jest-environment: node. And whatwg-fetch works only for jsdom environment.

I guess the only options are:

  1. use jsdom environment with whatwg-fetch
  2. use fetch-mock in tests that are run in node environment
  3. maybe I can also add XMLHttpRequest polyfill (required by whatwg-fetch) but haven't tried this

As for now I simply switched to jsdom. There were not so many tests with mocks so it won't have a big impact on tests performance

@kettanaito
Copy link
Member

The fact that you mention fetch-mock and XHR polyfill suggests you may not be using MSW correctly. Note that you don't need any mocks and polyfills when working with MSW—that's the whole point of adopting it. Using them may produce all sorts of unexpected results because you are, effectively, mocking modules on top of MSW interception. Make sure you don't do that.

node-fetch requires absolute urls instead of relative ones

That's absolutely correct: nothing to be relative to in Node.js. Relative URLs exist in a browser, where they are relative to the current location. You'd never put a browser code in a Node.js testing environment. Perhaps what you're trying to test shouldn't be tested in that environment?

@misha-erm
Copy link

I'm mentioning fetch-mock because I was migrating from it to mswjs.

Previously we had some test files which were run under node environment with fetch-mock. I assume node environment was used for performance reasons.

So after migrating to mswjs I tried to keep node environment but now I understand that it's probably a wrong way to use node environments for tests which use browser APIs like fetch

eplq added a commit to eplq/cryptoprices that referenced this issue Aug 13, 2022
es complejo hacer funcionar msw y whatwg-fetch (porque node no tiene fetch) debido a que son paquetes preparados
para funcionar con commonjs y no con esm, supongo que por la naturaleza de node, que no ha implementado esm hasta
hace pocas versiones.

de todas formas, lo que me ha dado la clave para hacerlo funcionar han sido dos factores:

 - el primero es haber encontrado [este hilo](mswjs/msw#686 (comment))
 - y el segundo ha sido haber sido notificado por el propio vitest o jest (no estoy seguro), indicándome como hacerlo, mírese el archivo vitest.config.ts (11-15)
@abdofola
Copy link

@kettanaito I was stuck for a whole day facing the same issue with fetch, cause I was under the impression msw mocks fetch. thanks for the clarification.

@kettanaito
Copy link
Member

Hi, @abdofola. No, MSW never stated to mock any request-issuing clients. In fact, not doing so is one of the things that sets MSW apart from the alternatives. But even with those, you must ensure your test environment can run your code, which often means polyfilling fetch or other modules your code depends on.

@tmerlet
Copy link

tmerlet commented Jan 30, 2023

kettanaito
Since the fetch api is available on the global scope now, how does this impact the above? I'm trying to use fetch in a component but getting [ReferenceError: fetch is not defined]. thanks 🙏

https://dev.to/cloudx/nodejs-18-fetch-api-test-runner-module-and-more-2ckg

@kettanaito
Copy link
Member

@tmerlet, the global fetch will make things much easier but MSW doesn't support it yet. The functionality is implemented and we're planning on releasing it sometime soon.

@VadimZP
Copy link

VadimZP commented Apr 29, 2023

@kettanaito thank you so much for your example with whatwg-fetch. This approached fixed my problem with ReferenceError: fetch is not defined too.

But before I tried to use node-fetch like this and it didn't do the trick:

import nextJest from "next/jest.js";
import 'whatwg-fetch'

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: "./",
});

// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const config = {
  // Add more setup options before each test is run
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  setupFilesAfterEnv: ["./jest.setup.ts"],
  testEnvironment: "jest-environment-jsdom",
  globals: {
    fetch,
  },
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config);

@EarthlingDavey
Copy link

@VadimZP thank you!

Adding only globals: { fetch } to jest config worked here!

@Nargonath
Copy link

By the way for people still coming here, starting from node@18 fetch is baked into node so you don't need a polyfill anymore, see: https://developer.mozilla.org/en-US/docs/Web/API/fetch#browser_compatibility.

My problem was that it was working locally on my machine (running node@18.17.0) but it didn't work in the CI. I figured node was shipped with the open-jdk image which had node@16 hence fetch was not defined. Upgrading the image to one with node@18 fixed the fetch is not defined error for me.

@kettanaito
Copy link
Member

@Nargonath, unfortunately, when using Jest, people still have to explicitly map fetch and other Fetch API classes manually in the globals option in jest.config.js. That's just how Jest works.

@Nargonath
Copy link

Alright thanks @kettanaito for the clarification. I'm using vitest so I didn't face this issue. The presence of fetch from node@18 environment was enough in that case.

But they don't a polyfill anymore, do they? They just need to add the config to jest as you mentioned, don't they?

@devjona
Copy link

devjona commented Mar 2, 2024

Hey, @MikeYermolayev.

Take a look at this Jest + MSW example that uses the most minimal Jest setup there can be. It uses whatwg-fetch as the fetch polyfill. Take a look at how it's written, compare it with your test configuration. Let us know if you need any assistance, we'd be happy to help given a reproduction repository.

This solved it for me. It was a combination of needing to use msw v 1.x, (finding the older docs) and using whatwq as opposed to node-fetch.

Thanks! The server for Jest tests (React pinging a Rails API) works wonderfully!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working scope:node Related to MSW running in Node
Projects
None yet
Development

No branches or pull requests