diff --git a/tests/unit/app/movements/movement-pages.test.ts b/tests/unit/app/movements/movement-pages.test.ts new file mode 100644 index 0000000..352ed34 --- /dev/null +++ b/tests/unit/app/movements/movement-pages.test.ts @@ -0,0 +1,132 @@ +import { createElement } from "react" +import { renderToStaticMarkup } from "react-dom/server" +import { beforeEach, describe, expect, it, vi } from "vitest" +import { es } from "@/i18n/dictionaries/es" + +const mocks = vi.hoisted(() => ({ + findAll: vi.fn(), + findAllByItemId: vi.fn(), + findByIdWithCategory: vi.fn(), + findAssetsByItemId: vi.fn(), + getI18n: vi.fn(), +})) + +vi.mock("@/i18n/server", () => ({ + getI18n: mocks.getI18n, +})) + +vi.mock("@/services/movement.service", () => ({ + MovementService: { + findAll: mocks.findAll, + findAllByItemId: mocks.findAllByItemId, + }, +})) + +vi.mock("@/services/item.service", () => ({ + ItemService: { + findByIdWithCategory: mocks.findByIdWithCategory, + }, +})) + +vi.mock("@/services/asset.service", () => ({ + AssetService: { + findByItemId: mocks.findAssetsByItemId, + }, +})) + +vi.mock("@/components/common/pagination", () => ({ + default: ({ totalPages }: { totalPages: number }) => + createElement("nav", { "aria-label": "Pagination" }, totalPages), +})) + +vi.mock("@/lib/utils", async (importOriginal) => { + const actual = await importOriginal() + + return { + ...actual, + formatDate: () => "2026-06-13", + } +}) + +describe("movement pages localization", () => { + beforeEach(() => { + vi.clearAllMocks() + mocks.getI18n.mockResolvedValue({ dictionary: es, locale: "es" }) + }) + + it("renders non-empty movement list headers and type labels in Spanish without changing audit data", async () => { + const { default: MovementsPage } = await import( + "@/app/(dashboard)/movements/page" + ) + + mocks.findAll.mockResolvedValue({ + data: [ + { + id: "movement-1", + type: "ASSIGNMENT", + quantity: 2, + createdAt: new Date("2026-06-13T00:00:00.000Z"), + item: { name: "Laptop" }, + asset: { serialNumber: "SN-001" }, + recipient: { firstName: "Ada", lastName: "Lovelace" }, + }, + ], + totalPages: 1, + }) + + const html = renderToStaticMarkup( + await MovementsPage({ searchParams: Promise.resolve({}) }), + ) + + expect(html).toContain("Movimientos") + expect(html).toContain("Tipo") + expect(html).toContain("Artículo") + expect(html).toContain("Número de serie") + expect(html).toContain("Cantidad") + expect(html).toContain("Destinatario") + expect(html).toContain("Fecha") + expect(html).toContain("Asignación") + expect(html).toContain("Laptop") + expect(html).toContain("SN-001") + expect(html).toContain("Ada Lovelace") + expect(html).toContain("2026-06-13") + expect(html).not.toContain(">ASSIGNMENT<") + }) + + it("renders the item-detail movement snippet with Spanish movement-owned labels only", async () => { + const { default: ItemPage } = await import( + "@/app/(dashboard)/inventory/items/[itemId]/page" + ) + + mocks.findByIdWithCategory.mockResolvedValue({ + id: "item-1", + name: "Laptop", + stock: 3, + category: { name: "Hardware" }, + }) + mocks.findAssetsByItemId.mockResolvedValue([]) + mocks.findAllByItemId.mockResolvedValue([ + { + id: "movement-1", + type: "RETURN", + quantity: 1, + }, + ]) + + const html = renderToStaticMarkup( + await ItemPage({ params: Promise.resolve({ itemId: "item-1" }) }), + ) + + expect(html).toContain("Laptop") + expect(html).toContain("Hardware") + expect(html).toContain("Categoría") + expect(html).toContain("Stock") + expect(html).toContain("Movimientos") + expect(html).toContain("Tipo") + expect(html).toContain("Cantidad") + expect(html).toContain("Devolución") + expect(html).not.toContain(">RETURN<") + expect(html).not.toContain("Serial Number") + expect(html).not.toContain("Delivery Note") + }) +})