feat: centralize application framework primitives
This commit is contained in:
@@ -3,6 +3,9 @@ import { createContext, type Context, type ProblemDetails } from "@wrnexus/core"
|
||||
export interface TestRequestOptions extends Omit<RequestInit, "body"> {
|
||||
body?: BodyInit | Record<string, unknown> | URLSearchParams | FormData | null;
|
||||
baseUrl?: string;
|
||||
params?: Record<string, string>;
|
||||
user?: unknown;
|
||||
locals?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** Build a web-standard Request with convenient JSON/FormData handling. */
|
||||
@@ -31,7 +34,50 @@ export function testRequest(path = "/", options: TestRequestOptions = {}): Reque
|
||||
/** Create a complete Context suitable for middleware and route unit tests. */
|
||||
export function testContext(path = "/", options: TestRequestOptions = {}): Context {
|
||||
const request = testRequest(path, options);
|
||||
return createContext(request, new URL(request.url));
|
||||
const ctx = createContext(request, new URL(request.url));
|
||||
ctx.params = { ...options.params };
|
||||
ctx.user = options.user;
|
||||
ctx.locals = { ...options.locals };
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/** Preferred descriptive alias for testContext(). */
|
||||
export const createTestContext = testContext;
|
||||
|
||||
/** Fluent, Bun-compatible fetch mock (including Bun.fetch.preconnect). */
|
||||
export type FetchMock = typeof fetch & {
|
||||
readonly calls: ReadonlyArray<{ input: string | URL | Request; init?: RequestInit }>;
|
||||
respondOnce(response: Response | (() => Response | Promise<Response>)): FetchMock;
|
||||
reset(): void;
|
||||
};
|
||||
|
||||
export function createFetchMock(): FetchMock {
|
||||
const responses: Array<Response | (() => Response | Promise<Response>)> = [];
|
||||
const calls: Array<{ input: string | URL | Request; init?: RequestInit }> = [];
|
||||
const implementation = async (input: string | URL | Request, init?: RequestInit) => {
|
||||
calls.push({ input, init });
|
||||
const next = responses.shift();
|
||||
if (!next) throw new Error("WRN-TEST-FETCH: no response was queued for this request");
|
||||
return typeof next === "function" ? next() : next.clone();
|
||||
};
|
||||
const mock = implementation as FetchMock;
|
||||
Object.defineProperties(mock, {
|
||||
calls: { get: () => calls },
|
||||
respondOnce: {
|
||||
value(response: Response | (() => Response | Promise<Response>)) {
|
||||
responses.push(response);
|
||||
return mock;
|
||||
},
|
||||
},
|
||||
reset: {
|
||||
value() {
|
||||
responses.length = 0;
|
||||
calls.length = 0;
|
||||
},
|
||||
},
|
||||
preconnect: { value: () => undefined },
|
||||
});
|
||||
return mock;
|
||||
}
|
||||
|
||||
export interface JsonResponse<T> {
|
||||
|
||||
@@ -181,15 +181,26 @@ export async function createHarness(
|
||||
};
|
||||
}
|
||||
|
||||
/** Preferred full-stack name; retained alongside createHarness for compatibility. */
|
||||
export const createTestApp = createHarness;
|
||||
|
||||
export {
|
||||
testRequest,
|
||||
testContext,
|
||||
createTestContext,
|
||||
readJsonResponse,
|
||||
expectProblem,
|
||||
deferred,
|
||||
waitFor,
|
||||
MemoryCookieJar,
|
||||
createFetchMock,
|
||||
} from "./advanced.ts";
|
||||
export type {
|
||||
TestRequestOptions,
|
||||
JsonResponse,
|
||||
Deferred,
|
||||
WaitForOptions,
|
||||
FetchMock,
|
||||
} from "./advanced.ts";
|
||||
export type { TestRequestOptions, JsonResponse, Deferred, WaitForOptions } from "./advanced.ts";
|
||||
export { withDatabaseRollback, createFactory, captureBrowserArtifacts } from "./platform.ts";
|
||||
export type { TransactionalDatabase, BrowserArtifactPage } from "./platform.ts";
|
||||
|
||||
Reference in New Issue
Block a user