Files
stock-manager/tests/integration/use-cases/update-person-user.use-cases.test.ts
T

254 lines
7.3 KiB
TypeScript

import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
import { type PrismaClient, UserStatus } from "@/generated/prisma/client"
import { normalizeEmail } from "@/lib/email"
import { getPasswordHash } from "@/lib/security"
import { createTestPerson, createTestUser } from "../helpers/factories"
import {
resetIntegrationTestDatabase,
startIntegrationTestDatabase,
stopIntegrationTestDatabase,
} from "../helpers/test-db"
let prisma: PrismaClient
let updatePersonUserUseCase: typeof import("@/use-cases/person.use-cases").updatePersonUserUseCase
beforeAll(async () => {
await startIntegrationTestDatabase()
const prismaModule = await import("@/lib/prisma")
const personUseCases = await import("@/use-cases/person.use-cases")
prisma = prismaModule.prisma
updatePersonUserUseCase = personUseCases.updatePersonUserUseCase
})
beforeEach(async () => {
await resetIntegrationTestDatabase(prisma)
})
afterAll(async () => {
await prisma?.$disconnect()
await stopIntegrationTestDatabase()
})
describe("updatePersonUserUseCase", () => {
describe("person-only update", () => {
it("updates only the Person when person has no linked User", async () => {
const person = await createTestPerson(prisma, {
firstName: "Old",
lastName: "Name",
email: "old@example.test",
})
const result = await updatePersonUserUseCase({
id: person.id,
firstName: "New",
lastName: "Name",
department: "IT",
email: "new@example.test",
phone: "1234",
})
expect(result).toEqual({ success: true })
const updated = await prisma.person.findUniqueOrThrow({
where: { id: person.id },
})
expect(updated).toMatchObject({
firstName: "New",
lastName: "Name",
department: "IT",
email: "new@example.test",
phone: "1234",
userId: null,
})
})
it("normalizes empty email to null when person has no User", async () => {
const person = await createTestPerson(prisma, { email: null })
const result = await updatePersonUserUseCase({
id: person.id,
firstName: "Empty",
lastName: "Email",
department: "OTHER",
email: "",
phone: null,
})
expect(result).toEqual({ success: true })
const updated = await prisma.person.findUniqueOrThrow({
where: { id: person.id },
})
expect(updated.email).toBeNull()
})
})
describe("person+user update", () => {
it("updates Person fields and User role/isActive when person has a User linked", async () => {
const user = await createTestUser(prisma, {
email: "user-update@example.test",
name: "Old Name",
role: "STAFF",
isActive: true,
})
const person = await createTestPerson(prisma, {
firstName: "Linked",
lastName: "Person",
email: "user-update@example.test",
})
await prisma.person.update({
where: { id: person.id },
data: { userId: user.id },
})
const result = await updatePersonUserUseCase({
id: person.id,
firstName: "Linked",
lastName: "Person",
department: "ENGINEERING",
email: "user-update@example.test",
phone: null,
role: "ADMIN",
isActive: false,
})
expect(result).toEqual({ success: true })
const updatedPerson = await prisma.person.findUniqueOrThrow({
where: { id: person.id },
include: { user: true },
})
expect(updatedPerson.department).toBe("ENGINEERING")
expect(updatedPerson.user).toMatchObject({
id: user.id,
role: "ADMIN",
status: "DISABLED",
})
})
it("resets the User password when password is provided", async () => {
const user = await createTestUser(prisma, {
email: "pw-reset@example.test",
})
const person = await createTestPerson(prisma, {
email: "pw-reset@example.test",
})
await prisma.person.update({
where: { id: person.id },
data: { userId: user.id },
})
const result = await updatePersonUserUseCase({
id: person.id,
firstName: person.firstName,
lastName: person.lastName,
department: "OTHER",
email: "pw-reset@example.test",
phone: null,
role: "STAFF",
isActive: true,
password: "new-password-1",
})
expect(result).toEqual({ success: true })
const updated = await prisma.user.findUniqueOrThrow({
where: { id: user.id },
})
const { verifyPassword } = await import("@/lib/security")
if (!updated.passwordHash) throw new Error("Expected password hash")
await expect(
verifyPassword("new-password-1", updated.passwordHash),
).resolves.toBe(true)
})
it("does not change the password when password is not provided", async () => {
const originalHash = await getPasswordHash("original-password-1")
const user = await prisma.user.create({
data: {
email: "no-pw@example.test",
emailNormalized: normalizeEmail("no-pw@example.test"),
name: "No PW",
passwordHash: originalHash,
role: "STAFF",
status: UserStatus.ACTIVE,
activatedAt: new Date(),
passwordChangedAt: new Date(),
},
})
const person = await createTestPerson(prisma, {
email: "no-pw@example.test",
})
await prisma.person.update({
where: { id: person.id },
data: { userId: user.id },
})
const result = await updatePersonUserUseCase({
id: person.id,
firstName: person.firstName,
lastName: person.lastName,
department: "OTHER",
email: "no-pw@example.test",
phone: null,
role: "STAFF",
isActive: true,
})
expect(result).toEqual({ success: true })
const updated = await prisma.user.findUniqueOrThrow({
where: { id: user.id },
})
const { verifyPassword: verify } = await import("@/lib/security")
if (!updated.passwordHash) throw new Error("Expected password hash")
await expect(
verify("original-password-1", updated.passwordHash),
).resolves.toBe(true)
})
})
describe("validation errors", () => {
it("returns error when person is not found", async () => {
const result = await updatePersonUserUseCase({
id: "nonexistent-id",
firstName: "Ghost",
lastName: "Person",
department: "OTHER",
email: "ghost@example.test",
phone: null,
})
expect(result.success).toBe(false)
if (!result.success) {
expect(result.errors.id).toBeDefined()
}
})
it("rejects duplicate email in Person table", async () => {
const person = await createTestPerson(prisma, {
email: "mine@example.test",
})
await createTestPerson(prisma, {
email: "theirs@example.test",
})
const result = await updatePersonUserUseCase({
id: person.id,
firstName: "Mine",
lastName: "Person",
department: "OTHER",
email: "theirs@example.test",
phone: null,
})
expect(result).toEqual({
success: false,
errors: { email: ["Email already exists"] },
})
})
})
})