refactor: rename recipients route to people, update all frontend references
This commit is contained in:
@@ -23,8 +23,8 @@ vi.mock("@/i18n/server", () => ({
|
||||
getI18n: mocks.getI18n,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/recipient.service", () => ({
|
||||
RecipientService: {
|
||||
vi.mock("@/services/person.service", () => ({
|
||||
PersonService: {
|
||||
findAll: mocks.findAllRecipients,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { en } from "@/i18n/dictionaries/en"
|
||||
import { es } from "@/i18n/dictionaries/es"
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
getI18n: vi.fn(),
|
||||
findById: vi.fn(),
|
||||
createNewPerson: vi.fn(),
|
||||
updatePerson: vi.fn(),
|
||||
push: vi.fn(),
|
||||
toastError: vi.fn(),
|
||||
toastSuccess: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@/i18n/server", () => ({
|
||||
getI18n: mocks.getI18n,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/person.service", () => ({
|
||||
PersonService: {
|
||||
findById: mocks.findById,
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("@/actions/person.actions", () => ({
|
||||
createNewPerson: mocks.createNewPerson,
|
||||
updatePerson: mocks.updatePerson,
|
||||
}))
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({
|
||||
push: mocks.push,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock("sonner", () => ({
|
||||
toast: {
|
||||
error: mocks.toastError,
|
||||
success: mocks.toastSuccess,
|
||||
},
|
||||
}))
|
||||
|
||||
describe("person form pages", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mocks.getI18n.mockResolvedValue({ dictionary: es, locale: "es" })
|
||||
})
|
||||
|
||||
it("renders the new person page with Person form copy and no username field", async () => {
|
||||
const { default: NewPersonPage } = await import(
|
||||
"@/app/(dashboard)/people/new/page"
|
||||
)
|
||||
|
||||
const html = renderToStaticMarkup(await NewPersonPage())
|
||||
|
||||
// Person form, not Recipient
|
||||
expect(html).toContain("Agregar persona")
|
||||
// No username label or placeholder
|
||||
expect(html).not.toContain("Usuario")
|
||||
expect(html).not.toContain('placeholder="Usuario"')
|
||||
// Has expected person form fields
|
||||
expect(html).toContain("Nombre")
|
||||
expect(html).toContain("Apellido")
|
||||
expect(html).toContain("Selecciona un departamento")
|
||||
expect(html).toContain('option value="ENGINEERING"')
|
||||
expect(html).toContain(">Ingeniería</option>")
|
||||
// Has department options from PERSON_DEPARTMENTS
|
||||
expect(html).toContain("Correo electrónico")
|
||||
expect(html).toContain("Teléfono")
|
||||
expect(html).toContain("Crear persona")
|
||||
})
|
||||
|
||||
it("renders the edit person page with Person heading and no username", async () => {
|
||||
const { default: PersonEditPage } = await import(
|
||||
"@/app/(dashboard)/people/[personId]/edit/page"
|
||||
)
|
||||
|
||||
mocks.findById.mockResolvedValue({
|
||||
id: "person-1",
|
||||
firstName: "Ada",
|
||||
lastName: "Lovelace",
|
||||
email: "ada@example.test",
|
||||
phone: "1234",
|
||||
department: "ENGINEERING",
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PersonEditPage({
|
||||
params: Promise.resolve({ personId: "person-1" }),
|
||||
}),
|
||||
)
|
||||
|
||||
expect(html).toContain("Editar persona")
|
||||
expect(html).toContain("Actualizar persona")
|
||||
expect(html).not.toContain("Usuario")
|
||||
})
|
||||
|
||||
it("renders a Person not-found message on edit page", async () => {
|
||||
const { default: PersonEditPage } = await import(
|
||||
"@/app/(dashboard)/people/[personId]/edit/page"
|
||||
)
|
||||
|
||||
mocks.findById.mockResolvedValue(null)
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PersonEditPage({
|
||||
params: Promise.resolve({ personId: "missing-person" }),
|
||||
}),
|
||||
)
|
||||
|
||||
expect(html).toContain("Persona no encontrada")
|
||||
})
|
||||
|
||||
it("wires English Person form submit copy through the new page", async () => {
|
||||
const { default: NewPersonPage } = await import(
|
||||
"@/app/(dashboard)/people/new/page"
|
||||
)
|
||||
|
||||
mocks.getI18n.mockResolvedValueOnce({ dictionary: en, locale: "en" })
|
||||
|
||||
const html = renderToStaticMarkup(await NewPersonPage())
|
||||
|
||||
expect(html).toContain("Create Person")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,81 @@
|
||||
import { createElement } from "react"
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { en } from "@/i18n/dictionaries/en"
|
||||
import { es } from "@/i18n/dictionaries/es"
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
getI18n: vi.fn(),
|
||||
findById: vi.fn(),
|
||||
personForm: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@/i18n/server", () => ({
|
||||
getI18n: mocks.getI18n,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/person.service", () => ({
|
||||
PersonService: {
|
||||
findById: mocks.findById,
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("@/app/(dashboard)/people/_components/person.form", () => ({
|
||||
default: (props: unknown) => {
|
||||
mocks.personForm(props)
|
||||
return createElement("div", null, "Person form")
|
||||
},
|
||||
}))
|
||||
|
||||
describe("person form schema wiring", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it("passes server-resolved Person schema copy into the new person form boundary", async () => {
|
||||
mocks.getI18n.mockResolvedValue({ dictionary: es, locale: "es" })
|
||||
|
||||
const { default: NewPersonPage } = await import(
|
||||
"@/app/(dashboard)/people/new/page"
|
||||
)
|
||||
|
||||
renderToStaticMarkup(await NewPersonPage())
|
||||
|
||||
expect(mocks.personForm).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
mode: "create",
|
||||
schemaCopy: es.inventory.people.schema,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it("passes server-resolved Person schema copy into the edit person form boundary", async () => {
|
||||
mocks.getI18n.mockResolvedValue({ dictionary: en, locale: "en" })
|
||||
mocks.findById.mockResolvedValue({
|
||||
id: "person-1",
|
||||
firstName: "Ada",
|
||||
lastName: "Lovelace",
|
||||
department: "ENGINEERING",
|
||||
email: "ada@example.test",
|
||||
phone: "1234",
|
||||
})
|
||||
|
||||
const { default: PersonEditPage } = await import(
|
||||
"@/app/(dashboard)/people/[personId]/edit/page"
|
||||
)
|
||||
|
||||
renderToStaticMarkup(
|
||||
await PersonEditPage({
|
||||
params: Promise.resolve({ personId: "person-1" }),
|
||||
}),
|
||||
)
|
||||
|
||||
expect(mocks.personForm).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
mode: "edit",
|
||||
schemaCopy: en.inventory.people.schema,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,163 @@
|
||||
import { createElement } from "react"
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { en } from "@/i18n/dictionaries/en"
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
findAllPaginated: vi.fn(),
|
||||
findById: vi.fn(),
|
||||
findAllByPerson: vi.fn(),
|
||||
getI18n: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@/i18n/server", () => ({
|
||||
getI18n: mocks.getI18n,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/person.service", () => ({
|
||||
PersonService: {
|
||||
findAllPaginated: mocks.findAllPaginated,
|
||||
findById: mocks.findById,
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("@/services/assignment.service", () => ({
|
||||
AssignmentService: {
|
||||
findAllByPerson: mocks.findAllByPerson,
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("@/components/common/pageheader", () => ({
|
||||
default: ({ title, addLabel }: { title: string; addLabel?: string }) =>
|
||||
createElement(
|
||||
"header",
|
||||
null,
|
||||
[title, addLabel].filter(Boolean).join(" | "),
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock("@/components/common/pagination", () => ({
|
||||
default: ({ totalPages }: { totalPages: number }) =>
|
||||
createElement("nav", { "aria-label": "Pagination" }, totalPages),
|
||||
}))
|
||||
|
||||
describe("person pages", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mocks.getI18n.mockResolvedValue({ dictionary: en, locale: "en" })
|
||||
})
|
||||
|
||||
it("renders the person list page with Person data and no username column", async () => {
|
||||
const { default: PeoplePage } = await import(
|
||||
"@/app/(dashboard)/people/page"
|
||||
)
|
||||
|
||||
mocks.findAllPaginated.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
id: "person-1",
|
||||
firstName: "Ada",
|
||||
lastName: "Lovelace",
|
||||
email: "ada@example.test",
|
||||
phone: "1234",
|
||||
department: "ENGINEERING",
|
||||
},
|
||||
],
|
||||
totalPages: 1,
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PeoplePage({ searchParams: Promise.resolve({}) }),
|
||||
)
|
||||
|
||||
// Uses Person copy (inventory.people), not Recipient copy
|
||||
expect(html).toContain("People")
|
||||
expect(html).toContain("Add Person")
|
||||
// No username column — username header must not appear
|
||||
expect(html).not.toContain("Username")
|
||||
// No standalone username cell — only name, email, phone, department columns
|
||||
expect(html).not.toContain(">ada<")
|
||||
// Name and other fields rendered
|
||||
expect(html).toContain("Ada Lovelace")
|
||||
expect(html).toContain("Engineering")
|
||||
// Links point to /people, not /recipients
|
||||
expect(html).toContain("/people/person-1")
|
||||
expect(html).toContain("/people/person-1/edit")
|
||||
})
|
||||
|
||||
it("renders the person list empty state from Person copy", async () => {
|
||||
const { default: PeoplePage } = await import(
|
||||
"@/app/(dashboard)/people/page"
|
||||
)
|
||||
|
||||
mocks.findAllPaginated.mockResolvedValue({
|
||||
data: [],
|
||||
totalPages: 0,
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PeoplePage({ searchParams: Promise.resolve({}) }),
|
||||
)
|
||||
|
||||
expect(html).toContain("No people found.")
|
||||
})
|
||||
|
||||
it("renders person detail page without username and uses PersonService + AssignmentService.findAllByPerson", async () => {
|
||||
const { default: PersonInfoPage } = await import(
|
||||
"@/app/(dashboard)/people/[personId]/page"
|
||||
)
|
||||
|
||||
mocks.findById.mockResolvedValue({
|
||||
id: "person-1",
|
||||
firstName: "Ada",
|
||||
lastName: "Lovelace",
|
||||
email: "ada@example.test",
|
||||
phone: "1234",
|
||||
department: "DRIVER",
|
||||
})
|
||||
mocks.findAllByPerson.mockResolvedValue([
|
||||
{
|
||||
id: "assignment-1",
|
||||
item: { name: "Laptop" },
|
||||
asset: { serialNumber: "SN-001" },
|
||||
quantity: 1,
|
||||
},
|
||||
])
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PersonInfoPage({
|
||||
params: Promise.resolve({ personId: "person-1" }),
|
||||
}),
|
||||
)
|
||||
|
||||
// No username label or value
|
||||
expect(html).not.toContain("Username")
|
||||
expect(html).not.toContain(">ada<")
|
||||
// Person detail fields
|
||||
expect(html).toContain("Email")
|
||||
expect(html).toContain("Phone")
|
||||
expect(html).toContain("Department")
|
||||
expect(html).toContain("ada@example.test")
|
||||
expect(html).toContain("Driver")
|
||||
// Embedded assignments
|
||||
expect(html).toContain("Laptop")
|
||||
})
|
||||
|
||||
it("renders person detail not-found from Person copy", async () => {
|
||||
const { default: PersonInfoPage } = await import(
|
||||
"@/app/(dashboard)/people/[personId]/page"
|
||||
)
|
||||
|
||||
mocks.findById.mockResolvedValue(null)
|
||||
mocks.findAllByPerson.mockResolvedValue([])
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
await PersonInfoPage({
|
||||
params: Promise.resolve({ personId: "missing-person" }),
|
||||
}),
|
||||
)
|
||||
|
||||
expect(html).toContain("Person not found")
|
||||
})
|
||||
})
|
||||
@@ -53,6 +53,7 @@ describe("i18n dictionaries", () => {
|
||||
categories: "Categories",
|
||||
assets: "Assets",
|
||||
recipients: "Recipients",
|
||||
people: "People",
|
||||
movements: "Movements",
|
||||
assignments: "Assignments",
|
||||
users: "Users",
|
||||
@@ -67,6 +68,7 @@ describe("i18n dictionaries", () => {
|
||||
item: "Item",
|
||||
asset: "Asset",
|
||||
recipient: "Recipient",
|
||||
person: "Person",
|
||||
assignment: "Assignment",
|
||||
},
|
||||
resetDatabase: {
|
||||
@@ -88,6 +90,7 @@ describe("i18n dictionaries", () => {
|
||||
categories: "Categorías",
|
||||
assets: "Activos",
|
||||
recipients: "Destinatarios",
|
||||
people: "Personas",
|
||||
movements: "Movimientos",
|
||||
assignments: "Asignaciones",
|
||||
users: "Usuarios",
|
||||
@@ -102,6 +105,7 @@ describe("i18n dictionaries", () => {
|
||||
item: "Artículo",
|
||||
asset: "Activo",
|
||||
recipient: "Destinatario",
|
||||
person: "Persona",
|
||||
assignment: "Asignación",
|
||||
},
|
||||
resetDatabase: {
|
||||
@@ -940,6 +944,10 @@ describe("i18n dictionaries", () => {
|
||||
title: "Total Recipients",
|
||||
countLabel: "Total",
|
||||
},
|
||||
people: {
|
||||
title: "Total People",
|
||||
countLabel: "Total",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -958,6 +966,10 @@ describe("i18n dictionaries", () => {
|
||||
title: "Total de destinatarios",
|
||||
countLabel: "Total",
|
||||
},
|
||||
people: {
|
||||
title: "Total de personas",
|
||||
countLabel: "Total",
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user