Skip to content

jsdom environment turns every Blob/File request body into the string "undefined" #11294

Description

@harshit-d3v

Describe the bug

Under environment: 'jsdom', a Blob or File used as a request body arrives as the literal string undefined. Nothing throws, so a test uploading a file passes while sending nine bytes of ASCII instead of its content.

const blob = new Blob(['hello world'], { type: 'text/plain' })
const text = await new Request('http://x.test/', { method: 'POST', body: blob }).text()
environment text
node "hello world"
happy-dom "hello world"
jsdom "undefined"

Same for a File inside FormData: the multipart part body is undefined, and fetch(URL.createObjectURL(blob)) returns undefined too.

Cause

makeCompatBlob in packages/vitest/src/integrations/env/jsdom.ts bridges jsdom's Blob to Node's fetch by reading a private field:

const buffer = (blob as any)[implSymbol]._buffer
return new NodeBlob_([buffer], { type: blob.type })

jsdom 28.0.0 renamed that field to _bytes, so the read is undefined and new Blob([undefined]) stringifies it.

jsdom impl keys
24.1.3 – 27.4.0 _buffer,_globalObject,type
28.1.0 – 29.1.1 _globalObject,type,_bytes

Vitest's own devDependency is jsdom: ^29.1.1, so the default combination is the broken one. The existing tests in test/unit/test/environments/jsdom.spec.ts use an empty new Blob() and only assert toBeInstanceOf, which is why CI stays green.

Reproduction

The snippet above, in any project with vitest@5.0.1 and jsdom@29, run once per environment. A single test file:

import { expect, test } from 'vitest'

test('blob bytes survive a Request body', async () => {
  const blob = new Blob(['hello world'], { type: 'text/plain' })
  const text = await new Request('http://x.test/', { method: 'POST', body: blob }).text()
  expect(text).toBe('hello world')
})

Passes with --environment=node and --environment=happy-dom, fails with --environment=jsdom.

System Info

vitest 5.0.1
jsdom 29.1.1
node 22.18.0
win32 x64

Used Package Manager

npm

Validations

  • Follow our Code of Conduct
  • Read the Contributing Guidelines
  • Read the docs
  • Check that there isn't already an issue that reports the same bug
  • Check that this is a concrete bug
  • The provided reproduction is a minimal reproducible example of the bug

I used Claude to help investigate this. I ran the reproduction myself across the three environments and the six jsdom versions above.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    p3-minor-bugAn edge case that only affects very specific usage (priority)

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions