import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { createApp } from "../../apps/api/src/app.js"; import { RegistrationService } from "../../apps/api/src/registration.js"; import { MockResendAdapter } from "../../apps/api/src/resend-adapter.js"; const fixedNow = Date.parse("2026-08-05T06:00:00.000Z"); const writeHeaders = { host: "127.0.0.1:43121", origin: "http://127.0.0.1:43121" }; const roots: string[] = []; const services: RegistrationService[] = []; function createRegistrationService() { const root = mkdtempSync(join(tmpdir(), "dada-local-test-session-")); roots.push(root); const registration = new RegistrationService({ challengePepper: Buffer.alloc(32, 0x51), clock: () => fixedNow, currentPrivacyNoticeVersion: "p0a-notice-v1", databasePath: join(root, "dada.sqlite3"), invitePepper: Buffer.alloc(32, 0x52), resend: new MockResendAdapter(), sessionPepper: Buffer.alloc(32, 0x53), }); services.push(registration); return registration; } afterEach(() => { for (const service of services.splice(0)) { try { service.close(); } catch { /* already closed by the test */ } } for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true }); }); describe("POSTV1-03 local test session", () => { it("does not expose the local test route unless explicitly enabled", async () => { const registration = createRegistrationService(); const app = await createApp({ browserGate: false, networkBoundary: { allowTestPort: true }, registration }); const status = await app.inject({ headers: writeHeaders, method: "GET", url: "/api/v1/auth/local-test" }); const created = await app.inject({ headers: writeHeaders, method: "POST", url: "/api/v1/auth/local-test" }); expect(status.statusCode).toBe(404); expect(created.statusCode).toBe(404); await app.close(); }); it("creates one isolated fixture account and restores it without duplicate credits", async () => { const registration = createRegistrationService(); const app = await createApp({ browserGate: false, localTestAuth: true, networkBoundary: { allowTestPort: true }, registration, }); const status = await app.inject({ headers: writeHeaders, method: "GET", url: "/api/v1/auth/local-test" }); expect(status.statusCode).toBe(200); expect(status.json()).toEqual({ available: true }); const first = await app.inject({ headers: writeHeaders, method: "POST", url: "/api/v1/auth/local-test" }); expect(first.statusCode).toBe(200); expect(first.json()).toMatchObject({ audience: "user", credits: { available_balance: 10, reserved_balance: 0 }, status: "authenticated", user: { creator_name: "本机测试用户", role: "user", social_id: "@dada_local_test", status: "active" }, }); expect(first.headers["set-cookie"]).toContain("dada_session="); const session = await app.inject({ headers: { cookie: first.headers["set-cookie"], host: "127.0.0.1:43121" }, method: "GET", url: "/api/v1/auth/session", }); expect(session.statusCode).toBe(200); expect(session.json()).toMatchObject({ authenticated: true, credits: { available_balance: 10 } }); const second = await app.inject({ headers: writeHeaders, method: "POST", url: "/api/v1/auth/local-test" }); expect(second.statusCode).toBe(200); expect(second.json().user.user_id).toBe(first.json().user.user_id); expect(registration.database.prepare("SELECT COUNT(*) AS count FROM users").get()).toEqual({ count: 1 }); expect(registration.database.prepare("SELECT COUNT(*) AS count FROM credit_ledger").get()).toEqual({ count: 1 }); expect(registration.database.prepare("SELECT counts_toward_stage_limit FROM users").get()).toEqual({ counts_toward_stage_limit: 0 }); const openapi = JSON.stringify(app.swagger()); expect(openapi).not.toContain("/api/v1/auth/local-test"); expect(openapi).not.toContain("local-test-user"); await app.close(); }); });