# @wrnexus/test > Testing utilities for WrNexus apps — component rendering, reactive-DOM mounting, route handler calls, and a full in-process app harness, plus a one-import re-export of `bun:test`. Part of the **WrNexus** framework — an SSR-first, Bun-native full-stack web framework. ## Overview `@wrnexus/test` is the server-side test toolkit you reach for when writing tests for a WrNexus app. It runs under `bun test` (invoked via `wrnexus test`) and gives you a single import surface: the `bun:test` primitives (`test`, `expect`, `mock`, …) re-exported alongside WrNexus-aware helpers that compile `.wrn` components, hydrate server HTML in a DOM, invoke API route handlers, and boot the real app on an ephemeral port for integration tests. ## Installation ```bash bun add @wrnexus/test ``` > Private package — the machine must be authenticated to the `wrnexus` npm org > (a read token in `~/.npmrc`). Requires **Bun** (Node is not supported). ## API ### Re-exported test primitives For one-import DX, the following are re-exported straight from `bun:test`: `test`, `expect`, `describe`, `it`, `beforeEach`, `afterEach`, `beforeAll`, `afterAll`, `mock`, `spyOn`. `createContext` is also re-exported from `@wrnexus/core`. ### `renderComponent(source, props?)` ```ts function renderComponent(source: string, props?: Record): Promise; ``` Compiles a `.wrn` component `source` string (via `@wrnexus/compiler`) and renders it to an HTML string with the given `props`. Throws if the compiled module has no `render` export. ### `mountHtml(html)` ```ts function mountHtml(html: string): { document: Document; window: unknown; querySelector: (sel: string) => Element | null; querySelectorAll: (sel: string) => Element[]; }; ``` Mounts server-rendered `html` in a `happy-dom` window with the reactive runtime hydrated, so you can test `data-scope` / `data-text` / `data-for` / `data-show` behaviour. Returns the window plus `document` and query helpers; assert on those. > `happy-dom` is loaded lazily (via `require`), so importing this package never > requires it unless you actually call `mountHtml`. ### `callRoute(handler, request)` ```ts function callRoute( handler: (ctx: Context) => Response | Promise, request: Request, ): Promise; ``` Calls an API route `handler` with a `Context` built from a `Request` (using `createContext`). Returns the handler's `Response`. ### `createHarness(projectRoot, options?)` ```ts function createHarness(projectRoot: string, options?: HarnessOptions): Promise; interface HarnessOptions { /** Config/env profile. Default "test". */ profile?: string; } interface Harness { /** Base URL of the ephemeral test server. */ url: string; /** Fetch a path on the app (relative to `url`). */ fetch(path: string, init?: RequestInit): Promise; /** The scanned router (pages/api/realtime/components). */ router: unknown; /** Stop the server. */ close(): void; } ``` Boots the app at `projectRoot` on an ephemeral port (`port: 0`) for integration tests covering pages, API routes, middleware, and the full request pipeline. Loads env and app config for the given `profile` (default `"test"`) so it picks up your test database/env. The server runs in `development` mode with HMR disabled. Remember to `await app.close()` when done. ## Usage The CLI supports focused suites by file or directory convention: ```bash wrnexus test unit # *.unit.test.ts or test/unit/** wrnexus test component # *.component.test.ts or test/component/** wrnexus test api # *.api.test.ts or test/api/** wrnexus test accessibility # *.a11y.test.ts / *.accessibility.test.ts wrnexus test performance # *.performance.test.ts / *.benchmark.test.ts wrnexus test browser # Playwright project when configured wrnexus test visual # Playwright tests tagged @visual ``` Pass the application directory after the level, for example `wrnexus test component examples/basic-app`. A focused command fails clearly when no matching suite exists instead of silently running unrelated tests. ```ts import { test, expect, renderComponent, mountHtml, createHarness } from "@wrnexus/test"; test("counter renders its label", async () => { const html = await renderComponent(SRC, { start: 3, label: "Hits" }); expect(html).toContain("Hits"); }); test("reactive scope hydrates", () => { const { querySelector } = mountHtml(serverHtml); expect(querySelector("[data-text]")?.textContent).toBe("3"); }); test("home page responds", async () => { const app = await createHarness("examples/basic-app"); const res = await app.fetch("/"); expect(res.status).toBe(200); await app.close(); }); ``` Calling an API route handler directly: ```ts import { test, expect, callRoute } from "@wrnexus/test"; import { GET } from "../app/api/health.ts"; test("health endpoint", async () => { const res = await callRoute(GET, new Request("http://test/api/health")); expect(res.status).toBe(200); }); ``` ## Requirements / Notes - **Bun-only.** Runs under `bun test` (via `wrnexus test`); uses Bun's module loading and the `bun:test` runtime. - `mountHtml` requires **`happy-dom`** to be available in the workspace (loaded lazily; it's a dev dependency, not a runtime dependency of this package). - Works with the rest of the WrNexus toolchain: [`@wrnexus/compiler`](../compiler) (compiles `.wrn` sources), [`@wrnexus/core`](../core) (`Context` / `createContext`), [`@wrnexus/csr`](../csr) (reactive runtime for `mountHtml`), [`@wrnexus/dev-server`](../dev-server) (`startServer` behind `createHarness`), and [`@wrnexus/styles`](../styles) (config/env/profile loading for the harness).