99 lines
3.8 KiB
TypeScript
99 lines
3.8 KiB
TypeScript
import { afterEach, expect, test } from "bun:test";
|
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { buildRouter } from "@wrnexus/router";
|
|
import { createHandlers, type RuntimeDeps } from "../src/runtime.ts";
|
|
|
|
const roots: string[] = [];
|
|
afterEach(() => roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true })));
|
|
|
|
test("in-process api failures preserve status and response data for server error sections", async () => {
|
|
const root = mkdtempSync(join(tmpdir(), "wrnexus-api-error-context-"));
|
|
roots.push(root);
|
|
const app = join(root, "app");
|
|
mkdirSync(join(app, "pages"), { recursive: true });
|
|
mkdirSync(join(app, "api"), { recursive: true });
|
|
writeFileSync(join(app, "pages", "probe.ts"), "export default () => '';\n");
|
|
writeFileSync(join(app, "api", "failure.ts"), "export const GET = () => null;\n");
|
|
|
|
const handlers = createHandlers({
|
|
mode: "production",
|
|
hmr: false,
|
|
router: buildRouter(app),
|
|
loadModule: async (file) =>
|
|
file.endsWith(`${join("api", "failure")}.ts`)
|
|
? {
|
|
GET: () => Response.json({ error: "denied", reason: "policy" }, { status: 403 }),
|
|
}
|
|
: {
|
|
__wrnexusLoad: async (ctx: {
|
|
__wrnexusCallApi: (path: string, method: string) => Promise<unknown>;
|
|
}) => {
|
|
try {
|
|
await ctx.__wrnexusCallApi("/api/failure", "GET");
|
|
return { caught: null };
|
|
} catch (error) {
|
|
return {
|
|
caught: {
|
|
status: (error as { status?: unknown }).status,
|
|
data: (error as { data?: unknown }).data,
|
|
},
|
|
};
|
|
}
|
|
},
|
|
default: (ctx: { caught: unknown }) => `<pre>${JSON.stringify(ctx.caught)}</pre>`,
|
|
},
|
|
getMiddleware: async () => [],
|
|
assets: { serve: async () => null },
|
|
} satisfies RuntimeDeps);
|
|
|
|
const response = await handlers.fetch(new Request("https://example.test/probe"), {
|
|
upgrade: () => false,
|
|
});
|
|
|
|
expect(response?.status).toBe(200);
|
|
expect(await response?.text()).toContain(
|
|
JSON.stringify({ status: 403, data: { error: "denied", reason: "policy" } }),
|
|
);
|
|
});
|
|
|
|
test("in-process api calls inherit authenticated request context", async () => {
|
|
const root = mkdtempSync(join(tmpdir(), "wrnexus-api-auth-context-"));
|
|
roots.push(root);
|
|
const app = join(root, "app");
|
|
mkdirSync(join(app, "pages"), { recursive: true });
|
|
mkdirSync(join(app, "api"), { recursive: true });
|
|
writeFileSync(join(app, "pages", "probe.ts"), "export default () => '';\n");
|
|
writeFileSync(join(app, "api", "identity.ts"), "export const GET = () => null;\n");
|
|
|
|
const handlers = createHandlers({
|
|
mode: "production",
|
|
hmr: false,
|
|
router: buildRouter(app),
|
|
loadModule: async (file) =>
|
|
file.endsWith(`${join("api", "identity")}.ts`)
|
|
? { GET: (ctx: { user?: unknown }) => Response.json({ user: ctx.user }) }
|
|
: {
|
|
__wrnexusLoad: async (ctx: {
|
|
__wrnexusCallApi: (path: string, method: string) => Promise<unknown>;
|
|
}) => ({ identity: await ctx.__wrnexusCallApi("/api/identity", "GET") }),
|
|
default: (ctx: { identity: unknown }) => `<pre>${JSON.stringify(ctx.identity)}</pre>`,
|
|
},
|
|
getMiddleware: async () => [
|
|
(ctx, next) => {
|
|
ctx.user = { id: "authenticated-user" };
|
|
return next();
|
|
},
|
|
],
|
|
assets: { serve: async () => null },
|
|
} satisfies RuntimeDeps);
|
|
|
|
const response = await handlers.fetch(new Request("https://example.test/probe"), {
|
|
upgrade: () => false,
|
|
});
|
|
|
|
expect(response?.status).toBe(200);
|
|
expect(await response?.text()).toContain(JSON.stringify({ user: { id: "authenticated-user" } }));
|
|
});
|