Setup
Install
pnpm add -D @opentf/afw-test @opentf/esdev-plugin-afw
Use esdev 0.17 or newer.
Configure compilation and cleanup
Create a separate test config so components use CSR even when the app builds for SSG:
{ "plugins": [{ "module": "@opentf/esdev-plugin-afw", "export": "createAfwPlugin", "options": { "target": "csr", "failOnError": true } }], "test": { "setup": ["@opentf/afw-test/setup"] } }
The plugin compiles JSX imports. The setup module registers cleanup after every test; it uses the DOM provided by the runner.
Write your first test
import { test, expect } from "runtime:test"; import { render } from "@opentf/afw-test"; import Counter from "./Counter.jsx"; test("renders", () => { const { getByRole } = render(Counter); expect(getByRole("button")).toBeDefined(); });
Run
esdev test --config=esdev.test.json --dom
The setup module calls cleanup() after each test. Component disconnect and page teardown dispose their lifecycle and effects. Await observable teardown when testing custom-element cleanup reactions.
Manual cleanup
If you omit test.setup, register the hook in each test file:
import { afterEach } from "runtime:test"; import { cleanup } from "@opentf/afw-test"; afterEach(cleanup);
Keep the compiler plugin in the test config: cleanup and JSX compilation are separate steps. See the official test configuration.
Browser interactions
userEvent.setup() workflows run under --dom. Use esdev test --config=esdev.test.json --browser with a supported browser and matching driver when a test depends on layout, CSS or real event timing. See User Events.