feat(teams): add team service and use-cases with integration tests

This commit is contained in:
2026-06-26 00:03:01 +02:00
parent f88d831f4c
commit 5d303bdb7e
7 changed files with 375 additions and 0 deletions
+13
View File
@@ -77,6 +77,19 @@ export async function createTestPerson(
})
}
export async function createTestTeam(
prisma: PrismaClient,
overrides: Partial<{ name: string }> = {},
) {
const suffix = nextSuffix()
return prisma.team.create({
data: {
name: overrides.name ?? `Test Team ${suffix}`,
},
})
}
export async function createTestItem(
prisma: PrismaClient,
overrides: Partial<{
+1
View File
@@ -18,6 +18,7 @@ const TABLES_TO_TRUNCATE = [
"Asset",
"Item",
"Category",
"Team",
"Person",
"User",
]
@@ -0,0 +1,175 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
import type { PrismaClient } from "@/generated/prisma/client"
import { createTestPerson, createTestTeam } from "../helpers/factories"
import {
resetIntegrationTestDatabase,
startIntegrationTestDatabase,
stopIntegrationTestDatabase,
} from "../helpers/test-db"
let prisma: PrismaClient
let createTeamUseCase: typeof import("@/use-cases/team.use-cases").createTeamUseCase
let updateTeamUseCase: typeof import("@/use-cases/team.use-cases").updateTeamUseCase
let deleteTeamUseCase: typeof import("@/use-cases/team.use-cases").deleteTeamUseCase
let listTeamsUseCase: typeof import("@/use-cases/team.use-cases").listTeamsUseCase
let TeamService: typeof import("@/services/team.service").TeamService
beforeAll(async () => {
await startIntegrationTestDatabase()
const prismaModule = await import("@/lib/prisma")
const teamUseCases = await import("@/use-cases/team.use-cases")
const teamService = await import("@/services/team.service")
prisma = prismaModule.prisma
createTeamUseCase = teamUseCases.createTeamUseCase
updateTeamUseCase = teamUseCases.updateTeamUseCase
deleteTeamUseCase = teamUseCases.deleteTeamUseCase
listTeamsUseCase = teamUseCases.listTeamsUseCase
TeamService = teamService.TeamService
})
beforeEach(async () => {
await resetIntegrationTestDatabase(prisma)
})
afterAll(async () => {
await prisma?.$disconnect()
await stopIntegrationTestDatabase()
})
describe("team use-cases", () => {
it("creates a team and rejects duplicate names", async () => {
expect(await createTeamUseCase({ name: "Engineering" })).toEqual({
success: true,
})
expect(
await prisma.team.findFirst({ where: { name: "Engineering" } }),
).toMatchObject({ name: "Engineering" })
expect(await createTeamUseCase({ name: "Engineering" })).toEqual({
success: false,
errors: { name: ["Team already exists"] },
})
expect(await prisma.team.count()).toBe(1)
})
it("rejects duplicate names case-insensitively and trims whitespace", async () => {
await createTestTeam(prisma, { name: "Engineering" })
expect(await createTeamUseCase({ name: "engineering" })).toEqual({
success: false,
errors: { name: ["Team already exists"] },
})
expect(await createTeamUseCase({ name: " ENGINEERING " })).toEqual({
success: false,
errors: { name: ["Team already exists"] },
})
expect(await prisma.team.count()).toBe(1)
})
it("trims the name before saving", async () => {
await createTeamUseCase({ name: " Engineering " })
const team = await prisma.team.findFirst({
where: { name: "Engineering" },
})
expect(team).not.toBeNull()
expect(team?.name).toBe("Engineering")
})
it("updates a team and rejects unchanged or duplicate names", async () => {
const team = await createTestTeam(prisma, { name: "Peripherals" })
const other = await createTestTeam(prisma, { name: "Networking" })
expect(
await updateTeamUseCase({ id: team.id, name: "Accessories" }),
).toEqual({ success: true })
expect(
await prisma.team.findUniqueOrThrow({ where: { id: team.id } }),
).toMatchObject({ name: "Accessories" })
expect(
await updateTeamUseCase({ id: team.id, name: "Accessories" }),
).toEqual({
success: false,
errors: { name: ["Team name is the same"] },
})
expect(
await updateTeamUseCase({ id: team.id, name: other.name }),
).toEqual({
success: false,
errors: { name: ["Team already exists"] },
})
expect(
await prisma.team.findUniqueOrThrow({ where: { id: team.id } }),
).toMatchObject({ name: "Accessories" })
})
it("returns not found when updating a missing team", async () => {
expect(
await updateTeamUseCase({
id: "00000000-0000-0000-0000-000000000000",
name: "Ghost",
}),
).toEqual({
success: false,
errors: { id: ["Team not found"] },
})
})
it("hard deletes a team", async () => {
const team = await createTestTeam(prisma, { name: "Legacy" })
expect(await deleteTeamUseCase(team.id)).toEqual({ success: true })
expect(await prisma.team.findUnique({ where: { id: team.id } })).toBeNull()
})
it("returns not found when deleting a missing team", async () => {
expect(
await deleteTeamUseCase("00000000-0000-0000-0000-000000000000"),
).toEqual({
success: false,
errors: { id: ["Team not found"] },
})
})
it("nulls linked Person.teamId when a team is deleted", async () => {
const team = await createTestTeam(prisma, { name: "Assigned" })
const person = await createTestPerson(prisma)
await prisma.person.update({
where: { id: person.id },
data: { teamId: team.id },
})
expect(await deleteTeamUseCase(team.id)).toEqual({ success: true })
const updatedPerson = await prisma.person.findUnique({
where: { id: person.id },
})
expect(updatedPerson).not.toBeNull()
expect(updatedPerson?.teamId).toBeNull()
})
it("lists all teams ordered by name", async () => {
await createTestTeam(prisma, { name: "Beta" })
await createTestTeam(prisma, { name: "Alpha" })
await createTestTeam(prisma, { name: "Gamma" })
const teams = await listTeamsUseCase()
expect(teams).toHaveLength(3)
expect(teams.map((team) => team.name)).toEqual(["Alpha", "Beta", "Gamma"])
})
})