vitest icon indicating copy to clipboard operation
vitest copied to clipboard

TypeError: Request constructor: Expected init.body ("URLSearchParams {}") to be an instance of URLSearchParams.

Open ghost opened this issue 7 months ago • 1 comments

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

ghost avatar Apr 29 '25 11:04 ghost

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.

sheremet-va avatar Apr 29 '25 14:04 sheremet-va

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.

Maverick283 avatar Jul 11 '25 14:07 Maverick283

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?

aelfric avatar Jul 23 '25 23:07 aelfric

Seems like this works on Node 24

sheremet-va avatar Aug 06 '25 15:08 sheremet-va