Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
import { expect, test } from "@playwright/test";
/**
* Stage-5 smoke spec — exercises every wired adapter from a real HTTP
* call against a `createTestHost(...)`-backed server. The companion
* `src/server.ts` boots the Bun.serve listener; this spec hits the
* endpoints and asserts on the observable behaviour.
*/
test.describe("createTestHost — Stage-5 smoke", () => {
test("1. zero-config plugin install lands on host.plugins", async ({
request,
}) => {
const res = await request.get("/api/plugins");
expect(res.status()).toBe(200);
const body = (await res.json()) as { plugins: string[] };
expect(body.plugins).toContain("smoke-fixture");
});
test("2. fixture-plugin route resolves via the in-memory router", async ({
request,
}) => {
const res = await request.get("/api/principal");
expect(res.status()).toBe(200);
const body = (await res.json()) as {
id: string | null;
scopes: string[] | null;
};
// Even with no tenant header, principal still resolves through the
// seeded static-principal resolver.
expect(body.id).toBe("smoke-principal");
});
test("3. seed.principal reaches ctx.principal", async ({ request }) => {
const res = await request.get("/api/principal");
const body = (await res.json()) as {
id: string | null;
scopes: string[] | null;
};
expect(body.id).toBe("smoke-principal");
expect(body.scopes).toEqual(["smoke:read", "smoke:write"]);
});
test("4. seed.tenants + X-Tenant-Id reaches ctx.tenant", async ({
request,
}) => {
const res = await request.get("/api/tenant", {
headers: { "X-Tenant-Id": "smoke-tenant" },
});
expect(res.status()).toBe(200);
const body = (await res.json()) as {
id: string | null;
slug: string | null;
};
expect(body.id).toBe("smoke-tenant");
expect(body.slug).toBe("smoke");
});
test("5. seed.secrets exposes ctx.secrets.require", async ({
request,
}) => {
const res = await request.get("/api/secret");
expect(res.status()).toBe(200);
const body = (await res.json()) as { name: string; length: number };
expect(body.name).toBe("SMOKE_TOKEN");
expect(body.length).toBe("shh-very-secret-smoke".length);
});
test("6. ctx.db round-trips a real bun:sqlite write/read", async ({
request,
}) => {
const res = await request.get("/api/db", {
headers: { "X-Tenant-Id": "smoke-tenant" },
});
expect(res.status()).toBe(200);
const body = (await res.json()) as {
ok: boolean;
count: number;
first: string | null;
};
expect(body.ok).toBe(true);
expect(body.count).toBeGreaterThanOrEqual(1);
expect(body.first).toBe("hello");
});
test("7. handler emits an event observable via the in-memory bus", async ({
request,
}) => {
// Fire-and-forget — the in-memory bus captures the publish in
// history, so a subsequent endpoint (or `waitForEvent` in a
// shared-process consumer) can resolve against it.
const res = await request.get("/api/events/emit");
expect(res.status()).toBe(200);
const body = (await res.json()) as { ok: boolean; topic: string };
expect(body.ok).toBe(true);
expect(body.topic).toBe("smoke.events.fired");
});
test("8. host serves /internal/livez during the smoke", async ({
request,
}) => {
const res = await request.get("/internal/livez");
expect(res.status()).toBe(200);
const body = await res.text();
expect(body).toBe("ok");
});
});