import { randomUUID } from "node:crypto"; import express from "express"; import request from "supertest"; import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest"; import { companies, createDb, projects } from "@paperclipai/db"; import { getEmbeddedPostgresTestSupport, startEmbeddedPostgresTestDatabase, } from "./helpers/embedded-postgres.js"; import { errorHandler } from "../middleware/index.js"; import { projectRoutes } from "../routes/projects.js"; const embeddedPostgresSupport = await getEmbeddedPostgresTestSupport(); const describeEmbeddedPostgres = embeddedPostgresSupport.supported ? describe : describe.skip; if (!embeddedPostgresSupport.supported) { console.warn( `Skipping embedded Postgres project list archived tests on this host: ${ embeddedPostgresSupport.reason ?? "unsupported environment" }`, ); } function boardActor(companyId: string): Express.Request["actor"] { return { type: "board", userId: "user-1", source: "session", isInstanceAdmin: true, companyIds: [companyId], memberships: [{ companyId, membershipRole: "admin", status: "active" }], }; } function createApp(db: ReturnType, actor: Express.Request["actor"]) { const app = express(); app.use(express.json()); app.use((req, _res, next) => { req.actor = actor; next(); }); app.use("/api", projectRoutes(db)); app.use(errorHandler); return app; } describeEmbeddedPostgres("project list archived route defaults", () => { let db!: ReturnType; let tempDb: Awaited> | null = null; beforeAll(async () => { tempDb = await startEmbeddedPostgresTestDatabase("paperclip-projects-list-archived-"); db = createDb(tempDb.connectionString); }, 20_000); afterEach(async () => { await db.delete(projects); await db.delete(companies); }); afterAll(async () => { await tempDb?.cleanup(); }); async function seed() { const companyId = randomUUID(); const activeProjectId = randomUUID(); const archivedProjectId = randomUUID(); await db.insert(companies).values({ id: companyId, name: "Paperclip", issuePrefix: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}`, requireBoardApprovalForNewAgents: false, }); await db.insert(projects).values([ { id: activeProjectId, companyId, name: "Active Project", status: "in_progress" }, { id: archivedProjectId, companyId, name: "Archived Project", status: "completed", archivedAt: new Date(), }, ]); return { activeProjectId, archivedProjectId, companyId }; } it("omits archived projects by default", async () => { const { activeProjectId, archivedProjectId, companyId } = await seed(); const app = createApp(db, boardActor(companyId)); const res = await request(app).get(`/api/companies/${companyId}/projects`); expect(res.status).toBe(200); expect(res.body.map((project: { id: string }) => project.id)).toEqual([activeProjectId]); expect(res.body.map((project: { id: string }) => project.id)).not.toContain(archivedProjectId); }); it("includes archived projects when includeArchived is true", async () => { const { activeProjectId, archivedProjectId, companyId } = await seed(); const app = createApp(db, boardActor(companyId)); const res = await request(app).get(`/api/companies/${companyId}/projects?includeArchived=true`); expect(res.status).toBe(200); expect(res.body.map((project: { id: string }) => project.id)).toEqual([activeProjectId, archivedProjectId]); }); });