> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# DOM Testing

> Test DOM and Web APIs with Bun's built-in support

Bun includes built-in support for Web APIs, making it easy to test DOM-related code without additional setup.

## Built-in DOM APIs

Bun provides these Web APIs out of the box:

* `fetch`
* `Request`, `Response`, `Headers`
* `URL`, `URLSearchParams`
* `Blob`, `File`
* `FormData`
* `TextEncoder`, `TextDecoder`
* `ReadableStream`, `WritableStream`, `TransformStream`
* `WebSocket`
* `EventTarget`, `Event`, `CustomEvent`
* `AbortController`, `AbortSignal`
* `structuredClone`

```ts theme={null}
import { test, expect } from "bun:test";

test("fetch API", async () => {
  const response = await fetch("https://api.example.com/data");
  expect(response.ok).toBe(true);
  const data = await response.json();
  expect(data).toBeDefined();
});

test("URL parsing", () => {
  const url = new URL("https://example.com/path?foo=bar");
  expect(url.hostname).toBe("example.com");
  expect(url.searchParams.get("foo")).toBe("bar");
});
```

## Testing with happy-dom

For full DOM support, use `happy-dom`:

```bash theme={null}
$ bun add -d happy-dom
```

Create a test setup file:

```ts #test/setup.ts theme={null}
import { GlobalRegistrator } from "@happy-dom/global-registrator";

GlobalRegistrator.register();
```

Configure in `bunfig.toml`:

```toml theme={null}
[test]
preload = ["./test/setup.ts"]
```

Now you can use DOM APIs in tests:

```ts theme={null}
import { test, expect } from "bun:test";

test("DOM manipulation", () => {
  document.body.innerHTML = `
    <div id="app">
      <h1>Hello World</h1>
    </div>
  `;
  
  const app = document.getElementById("app");
  expect(app).toBeDefined();
  expect(app?.querySelector("h1")?.textContent).toBe("Hello World");
});
```

## Testing React components

Test React components with `@testing-library/react`:

```bash theme={null}
$ bun add -d @testing-library/react happy-dom
```

Setup file:

```ts #test/setup.ts theme={null}
import { GlobalRegistrator } from "@happy-dom/global-registrator";

GlobalRegistrator.register();
```

Test a component:

```tsx theme={null}
import { test, expect } from "bun:test";
import { render, screen } from "@testing-library/react";

function Button({ onClick, children }: { onClick: () => void; children: React.ReactNode }) {
  return <button onClick={onClick}>{children}</button>;
}

test("Button renders", () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Click me</Button>);
  
  const button = screen.getByText("Click me");
  expect(button).toBeDefined();
  
  button.click();
  expect(handleClick).toHaveBeenCalledTimes(1);
});
```

## Testing with jsdom

Alternatively, use `jsdom`:

```bash theme={null}
$ bun add -d jsdom
```

Setup file:

```ts #test/setup.ts theme={null}
import { JSDOM } from "jsdom";

const dom = new JSDOM("<!DOCTYPE html>");
global.document = dom.window.document;
global.window = dom.window as any;
```

## Testing Web Components

```ts theme={null}
import { test, expect } from "bun:test";

class MyElement extends HTMLElement {
  connectedCallback() {
    this.innerHTML = "<p>Hello from Web Component</p>";
  }
}

customElements.define("my-element", MyElement);

test("Web Component", () => {
  const element = document.createElement("my-element");
  document.body.appendChild(element);
  
  expect(element.innerHTML).toBe("<p>Hello from Web Component</p>");
});
```

## Testing event handling

```ts theme={null}
import { test, expect } from "bun:test";

test("event handling", () => {
  const button = document.createElement("button");
  const handleClick = jest.fn();
  
  button.addEventListener("click", handleClick);
  button.click();
  
  expect(handleClick).toHaveBeenCalledTimes(1);
});
```

## Testing async DOM updates

```ts theme={null}
import { test, expect } from "bun:test";
import { waitFor } from "@testing-library/react";

test("async DOM update", async () => {
  const div = document.createElement("div");
  
  setTimeout(() => {
    div.textContent = "Updated";
  }, 100);
  
  await waitFor(() => {
    expect(div.textContent).toBe("Updated");
  });
});
```

## Cleanup

Clean up DOM between tests:

```ts theme={null}
import { afterEach } from "bun:test";

afterEach(() => {
  document.body.innerHTML = "";
});
```

## Accessing window properties

```ts theme={null}
import { test, expect } from "bun:test";

test("window properties", () => {
  expect(window.location.href).toBe("http://localhost/");
  expect(window.innerWidth).toBeGreaterThan(0);
});
```

## Form testing

```ts theme={null}
import { test, expect } from "bun:test";

test("form submission", () => {
  document.body.innerHTML = `
    <form id="myForm">
      <input name="username" value="alice" />
      <input name="email" value="alice@example.com" />
    </form>
  `;
  
  const form = document.getElementById("myForm") as HTMLFormElement;
  const formData = new FormData(form);
  
  expect(formData.get("username")).toBe("alice");
  expect(formData.get("email")).toBe("alice@example.com");
});
```

## Related

* [Writing Tests](/test/writing)
* [Mocks](/test/mocks)
* [Configuration](/test/configuration)
