165 lines
4.3 KiB
TypeScript
165 lines
4.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest"
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
getPasswordHash: vi.fn(),
|
|
}))
|
|
|
|
vi.mock("@/lib/security", () => ({
|
|
getPasswordHash: mocks.getPasswordHash,
|
|
}))
|
|
|
|
vi.mock("../../../src/lib/prisma", () => ({
|
|
default: {},
|
|
}))
|
|
|
|
import { bootstrapAdmin } from "../../../prisma/bootstrap-admin"
|
|
|
|
describe("bootstrapAdmin", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
process.env.ADMIN_BOOTSTRAP_ENABLED = "true"
|
|
process.env.ADMIN_EMAIL = "Admin@Example.Test"
|
|
process.env.ADMIN_NAME = "E2E Admin"
|
|
process.env.ADMIN_PASSWORD = "admin-password"
|
|
vi.stubEnv("NODE_ENV", "development")
|
|
mocks.getPasswordHash.mockResolvedValue("hashed-password")
|
|
})
|
|
|
|
it("creates an active user and links a person on first run", async () => {
|
|
const userFindUnique = vi.fn().mockResolvedValue(null)
|
|
const userCreate = vi.fn().mockResolvedValue({
|
|
id: "user-1",
|
|
person: null,
|
|
})
|
|
const userUpdate = vi.fn()
|
|
const personUpsert = vi.fn().mockResolvedValue({ id: "person-1" })
|
|
|
|
const client = {
|
|
user: {
|
|
findUnique: userFindUnique,
|
|
create: userCreate,
|
|
update: userUpdate,
|
|
},
|
|
person: {
|
|
upsert: personUpsert,
|
|
},
|
|
}
|
|
|
|
await bootstrapAdmin(client as never)
|
|
|
|
expect(userFindUnique).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
where: {
|
|
emailNormalized: "admin@example.test",
|
|
},
|
|
}),
|
|
)
|
|
expect(userCreate).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
data: expect.objectContaining({
|
|
emailNormalized: "admin@example.test",
|
|
passwordHash: "hashed-password",
|
|
status: "ACTIVE",
|
|
}),
|
|
}),
|
|
)
|
|
expect(userUpdate).not.toHaveBeenCalled()
|
|
expect(personUpsert).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
where: {
|
|
userId: "user-1",
|
|
},
|
|
create: expect.objectContaining({
|
|
firstName: "E2E",
|
|
lastName: "Admin",
|
|
email: "Admin@Example.Test",
|
|
}),
|
|
update: expect.objectContaining({
|
|
firstName: "E2E",
|
|
lastName: "Admin",
|
|
email: "Admin@Example.Test",
|
|
}),
|
|
}),
|
|
)
|
|
})
|
|
|
|
it("is idempotent when the admin already has a linked person", async () => {
|
|
const userFindUnique = vi.fn().mockResolvedValue({
|
|
id: "user-1",
|
|
passwordHash: "existing-hash",
|
|
activatedAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
person: { id: "person-1" },
|
|
})
|
|
const userCreate = vi.fn()
|
|
const userUpdate = vi.fn().mockResolvedValue({
|
|
id: "user-1",
|
|
person: { id: "person-1" },
|
|
})
|
|
const personUpsert = vi.fn()
|
|
|
|
const client = {
|
|
user: {
|
|
findUnique: userFindUnique,
|
|
create: userCreate,
|
|
update: userUpdate,
|
|
},
|
|
person: {
|
|
upsert: personUpsert,
|
|
},
|
|
}
|
|
|
|
await bootstrapAdmin(client as never)
|
|
|
|
expect(mocks.getPasswordHash).not.toHaveBeenCalled()
|
|
expect(userCreate).not.toHaveBeenCalled()
|
|
expect(userUpdate).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
data: expect.not.objectContaining({
|
|
passwordHash: expect.any(String),
|
|
activatedAt: expect.any(Date),
|
|
passwordChangedAt: expect.any(Date),
|
|
}),
|
|
}),
|
|
)
|
|
expect(personUpsert).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it("links a missing person without rehashing an existing admin password", async () => {
|
|
const userFindUnique = vi.fn().mockResolvedValue({
|
|
id: "user-1",
|
|
passwordHash: "existing-hash",
|
|
activatedAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
person: null,
|
|
})
|
|
const userCreate = vi.fn()
|
|
const userUpdate = vi.fn().mockResolvedValue({
|
|
id: "user-1",
|
|
person: null,
|
|
})
|
|
const personUpsert = vi.fn().mockResolvedValue({ id: "person-1" })
|
|
|
|
const client = {
|
|
user: {
|
|
findUnique: userFindUnique,
|
|
create: userCreate,
|
|
update: userUpdate,
|
|
},
|
|
person: {
|
|
upsert: personUpsert,
|
|
},
|
|
}
|
|
|
|
await bootstrapAdmin(client as never)
|
|
|
|
expect(mocks.getPasswordHash).not.toHaveBeenCalled()
|
|
expect(userCreate).not.toHaveBeenCalled()
|
|
expect(personUpsert).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
where: {
|
|
userId: "user-1",
|
|
},
|
|
}),
|
|
)
|
|
})
|
|
})
|