seahaven-ap/packages/api/src/routes/master-data.test.ts

102 lines
3.7 KiB
TypeScript

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" });
});
});