/** * Self-conformance for the `TenantResolver` contract: the jwt resolver MUST * (a) expose a non-empty `id`, (b) return `Promise` * shape on every call, (c) never mutate the inbound `Request`, (d) be safe * to call concurrently across many requests sharing the same factory. * * `@suaveplan/api-types/tenant-resolver` does not (yet) ship a conformance * harness; this file stands in as one. */ import type { Principal, PrincipalId, Scope, } from "@suaveplan/api-types/principal"; import type { TenantId } from "@suaveplan/api-types/tenant"; import type { TenantResolver } from "@suaveplan/api-types/tenant-resolver"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { createJwtTenantResolver } from "../src/resolver/resolver.js"; function principal(tenantId: string | undefined): Principal { return { id: "u" as PrincipalId, scopes: [] as readonly Scope[], tenantId: tenantId as TenantId | undefined, claims: {}, }; } function makeRequest(p: Principal | null): Request { const req = new Request(`https://example.com/${Math.random()}`); Object.defineProperty(req, "principal", { value: p, enumerable: true }); return req; } describe("TenantResolver conformance — jwt", () => { const factory = (): TenantResolver => createJwtTenantResolver(); it("exposes a non-empty id", { timeout: 5000 }, () => { expect(factory().id.length).toBeGreaterThan(0); }); it("returns a TenantContext when claim is present", { timeout: 5000, }, async () => { const ctx = await factory().resolve(makeRequest(principal("t1"))); expect(ctx).not.toBeNull(); expect(ctx?.id).toBe("t1"); expect(typeof ctx?.slug).toBe("string"); }); it("returns null (chain advance) when claim is absent", { timeout: 5000, }, async () => { expect( await factory().resolve(makeRequest(principal(undefined))) ).toBeNull(); }); it("does not mutate the inbound Request", { timeout: 5000 }, async () => { const req = makeRequest(principal("t2")); const before = Object.keys(req).sort(); await factory().resolve(req); expect(Object.keys(req).sort()).toEqual(before); }); it("is safe to call concurrently", { timeout: 5000 }, async () => { const resolver = factory(); const results = await Promise.all( Array.from({ length: 32 }, (_, i) => resolver.resolve(makeRequest(principal(`t${i}`))) ) ); expect(results).toHaveLength(32); for (const [i, ctx] of results.entries()) { expect(ctx?.id).toBe(`t${i}`); } }); });