167 lines
5.7 KiB
Markdown
167 lines
5.7 KiB
Markdown
# @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<string, unknown>): Promise<string>;
|
|
```
|
|
|
|
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<Response>,
|
|
request: Request,
|
|
): Promise<Response>;
|
|
```
|
|
|
|
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<Harness>;
|
|
|
|
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<Response>;
|
|
/** 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).
|