reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.74k stars 1.18k forks source link

In Vitest tests, query for mocked data throws ERR_INVALID_ARG_TYPE (RTK Query, MSW, Vitest) #3254

Closed oidualc closed 1 year ago

oidualc commented 1 year ago

RTK Query throws the following error when being tested using Vitest and MSW, and does not make the call to the mocked endpoint. It works correctly on the browser, so it probably is some misconfiguration/incompatibilty with Vitest.

stderr | src/App.test.tsx > should display text
An unhandled error occurred processing a request for the endpoint "getPosts".
In the case of an unhandled error, no tags will be "provided" or "invalidated". TypeError: The "emitter" argument must be an instance of EventEmitter or EventTarget. Received an instance of AbortSignal
    at new NodeError (node:internal/errors:399:5)
    at getEventListeners (node:events:913:9)
    at new Request (node:internal/deps/undici/undici:7138:17)
    at Proxy.<anonymous> (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/src/query/fetchBaseQuery.ts:267:21)
    at step (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:23:23)
    at Object.next (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:4:53)
    at fulfilled (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:95:32) {
  code: 'ERR_INVALID_ARG_TYPE'
}

Here is a minimal reproducible example to replicate the error.

phryneas commented 1 year ago

The "emitter" argument must be an instance of EventEmitter or EventTarget. Received an instance of AbortSignal.

On first thought, I would assume you have multiple incompatible polyfills in place here.

phryneas commented 1 year ago

Running this in my environment (node 16), I am getting

Warning: fetch is not available. Please supply a custom fetchFn property to use fetchBaseQuery on SSR environments.

That might of course be different in other node versions. But it points more towards the direction of "you need a globalThis.fetch and globalThis.AbortController that are compatible with each other". In browsers that is a given, in node it itsn't.

oidualc commented 1 year ago

I'm using the latest Node, v19.7.0, and not getting that warning (I assume you are getting the warning while running pnpm test). I also tried applying this https://github.com/reduxjs/redux-toolkit/blob/67a69e876812282ad7fe5590d173a88bd7b80282/packages/toolkit/jest.setup.js, after following this issue, but it's not working either. It just emits another error:

stderr | src/App.test.tsx > should display text
An unhandled error occurred processing a request for the endpoint "getPosts".
In the case of an unhandled error, no tags will be "provided" or "invalidated". TypeError: Request is not a constructor
    at Proxy.<anonymous> (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/src/query/fetchBaseQuery.ts:267:21)
    at step (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:23:23)
    at Object.next (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:4:53)
    at fulfilled (/home/user/rtkquery-msw-vitest-error/node_modules/.pnpm/@reduxjs+toolkit@1.9.3_k4ae6lp43ej6mezo3ztvx6pykq/node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:95:32)

I can commit this on a branch in the MRE repo if it helps clarifying what I tried.

Is there some documentation somewhere to show how to correctly set globalThis.fetch and globalThis.AbortController to make it work with Vitest?

phryneas commented 1 year ago

Request is not a constructor

Now globalThis.Request is not a constructor o_O.

Did you also polyfill that with the code that you linked?

oidualc commented 1 year ago

Yes, this is what I did: https://github.com/oidualc/rtkquery-msw-vitest-error/blob/node-fetch-polyfill/src/setupTests.ts in the node-fetch-polyfill branch.

phryneas commented 1 year ago

Seems like node-fetch 3 changed their bundling, so the import changes



import nodeFetch, { Request, Response } from "node-fetch";

//@ts-ignore
global.fetch = nodeFetch;
//@ts-ignore
global.Request = Request;
//@ts-ignore
global.Response = Response;```
oidualc commented 1 year ago

Thank you @phryneas, I confirm that your snippet fixes the problem. I'm going to make a repository as an example for future reference, if you think it'll be useful I can make a PR also to include it in the examples section.

phryneas commented 1 year ago

Yes, please, something like that could definitely be useful :)

jfairley commented 1 year ago

Seems like node-fetch 3 changed their bundling, so the import changes

import nodeFetch, { Request, Response } from "node-fetch";

//@ts-ignore
global.fetch = nodeFetch;
//@ts-ignore
global.Request = Request;
//@ts-ignore
global.Response = Response;```

Awesome find! This helped me too! 🎉

With a tweak, you can do it in one line and without @ts-ignore...

import nodeFetch, { Request, Response } from "node-fetch";

Object.assign(global, { fetch: nodeFetch, Request, Response });
LuanScudeler commented 1 year ago

I was having the same issue with Node v18.14.2 and node-fetch 2.6.7 the polyfills suggested here also solved the issue