Testing Fresh pages
The @netscript/fresh testing export provides fixtures for exercising routes,
loaders, and layouts without standing up an HTTP server. Reach for it when you
want to unit-test a page's loader logic, assert on the context a route receives,
or drive defer-region helpers with a controlled policy. The helpers build the
same shape your route code reads at runtime, so a test can call your loader
directly and inspect the result.
What the testing surface provides
The export centers on two factory functions:
createMockRouteContext()builds a minimal page context fixture for route, loader, and layout tests. It returns aMockRouteContextthat mirrors the request URL, route params, parsed path and search values, layer data, named resources, and an abort signal — everything a loader or layout reads from its context.createMockDeferPolicy()builds a defer policy fixture accepted by defer-region helpers, so tests that cover deferred or streaming partials can pin freshness and prewarm behavior.
Both factories take a plain options object, so a test composes only the fields it cares about and leaves the rest at their fixture defaults.
Testing a route loader
createMockRouteContext() accepts MockRouteContextOptions. Every field is
optional: supply a url, params, state, parsed path and search values,
a routePattern, named resources, an explicit req, or a signal. The
returned MockRouteContext exposes those values as readonly properties, plus a
resource(key) method that returns a single named resource and a nav fixture
with makeHref().
import { assertEquals } from "@std/assert";
import { createMockRouteContext } from "@netscript/fresh/testing";
// The loader under test reads params and a named resource from its context.
const loadDashboard = (ctx: {
path: { id: string };
resource: (key: "metrics") => { read: () => number };
}) => ({
id: ctx.path.id,
total: ctx.resource("metrics").read(),
});
Deno.test("dashboard loader reads the path id and metrics resource", () => {
const ctx = createMockRouteContext<
Record<string, never>,
{ metrics: { read: () => number } },
{ id: string }
>({
url: "https://example.com/dashboards/42",
routePattern: "/dashboards/:id",
path: { id: "42" },
resources: { metrics: { read: () => 128 } },
});
const result = loadDashboard(ctx);
assertEquals(result.id, "42");
assertEquals(result.total, 128);
assertEquals(ctx.resource("metrics").read(), 128);
});
The fixture's url is a URL, req is a Request, params is a
Record<string, string | undefined>, and signal is an AbortSignal. Tests
that need to assert on cancellation can pass their own signal through the
options and observe it on the returned context.
Testing layouts
Layout tests read layerData from the context, a Record<string, unknown>
carrying the data a layout receives. Construct a fixture with the layer data your
layout expects and pass the context to the layout under test.
import { createMockRouteContext } from "@netscript/fresh/testing";
const ctx = createMockRouteContext({
url: "https://example.com/reports",
routePattern: "/reports",
});
// `ctx.layerData` is the Record<string, unknown> a layout reads.
const layerData = ctx.layerData;
Defer policy fixtures
createMockDeferPolicy() accepts either a MockDeferPolicyProfile name or a
MockDeferPolicyInput override object, and returns the resolved policy for use
with defer-region helpers. The profile names are "balanced",
"aggressive-first-paint", "background-refresh", and "low-bandwidth". The
MockDeferPolicyInput form lets a test start from a named profile and then
override individual fields: staleTimeMs for the freshness window,
prewarmOnMiss and prewarmOnStale for cache-prewarm behavior, and
clientRefreshOnFreshCache and skipClientWhenServerPrewarm for client refresh
behavior.
import { createMockDeferPolicy } from "@netscript/fresh/testing";
// Start from a named profile.
const balanced = createMockDeferPolicy("balanced");
// Or override individual fields on top of a profile.
const tuned = createMockDeferPolicy({
profile: "background-refresh",
staleTimeMs: 5_000,
prewarmOnStale: true,
skipClientWhenServerPrewarm: true,
});
API summary
| Symbol | Kind | Description |
|---|---|---|
createMockRouteContext() |
function | Create a minimal page context fixture for route, loader, and layout tests. |
createMockDeferPolicy() |
function | Create a defer policy fixture accepted by defer-region helpers. |
MockRouteContext |
interface | Mock route context returned by createMockRouteContext(). |
MockRouteContextOptions |
interface | Options used to construct a route context fixture. |
MockDeferPolicyInput |
interface | Mock defer policy override accepted by defer test fixtures. |
MockDeferPolicyProfile |
type | Named policy profile: "balanced", "aggressive-first-paint", "background-refresh", "low-bandwidth". |
MockRouteContext properties
| Property | Type | Description |
|---|---|---|
url |
URL |
Request URL for the fixture. |
req |
Request |
Raw request object for the fixture. |
params |
Record<string, string | undefined> |
Fresh route params for the fixture. |
state |
TState |
Fresh state object for the fixture. |
signal |
AbortSignal |
Request abort signal. |
path |
TPath |
Parsed route path params. |
search |
TSearch |
Parsed route search values. |
layerData |
Record<string, unknown> |
Layer data available to layout tests. |
routePattern |
string |
Route pattern represented by the fixture. |
nav |
{ makeHref(): string } |
Minimal route navigation fixture. |
route |
unknown |
Optional route reference for tests that need routed context. |
resources |
TResources |
Named resources available to route loaders. |
resource(key) |
method | Return a named resource from the fixture. |
MockDeferPolicyInput properties
| Property | Type | Description |
|---|---|---|
profile |
MockDeferPolicyProfile |
Named policy profile to start from. |
staleTimeMs |
number |
Override for the freshness window in milliseconds. |
prewarmOnMiss |
boolean |
Prewarm the partial when the cache is missing. |
prewarmOnStale |
boolean |
Prewarm the partial when the cache is stale. |
clientRefreshOnFreshCache |
boolean |
Allow client refresh even when server cache is fresh. |
skipClientWhenServerPrewarm |
boolean |
Skip client refresh when the server is already prewarming. |