All guidesMore providers: databases, auth, hosting, email and payments
On this page

Vitest error

Vitest

ReferenceError: document is not defined

By Ohad Krispin, founder of VibeRaven · LinkedIn

"ReferenceError: document is not defined", or "window is not defined", in a Vitest test means the file ran in the node environment, which has no DOM. The Vitest docs list node as the default for the environment option. Set test.environment to jsdom or happy-dom in vitest.config.ts and install that package as a dev dependency, or put // @vitest-environment jsdom at the top of the one test file that needs it. The same failure appears in GitHub Actions or in a Vercel build command that runs Vitest, because they read the same config. Reproduced with vitest 5.0.5 on 2026-10-31.

What does the full error look like?

A test that calls document.createElement, or reads window.location, fails in the node environment. Vitest reports each test separately, and the first line of each is the ReferenceError. With the environment set to jsdom or happy-dom, the same two tests passed in our run.

FAIL  a.test.ts > dom
ReferenceError: document is not defined
 ❯ a.test.ts:3:14
      3|   const el = document.createElement('div')

FAIL  a.test.ts > win
ReferenceError: window is not defined
 ❯ a.test.ts:7:10

Should I use jsdom or happy-dom?

The Vitest environment docs describe both as emulating a browser: jsdom through the jsdom package, and happy-dom as considered faster than jsdom but missing some APIs. The Next.js guide for Vitest installs jsdom and sets environment: 'jsdom'. Both made the two tests above pass. If a component test later fails on a missing browser API, that is the point to switch, not before.

npm install -D jsdom
# or
npm install -D happy-dom

// vitest.config.ts
import { defineConfig } from "vitest/config"
export default defineConfig({ test: { environment: "jsdom" } })

I set the environment in vite.config.ts and it is still node

The Vitest config docs say that when a vitest.config file exists it has the higher priority and overrides vite.config, so all options in vite.config are ignored. In our run, a vite.config.ts with test.environment set to jsdom was ignored once a vitest.config.ts without it was added, and the same two tests failed with the same error. Put the option in the file Vitest actually reads.

Checklist

How to fix it, then check the fix

  1. 01
    Find which config file Vitest reads and whether it sets an environment:
    ls vitest.config.* vite.config.* 2>/dev/null
    grep -rn "environment" vitest.config.* vite.config.* 2>/dev/null
  2. 02If both files exist, set the option in vitest.config, or delete it and keep one file. The one named vitest.config wins.
  3. 03
    Install the DOM package you chose as a dev dependency, so CI has it:
    npm install -D jsdom
  4. 04For only a few DOM tests, leave the project on node and add // @vitest-environment jsdom as the first line of each of those files.
  5. 05
    Run the failing file again. It should list the tests as passed, not a ReferenceError:
    npx vitest run path/to/file.test.ts

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

Why does the same test pass in my editor but fail in CI?

CI runs npx vitest run with what is in the repository. If the jsdom setting or the dev dependency exists only on your machine, CI runs the file in node. Commit the config and the lockfile.

What if Vitest says MISSING DEPENDENCY, Cannot find dependency 'jsdom'?

The environment is set but the package is not installed. In our run, with jsdom removed from node_modules, Vitest printed that line and then failed to start the worker with Cannot find package 'jsdom'. Install it as a dev dependency and commit the lockfile so CI installs it too.

Does the error mean the app is broken on Vercel?

No. It only says a test touched a browser object in a Node process. It says nothing about your deployed app.