import { describe, expect, it } from "vitest"; import { createApp } from "../app.js"; import { loadEnv } from "../env.js"; import type { ErrorEnvelope } from "../http.js"; import { createFakeDb, emptyStore, SEED } from "../test/fake-db.js"; function expectEnvelope(body: unknown, code: string) { const envelope = body as ErrorEnvelope; expect(envelope.error.code).toBe(code); } function adminEnv() { return loadEnv({ NODE_ENV: "test", DEV_AUTH_BYPASS: "true", DEV_AUTH_SUB: SEED.user.cognitoSub, DEV_AUTH_EMAIL: SEED.user.email, DEV_AUTH_NAME: SEED.user.name, DEV_AUTH_ROLE: "admin", }); } function viewerEnv() { return loadEnv({ NODE_ENV: "test", DEV_AUTH_BYPASS: "true", DEV_AUTH_SUB: SEED.user.cognitoSub, DEV_AUTH_EMAIL: SEED.user.email, DEV_AUTH_NAME: SEED.user.name, DEV_AUTH_ROLE: "viewer", }); } describe("master data stubs", () => { it("lists and gets seeded vendors", async () => { const app = createApp(adminEnv(), createFakeDb()); const list = await app.request("/api/vendors"); expect(list.status).toBe(200); const listed = (await list.json()) as { items: Array<{ id: string; name: string }> }; expect(listed.items[0]?.id).toBe(SEED.vendor.id); const get = await app.request(`/api/vendors/${SEED.vendor.id}`); expect(get.status).toBe(200); await expect(get.json()).resolves.toMatchObject({ id: SEED.vendor.id, name: SEED.vendor.name }); }); it("creates a vendor and returns 201", async () => { const app = createApp(adminEnv(), createFakeDb()); const response = await app.request("/api/vendors", { method: "POST", headers: { "content-type": "application/json", origin: "http://127.0.0.1:3000" }, body: JSON.stringify({ name: "Harbor Maintenance", defaultPaymentMethod: "ach" }), }); expect(response.status).toBe(201); await expect(response.json()).resolves.toMatchObject({ name: "Harbor Maintenance", defaultPaymentMethod: "ach", }); }); it("returns 404 for a missing vendor", async () => { const store = emptyStore(); store.vendors = []; const app = createApp(adminEnv(), createFakeDb(store)); const response = await app.request(`/api/vendors/${SEED.vendor.id}`); expect(response.status).toBe(404); expectEnvelope(await response.json(), "NOT_FOUND"); }); it("returns 403 when a non-admin writes vendors", async () => { const app = createApp(viewerEnv(), createFakeDb()); const response = await app.request("/api/vendors", { method: "POST", headers: { "content-type": "application/json", origin: "http://127.0.0.1:3000" }, body: JSON.stringify({ name: "Nope" }), }); expect(response.status).toBe(403); expectEnvelope(await response.json(), "FORBIDDEN"); }); it("lists GL accounts and departments", async () => { const app = createApp(adminEnv(), createFakeDb()); const gl = await app.request("/api/gl-accounts"); expect(gl.status).toBe(200); const glBody = (await gl.json()) as { items: Array<{ code: string }> }; expect(glBody.items[0]?.code).toBe("6100"); const departments = await app.request("/api/departments"); expect(departments.status).toBe(200); const deptBody = (await departments.json()) as { items: Array<{ code: string }> }; expect(deptBody.items[0]?.code).toBe("OPS"); }); it("updates a user role", async () => { const app = createApp(adminEnv(), createFakeDb()); const response = await app.request(`/api/users/${SEED.user.id}`, { method: "PATCH", headers: { "content-type": "application/json", origin: "http://127.0.0.1:3000" }, body: JSON.stringify({ role: "approver" }), }); expect(response.status).toBe(200); await expect(response.json()).resolves.toMatchObject({ role: "approver" }); }); });