Skip to content

Setup as Test Environment

David Ortner edited this page Sep 9, 2024 · 6 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 affect 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

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 Interface

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