vitest-dev / vitest

Next generation testing framework powered by Vite.

Home Page:https://vitest.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FormData with file is not setting boundary when running in jsdom env

edenhermelin opened this issue · comments

Describe the bug

Hi,
when trying to send a FormData request that includes a file on a test that is using jsdom,
seems like the request is not adding the content-length properly (as happens automatically on the browser/Node.js)

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-lqr5xr?file=test%2Fbasic.test.ts,vite.config.ts,package.json,package-lock.json&initialPath=__vitest__/

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.18.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    @vitest/ui: latest => 1.6.0 
    vite: latest => 5.2.11 
    vitest: latest => 1.6.0

Used Package Manager

pnpm

Validations

on the browser/Node.js

fetch is provided by Node.js, but FormData is provided by jsdom, so fetch doesn't know how to handle it. This is out of scope of Vitest as we don't control how environments implement their API. To make this work, you can reassign FormData to Node.js one, patch global fetch or wait for JSDOM to implement their own fetch method.

on the browser/Node.js

fetch is provided by Node.js, but FormData is provided by jsdom, so fetch doesn't know how to handle it. This is out of scope of Vitest as we don't control how environments implement their API. To make this work, you can reassign FormData to Node.js one, patch global fetch or wait for JSDOM to implement their own fetch method.

Ok, thanks.
Is there a similar example for one of the workaround methods?

Technically overwriting globals back to nodejs is possible, but I feel the purpose of jsdom environment is questionable at this point.
https://stackblitz.com/edit/vitest-dev-vitest-amqvxh?file=test%2Fbasic.test.ts

// this works because jsdom doesn't provide `Request` and it's coming from NodeJs/undici
async function restoreNodeGlobals() {
  const nodeGlobals: any = {};
  {
    const request = new Request("https://test.local", {
      method: "POST",
      headers: {
        "content-type": "application/x-www-form-urlencoded",
      },
    });
    const formData = await request.formData();
    nodeGlobals.FormData = formData.constructor;
  }
  {
    const request = new Request("https://test.local", {
      method: "POST",
    });
    const blob = await request.blob();
    nodeGlobals.Blob = blob.constructor;
  }
  Object.assign(globalThis, nodeGlobals);
}

FYI, the similar issue has been discussed in #4043