vitest
vitest copied to clipboard
TypeError: Request constructor: Expected init.body ("URLSearchParams {}") to be an instance of URLSearchParams.
Describe the bug
I wanted to open the bug report with jsdom but I failed to reproduce the error without vitest so here we go.
When you are using Node 22.15.0 and you are using "environment": "jsdom" in vitest.config.ts you cannot construct Request objects with URLSearchParams bodies or else TypeError will be thrown:
TypeError: Request constructor: Expected init.body ("URLSearchParams {}") to be an instance of URLSearchParams.
You can successfully construct Request objects again when you override globalThis.URLSearchParams with node:urls URLSearchParams.
Reproduction
The StackBlitz here just presents the setup. I cannot change the Node version in StackBlitz to 22.15.0. And because of this the bug will not show up.
System Info
System:
OS: Linux 5.15 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
CPU: (12) x64 13th Gen Intel(R) Core(TM) i7-1365U
Memory: 2.69 GB / 7.59 GB
Container: Yes
Shell: 5.1.4 - /bin/bash
Binaries:
Node: 23.8.0 - /run/user/1000/fnm_multishells/86411_1745923856293/bin/node
npm: 10.9.2 - /run/user/1000/fnm_multishells/86411_1745923856293/bin/npm
pnpm: 10.4.1 - /run/user/1000/fnm_multishells/86411_1745923856293/bin/pnpm
npmPackages:
vitest: ^3.1.2 => 3.1.2
Used Package Manager
pnpm
Validations
- [x] Follow our Code of Conduct
- [x] Read the Contributing Guidelines.
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [x] The provided reproduction is a minimal reproducible example of the bug.
I'd say this is a known edge case. See a similar issue: https://github.com/vitest-dev/vitest/issues/4043
JSDOM doesn't provide Request or fetch, so Vitest exposes the built-in Node.js one, but jsdom provides URL and URLSearchParam. The default Request validates that input is actually Node.js implementation of URLSearchParam, not that it just implements the same interface. This is why overriding URLSearchParams makes Request work correctly.
I know this might not be the solution you want, but it is a solution that worked for us. Instead of
const body = new URLSearchParams();
body.set('key', 'value');
new Request('http://localhost', { method: 'POST', body });
you can write
const searchParams = new URLSearchParams();
searchParams.set('key', 'value');
new Request('http://localhost', { method: 'POST', body: searchParams.toString() });
Mind you that we did that with the header 'content-type': 'application/x-www-form-urlencoded' and it might thus not work for you - I haven't tried to replicate your exact case.
Are there any downsides to overriding URLSearchParams in the vitest setup? Would it be appropriate to somehow do that override in vitest? Or is this actually a bug in jsdom that it's implementation needs to change so node can validate it?
Seems like this works on Node 24