205 lines
5.2 KiB
TypeScript
205 lines
5.2 KiB
TypeScript
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")
|
|
})
|
|
})
|