test: add initial unit integration and e2e coverage

Adds the initial testing baseline for the project:

   Unit coverage:
   - Zod schemas for items, assignments, movements, categories, auth, recipients, users, and assets
   - password hashing and verification helpers
   - auth role helper functions

   Integration coverage with PostgreSQL Testcontainers:
   - item use-cases: create, duplicate names, delete constraints
   - assignment use-cases: create, insufficient stock, return, double return
   - asset use-cases: available/assigned creation and lifecycle transitions
   - user use-cases: create/update, uniqueness, admin safeguards, password reset
   - category use-cases: create/update/delete constraints
   - recipient use-cases: create/update and uniqueness constraints

   E2E smoke coverage with Playwright:
   - unauthenticated redirect to login
   - seeded admin login
   - dashboard load
   - admin users page
   - inventory items page
   - assignments page

   Also configures:
   - Vitest
   - Playwright
   - PostgreSQL Testcontainers helpers
   - deterministic E2E admin bootstrap
   - test artifact ignores

   Validation:
   - bun run test: 9 files / 37 tests passed
   - bun run test:e2e: 3 passed
   - bunx tsc --noEmit: passed
   - bunx prisma validate: passed
This commit is contained in:
2026-06-07 04:14:01 +02:00
parent cb01f4f8ef
commit f2b9239d82
18 changed files with 2372 additions and 9 deletions
@@ -0,0 +1,170 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
import type { PrismaClient } from "@/generated/prisma/client"
import { createTestRecipient } from "../helpers/factories"
import {
resetIntegrationTestDatabase,
startIntegrationTestDatabase,
stopIntegrationTestDatabase,
} from "../helpers/test-db"
let prisma: PrismaClient
let createRecipientUseCase: typeof import("@/use-cases/recipient.use-cases").createRecipientUseCase
let updateRecipientUseCase: typeof import("@/use-cases/recipient.use-cases").updateRecipientUseCase
beforeAll(async () => {
await startIntegrationTestDatabase()
const prismaModule = await import("@/lib/prisma")
const recipientUseCases = await import("@/use-cases/recipient.use-cases")
prisma = prismaModule.prisma
createRecipientUseCase = recipientUseCases.createRecipientUseCase
updateRecipientUseCase = recipientUseCases.updateRecipientUseCase
})
beforeEach(async () => {
await resetIntegrationTestDatabase(prisma)
})
afterAll(async () => {
await prisma?.$disconnect()
await stopIntegrationTestDatabase()
})
describe("recipient use-cases", () => {
it("creates a recipient and normalizes empty optional contact fields to null", async () => {
await expect(
createRecipientUseCase({
username: "recipient-one",
firstName: "Recipient",
lastName: "One",
department: "IT",
email: "",
phone: "",
}),
).resolves.toEqual({ success: true })
await expect(
prisma.recipient.findUniqueOrThrow({
where: { username: "recipient-one" },
}),
).resolves.toMatchObject({
username: "recipient-one",
firstName: "Recipient",
lastName: "One",
department: "IT",
email: null,
phone: null,
})
})
it("rejects duplicate usernames and duplicate emails on create", async () => {
await createTestRecipient(prisma, {
username: "existing-recipient",
email: "existing-recipient@example.test",
})
await expect(
createRecipientUseCase({
username: "existing-recipient",
firstName: "Duplicate",
lastName: "Username",
department: "OTHER",
email: "unique-recipient@example.test",
phone: null,
}),
).resolves.toEqual({
success: false,
errors: { username: ["Username already exists"] },
})
await expect(
createRecipientUseCase({
username: "unique-recipient",
firstName: "Duplicate",
lastName: "Email",
department: "OTHER",
email: "existing-recipient@example.test",
phone: null,
}),
).resolves.toEqual({
success: false,
errors: { email: ["Email already exists"] },
})
await expect(prisma.recipient.count()).resolves.toBe(1)
})
it("updates a recipient and rejects duplicate usernames or emails", async () => {
const recipient = await createTestRecipient(prisma, {
username: "editable-recipient",
email: "editable-recipient@example.test",
phone: "111111111",
})
const other = await createTestRecipient(prisma, {
username: "other-recipient",
email: "other-recipient@example.test",
})
await expect(
updateRecipientUseCase({
id: recipient.id,
username: "edited-recipient",
firstName: "Edited",
lastName: "Recipient",
department: "ENGINEERING",
email: "edited-recipient@example.test",
phone: "222222222",
}),
).resolves.toEqual({ success: true })
await expect(
prisma.recipient.findUniqueOrThrow({ where: { id: recipient.id } }),
).resolves.toMatchObject({
username: "edited-recipient",
firstName: "Edited",
lastName: "Recipient",
department: "ENGINEERING",
email: "edited-recipient@example.test",
phone: "222222222",
})
await expect(
updateRecipientUseCase({
id: recipient.id,
username: other.username,
firstName: "Edited",
lastName: "Recipient",
department: "ENGINEERING",
email: "new-recipient@example.test",
phone: "222222222",
}),
).resolves.toEqual({
success: false,
errors: { username: ["Username already exists"] },
})
await expect(
updateRecipientUseCase({
id: recipient.id,
username: "edited-recipient",
firstName: "Edited",
lastName: "Recipient",
department: "ENGINEERING",
email: other.email,
phone: "222222222",
}),
).resolves.toEqual({
success: false,
errors: { email: ["Email already exists"] },
})
await expect(
prisma.recipient.findUniqueOrThrow({ where: { id: recipient.id } }),
).resolves.toMatchObject({
username: "edited-recipient",
email: "edited-recipient@example.test",
})
await expect(prisma.recipient.count()).resolves.toBe(2)
})
})