Test browser APIs, DOM elements, and React components in Bun using happy-dom and React Testing Library.
Bun’s test runner is compatible with popular DOM and component testing libraries. The recommended setup uses happy-dom to simulate a browser environment.
happy-dom implements a complete set of HTML and DOM APIs in JavaScript, making it possible to run browser-targeting code in Bun without a real browser.
1
Install the package
bun add -d @happy-dom/global-registrator
2
Create a preload file
Create happydom.ts at the root of your project to register the browser globals:
happydom.ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";GlobalRegistrator.register();
3
Register the preload in bunfig.toml
bunfig.toml
[test]preload = ["./happydom.ts"]
This executes happydom.ts before any test file runs, making document, window, and other browser globals available.
For projects that need additional globals polyfilled (e.g., ResizeObserver, matchMedia), create a more comprehensive preload file:
test-setup.ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";import "@testing-library/jest-dom";import { afterEach } from "bun:test";import { cleanup } from "@testing-library/react";// Register all browser globalsGlobalRegistrator.register();// Polyfill APIs not in happy-domglobal.ResizeObserver = class ResizeObserver { observe() {} unobserve() {} disconnect() {}};// Clean up after each testafterEach(() => { cleanup(); document.body.innerHTML = "";});
If you prefer jsdom, install it and register it similarly:
bun add -d jsdom
jsdom-setup.ts
import { JSDOM } from "jsdom";const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");global.window = dom.window as unknown as Window & typeof globalThis;global.document = dom.window.document;global.navigator = dom.window.navigator;
Add the triple-slash DOM reference to the top of the file:
/// <reference lib="dom" />
Alternatively, add "lib": ["dom"] to your tsconfig.json.
Globals not available in tests
Ensure your preload file is registered in bunfig.toml and that GlobalRegistrator.register() is called before any tests run.
React component rendering issues
Confirm that both @testing-library/react and @happy-dom/global-registrator are installed as dev dependencies, and that the preload file is loaded before test files.
State leaking between tests
Reset the DOM in afterEach to prevent state from one test affecting the next:
import { afterEach } from "bun:test";import { cleanup } from "@testing-library/react";afterEach(() => { cleanup(); document.body.innerHTML = "";});