refactor: rename Recipient to Person, remove username, add userId FK

This commit is contained in:
2026-06-16 10:04:24 +02:00
parent befe1f3f82
commit d67f31cf54
27 changed files with 751 additions and 628 deletions
@@ -0,0 +1,190 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
import type { PrismaClient } from "@/generated/prisma/client"
import { createTestPerson, createTestUser } from "../helpers/factories"
import {
resetIntegrationTestDatabase,
startIntegrationTestDatabase,
stopIntegrationTestDatabase,
} from "../helpers/test-db"
let prisma: PrismaClient
let createPersonUseCase: typeof import("@/use-cases/person.use-cases").createPersonUseCase
let updatePersonUseCase: typeof import("@/use-cases/person.use-cases").updatePersonUseCase
beforeAll(async () => {
await startIntegrationTestDatabase()
const prismaModule = await import("@/lib/prisma")
const personUseCases = await import("@/use-cases/person.use-cases")
prisma = prismaModule.prisma
createPersonUseCase = personUseCases.createPersonUseCase
updatePersonUseCase = personUseCases.updatePersonUseCase
})
beforeEach(async () => {
await resetIntegrationTestDatabase(prisma)
})
afterAll(async () => {
await prisma?.$disconnect()
await stopIntegrationTestDatabase()
})
describe("person use-cases", () => {
it("creates a person and normalizes empty optional contact fields to null", async () => {
await expect(
createPersonUseCase({
firstName: "Person",
lastName: "One",
department: "IT",
email: "",
phone: "",
}),
).resolves.toEqual({ success: true })
await expect(
prisma.person.findFirstOrThrow({
where: { firstName: "Person", lastName: "One" },
}),
).resolves.toMatchObject({
firstName: "Person",
lastName: "One",
department: "IT",
email: null,
phone: null,
userId: null,
})
})
it("creates a person with linked userId", async () => {
const user = await createTestUser(prisma)
await expect(
createPersonUseCase({
firstName: "Linked",
lastName: "Person",
department: "ENGINEERING",
email: "linked@example.test",
phone: null,
userId: user.id,
}),
).resolves.toEqual({ success: true })
await expect(
prisma.person.findFirstOrThrow({
where: { firstName: "Linked" },
}),
).resolves.toMatchObject({
firstName: "Linked",
lastName: "Person",
department: "ENGINEERING",
email: "linked@example.test",
userId: user.id,
})
})
it("rejects duplicate emails on create", async () => {
await createTestPerson(prisma, {
email: "existing@example.test",
})
await expect(
createPersonUseCase({
firstName: "Duplicate",
lastName: "Email",
department: "OTHER",
email: "existing@example.test",
phone: null,
}),
).resolves.toEqual({
success: false,
errors: { email: ["Email already exists"] },
})
await expect(prisma.person.count()).resolves.toBe(1)
})
it("updates a person and rejects duplicate emails", async () => {
const person = await createTestPerson(prisma, {
email: "person@example.test",
phone: "111111111",
})
const other = await createTestPerson(prisma, {
email: "other@example.test",
})
await expect(
updatePersonUseCase({
id: person.id,
firstName: "Edited",
lastName: "Person",
department: "ENGINEERING",
email: "edited@example.test",
phone: "222222222",
}),
).resolves.toEqual({ success: true })
await expect(
prisma.person.findUniqueOrThrow({ where: { id: person.id } }),
).resolves.toMatchObject({
firstName: "Edited",
lastName: "Person",
department: "ENGINEERING",
email: "edited@example.test",
phone: "222222222",
})
await expect(
updatePersonUseCase({
id: person.id,
firstName: "Edited",
lastName: "Person",
department: "ENGINEERING",
email: other.email,
phone: "222222222",
}),
).resolves.toEqual({
success: false,
errors: { email: ["Email already exists"] },
})
await expect(
prisma.person.findUniqueOrThrow({ where: { id: person.id } }),
).resolves.toMatchObject({
email: "edited@example.test",
})
await expect(prisma.person.count()).resolves.toBe(2)
})
it("searches by email and name in paginated results", async () => {
await createTestPerson(prisma, {
firstName: "Alice",
lastName: "Smith",
email: "alice@company.com",
})
await createTestPerson(prisma, {
firstName: "Bob",
lastName: "Jones",
email: "bob@other.com",
})
const { PersonService } = await import("@/services/person.service")
const emailResults = await PersonService.findAllPaginated({
search: "company",
page: 1,
pageSize: 10,
})
expect(emailResults.data).toHaveLength(1)
expect(emailResults.data[0].firstName).toBe("Alice")
const nameResults = await PersonService.findAllPaginated({
search: "Bob",
page: 1,
pageSize: 10,
})
expect(nameResults.data).toHaveLength(1)
expect(nameResults.data[0].firstName).toBe("Bob")
})
})