feat(auth): align login and bootstrap with new user schema
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
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",
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user