import { beforeEach, describe, expect, it, vi } from "vitest" const { mockDb } = vi.hoisted(() => ({ mockDb: { page: { create: vi.fn(), update: vi.fn(), delete: vi.fn(), findUnique: vi.fn(), findFirst: vi.fn(), findMany: vi.fn(), }, pageTranslation: { upsert: vi.fn(), findMany: vi.fn(), }, navigationMenu: { create: vi.fn(), findMany: vi.fn(), findFirst: vi.fn(), }, navigationItem: { create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, navigationItemTranslation: { upsert: vi.fn(), }, }, })) vi.mock("./client", () => ({ db: mockDb, })) import { createNavigationItem, createNavigationMenu, createPage, getPublishedPageBySlugForLocale, listPublicNavigation, updatePage, upsertNavigationItemTranslation, upsertPageTranslation, } from "./pages-navigation" describe("pages-navigation service", () => { beforeEach(() => { for (const value of Object.values(mockDb)) { for (const fn of Object.values(value)) { if (typeof fn === "function") { fn.mockReset() } } } }) it("creates published pages with publishedAt", async () => { mockDb.page.create.mockResolvedValue({ id: "page-1" }) await createPage({ title: "About", slug: "about", status: "published", content: "hello", }) expect(mockDb.page.create).toHaveBeenCalledTimes(1) expect(mockDb.page.create.mock.calls[0]?.[0].data.publishedAt).toBeInstanceOf(Date) }) it("updates page status publication timestamp", async () => { mockDb.page.update.mockResolvedValue({ id: "page-1" }) await updatePage({ id: "550e8400-e29b-41d4-a716-446655440000", status: "draft", }) expect(mockDb.page.update).toHaveBeenCalledTimes(1) expect(mockDb.page.update.mock.calls[0]?.[0].data.publishedAt).toBeNull() }) it("creates menus and items with schema parsing", async () => { mockDb.navigationMenu.create.mockResolvedValue({ id: "menu-1" }) mockDb.navigationItem.create.mockResolvedValue({ id: "item-1" }) await createNavigationMenu({ name: "Primary", slug: "primary", location: "header", }) await createNavigationItem({ menuId: "550e8400-e29b-41d4-a716-446655440001", label: "Home", href: "/", sortOrder: 0, }) expect(mockDb.navigationMenu.create).toHaveBeenCalledTimes(1) expect(mockDb.navigationItem.create).toHaveBeenCalledTimes(1) }) it("maps public navigation href from linked pages", async () => { mockDb.navigationMenu.findFirst.mockResolvedValue({ id: "menu-1", items: [ { id: "item-1", label: "Home", href: null, parentId: null, page: { slug: "home", status: "published", }, translations: [{ locale: "de", label: "Startseite" }], }, ], }) const navigation = await listPublicNavigation("header", "de") expect(navigation).toEqual([ { id: "item-1", label: "Startseite", href: "/", children: [], }, ]) }) it("validates locale when upserting navigation item translation", async () => { await expect(() => upsertNavigationItemTranslation({ navigationItemId: "550e8400-e29b-41d4-a716-446655440001", locale: "it", label: "Home", }), ).rejects.toThrow() }) it("validates locale when upserting page translation", async () => { await expect(() => upsertPageTranslation({ pageId: "550e8400-e29b-41d4-a716-446655440000", locale: "it", title: "Titolo", content: "Contenuto", }), ).rejects.toThrow() }) it("upserts page translation and reads localized page with fallback", async () => { mockDb.pageTranslation.upsert.mockResolvedValue({ id: "pt-1" }) mockDb.page.findFirst .mockResolvedValueOnce({ id: "page-1", title: "About", summary: "Base summary", content: "Base content", seoTitle: "Base SEO", seoDescription: "Base description", translations: [ { locale: "de", title: "Uber Uns", summary: "Zusammenfassung", content: "Inhalt", seoTitle: "SEO DE", seoDescription: "Beschreibung", }, ], }) .mockResolvedValueOnce({ id: "page-1", title: "About", summary: "Base summary", content: "Base content", seoTitle: "Base SEO", seoDescription: "Base description", translations: [], }) await upsertPageTranslation({ pageId: "550e8400-e29b-41d4-a716-446655440000", locale: "de", title: "Uber Uns", content: "Inhalt", }) const translated = await getPublishedPageBySlugForLocale("about", "de") const fallback = await getPublishedPageBySlugForLocale("about", "fr") expect(mockDb.pageTranslation.upsert).toHaveBeenCalledTimes(1) expect(translated?.title).toBe("Uber Uns") expect(translated?.content).toBe("Inhalt") expect(fallback?.title).toBe("About") expect(fallback?.content).toBe("Base content") }) })