Skip to content

Setup as Test Environment

David Ortner edited this page Jan 2, 2025 · 9 revisions

Setup

Vitest

Vitest supports Happy DOM out of the box.

Link to guide

Timer Functionality

happyDOM.waitUntilComplete() and happyDOM.abort() doesn't fully work by default in Vitest, as Vitest doesn't use the timer methods from Happy DOM. The timer settings will have no effect for the same reason.

As a workaround you can take in the timer methods from Happy DOM.

Add this to you test setup file to add the workaround:

import { PropertySymbol } from "happy-dom";

// It was "ownerWindow" in older versions of Happy DOM
const browserWindow =
	global.document[PropertySymbol.ownerWindow] ||
	global.document[PropertySymbol.window];

global.setTimeout = browserWindow.setTimeout;
global.clearTimeout = browserWindow.clearTimeout;
global.setInterval = browserWindow.setInterval;
global.clearInterval = browserWindow.clearInterval;
global.requestAnimationFrame = browserWindow.requestAnimationFrame;
global.cancelAnimationFrame = browserWindow.cancelAnimationFrame;
global.queueMicrotask = browserWindow.queueMicrotask;

Hopefully this can be fixed soon.

Bun

Bun supports Happy DOM out of the box.

Link to guide

Node.js Native Test Runner

Node.js v23 adds support for a built in test runner. The package @happy-dom/global-registrator can be used to setup Happy DOM as an envionment for it.

Note that the Happy DOM environment needs to be imported before any setup scripts or tests in order for them to be executed within the Happy DOM environment.

  1. Create a file called happy-dom-env.ts (or any other name you prefer).

  2. Add the following to it:

    import { GlobalRegistrator } from "@happy-dom/global-registrator";
    
    GlobalRegistrator.register({
       url: 'http://localhost:3000',
       width: 1920,
       height: 1080,
    });
  3. Add the file as an import to the "test" script in package.json:

    {
       "scripts": {
          "test": "node --import ./happy-dom-env.ts --test ./test/**/*.test.{ts,tsx}"
       }
    }

Testing Library

Testing Library supports Happy DOM out of the box.

Jest

Happy DOM provide with a package called @happy-dom/jest-environment that makes it possible to use Happy DOM with Jest.

Global Registrator

Happy DOM provide with a package called @happy-dom/global-registrator that can register Happy DOM globally, which makes it easy to setup your own testing environment.

Browser API

Happy DOM provide with an interface for accessing the Browser API functionality in test environments. It is accessible through the property Window.happyDOM. It provide with various functionality, such as changing viewport or settings at runtime.

Read more about which methods and properties it has in the API documention for DetachedWindowAPI.

Type definition

If you are using Typescript and you wish to be able to access the happyDOM property globally, you can achieve this by creating a type definition file for your project.

  1. Create the file test.global.d.ts

  2. Add the following to it:

    import type DetachedWindowAPI from "happy-dom/lib/window/DetachedWindowAPI.js";
    
    declare global {
       const happyDOM: DetachedWindowAPI;
    }
  3. Add the file as an include to your tsconfig.json:

    {
       "include": ["./test.global.d.ts"]
    }

Mocking / Spying

Storage

It is common to mock local and session storage for unit tests. Storage mocking is a special case as according to spec, Object.getOwnPropertyDescriptor() should return undefined for methods in the Storage class, which is something Jest doesn't play well with.

Vitest

Spy on instance

it("Should be able to spy on localStorage.getItem().", () => {
   vi.spyOn(localStorage, "getItem").mockImplementation(() => "mocked");
   expect(localStorage.getItem("key1")).toBe("mocked");
});

Spy on prototype methods

it("Should be able to spy on Storage.prototype.getItem().", () => {
   vi.spyOn(Storage.prototype, "getItem").mockImplementation(() => "mocked");
   expect(localStorage.getItem("key1")).toBe("mocked");
});

Jest

Spy on instance

It is not possible to spy on the instance methods as Jest relies on Object.getOwnPropertyDescriptor() to return a descriptor for the method, which Storage shouldn't do according to spec.

Spy on prototype methods

it("Should be able to spy on Storage.prototype.getItem().", () => {
   jest.spyOn(Storage.prototype, "getItem").mockImplementation(() => "mocked");
   expect(localStorage.getItem("key1")).toBe("mocked");
});
Clone this wiki locally