322 lines
12 KiB
TypeScript
322 lines
12 KiB
TypeScript
import { SEEDED_TEST_CONTENT } from "../../fixtures/test-constants"
|
|
import { createCollectionEntry, deleteCollectionEntry, listCollectionEntries } from "./admin-api"
|
|
|
|
type ContentEntry = {
|
|
id?: string
|
|
_id?: string | { $oid?: string }
|
|
_testdata?: boolean
|
|
translationKey?: string
|
|
path?: string
|
|
[key: string]: unknown
|
|
}
|
|
|
|
function getEntryId(entry: ContentEntry): string | undefined {
|
|
if (typeof entry.id === "string") return entry.id
|
|
if (typeof entry._id === "string") return entry._id
|
|
if (entry._id && typeof entry._id === "object" && typeof entry._id.$oid === "string") return entry._id.$oid
|
|
return undefined
|
|
}
|
|
|
|
const SEEDED_TRANSLATION_KEYS = new Set<string>(Object.values(SEEDED_TEST_CONTENT).map((entry) => entry.translationKey))
|
|
const SEEDED_PATHS = new Set<string>(Object.values(SEEDED_TEST_CONTENT).map((entry) => entry.path))
|
|
|
|
function isSeededContentEntry(entry: ContentEntry): boolean {
|
|
if (entry._testdata === true) {
|
|
return true
|
|
}
|
|
|
|
if (typeof entry.translationKey === "string" && SEEDED_TRANSLATION_KEYS.has(entry.translationKey)) {
|
|
return true
|
|
}
|
|
|
|
if (typeof entry.path === "string" && SEEDED_PATHS.has(entry.path)) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
const SEEDED_CONTENT_ENTRIES = [
|
|
{
|
|
_testdata: true,
|
|
active: true,
|
|
type: "page",
|
|
lang: "de",
|
|
translationKey: SEEDED_TEST_CONTENT.home.translationKey,
|
|
name: "Playwright Startseite",
|
|
path: SEEDED_TEST_CONTENT.home.path,
|
|
teaserText: "Deterministisch erzeugte Testseite fuer API- und E2E-Tests.",
|
|
meta: {
|
|
title: "Playwright Startseite",
|
|
description: "Seeded Startseite fuer stabile Playwright-Tests.",
|
|
keywords: ["playwright", "seed", "e2e"],
|
|
},
|
|
blocks: [
|
|
{
|
|
type: "hero",
|
|
headline: "Playwright Seed Startseite",
|
|
headlineH1: true,
|
|
tagline: "Deterministische Testdaten",
|
|
subline: "Diese Seite wird vor dem Testlauf frisch ueber die Admin-API angelegt.",
|
|
containerWidth: "wide",
|
|
callToAction: {
|
|
buttonText: "Zum Kontakt",
|
|
buttonLink: `/de${SEEDED_TEST_CONTENT.contact.path}`,
|
|
},
|
|
},
|
|
{
|
|
type: "features",
|
|
anchorId: "seed-features",
|
|
headline: "Stabile Grundlage fuer Frontend-Tests",
|
|
tagline: "Seed",
|
|
padding: { top: "md", bottom: "md" },
|
|
featureBoxes: [
|
|
{
|
|
icon: "lightning",
|
|
title: "Frisch angelegt",
|
|
text: "Die Inhalte werden in globalSetup erstellt statt aus Demo-Daten uebernommen.",
|
|
},
|
|
{
|
|
icon: "database",
|
|
title: "API-nah",
|
|
text: "Die Seed-Daten kommen ueber dieselben Collection-Endpunkte wie das CMS.",
|
|
},
|
|
{
|
|
icon: "globe",
|
|
title: "Mehrsprachig",
|
|
text: "DE und EN teilen sich denselben translationKey fuer Routing-Checks.",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: "richtext",
|
|
anchorId: "seed-richtext",
|
|
headline: "Mehr Kontext",
|
|
tagline: "API + UI",
|
|
padding: { top: "md", bottom: "md" },
|
|
imagePosition: "none",
|
|
text: "<p>Dieser Richtext-Block prueft, dass formatierter HTML-Inhalt im SPA gerendert wird.</p>",
|
|
},
|
|
{
|
|
type: "accordion",
|
|
anchorId: "seed-faq",
|
|
headline: "Hauefige Fragen",
|
|
tagline: "Verhalten",
|
|
padding: { top: "md", bottom: "md" },
|
|
accordionItems: [
|
|
{
|
|
question: "Warum Seed-Daten?",
|
|
answer: "<p>Damit Tests nicht blind auf bestehende Inhalte oder Demo-Routen vertrauen.</p>",
|
|
open: true,
|
|
},
|
|
{
|
|
question: "Was wird geprueft?",
|
|
answer: "<p>API-Antworten, Routing, Sprachwechsel und Block-Rendering.</p>",
|
|
open: false,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
_testdata: true,
|
|
active: true,
|
|
type: "page",
|
|
lang: "en",
|
|
translationKey: SEEDED_TEST_CONTENT.home.translationKey,
|
|
name: "Playwright Home",
|
|
path: SEEDED_TEST_CONTENT.home.path,
|
|
teaserText: "Deterministically seeded page for API and E2E coverage.",
|
|
meta: {
|
|
title: "Playwright Home",
|
|
description: "Seeded home page for stable Playwright tests.",
|
|
keywords: ["playwright", "seed", "home"],
|
|
},
|
|
blocks: [
|
|
{
|
|
type: "hero",
|
|
headline: "Playwright Seed Home",
|
|
headlineH1: true,
|
|
tagline: "Deterministic fixtures",
|
|
subline: "This page is recreated before every test run through the admin API.",
|
|
containerWidth: "wide",
|
|
callToAction: {
|
|
buttonText: "Go to contact",
|
|
buttonLink: `/en${SEEDED_TEST_CONTENT.contact.path}`,
|
|
},
|
|
},
|
|
{
|
|
type: "features",
|
|
anchorId: "seed-features",
|
|
headline: "Stable frontend coverage",
|
|
tagline: "Seed",
|
|
padding: { top: "md", bottom: "md" },
|
|
featureBoxes: [
|
|
{
|
|
icon: "lightning",
|
|
title: "Freshly created",
|
|
text: "The content is created during globalSetup instead of relying on demo data.",
|
|
},
|
|
{
|
|
icon: "database",
|
|
title: "API-backed",
|
|
text: "The seed uses the same collection endpoints as the CMS itself.",
|
|
},
|
|
{
|
|
icon: "globe",
|
|
title: "Localized",
|
|
text: "DE and EN share the same translationKey for route switching checks.",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: "richtext",
|
|
anchorId: "seed-richtext",
|
|
headline: "More context",
|
|
tagline: "API + UI",
|
|
padding: { top: "md", bottom: "md" },
|
|
imagePosition: "none",
|
|
text: "<p>This richtext block proves that formatted HTML content renders in the SPA.</p>",
|
|
},
|
|
{
|
|
type: "accordion",
|
|
anchorId: "seed-faq",
|
|
headline: "Common questions",
|
|
tagline: "Behavior",
|
|
padding: { top: "md", bottom: "md" },
|
|
accordionItems: [
|
|
{
|
|
question: "Why seeded data?",
|
|
answer: "<p>So the tests do not depend on existing demo pages or editorial content.</p>",
|
|
open: true,
|
|
},
|
|
{
|
|
question: "What is covered?",
|
|
answer: "<p>API responses, routing, locale switching and block rendering.</p>",
|
|
open: false,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
_testdata: true,
|
|
active: true,
|
|
type: "page",
|
|
lang: "de",
|
|
translationKey: SEEDED_TEST_CONTENT.contact.translationKey,
|
|
name: "Playwright Kontakt",
|
|
path: SEEDED_TEST_CONTENT.contact.path,
|
|
teaserText: "Seeded Kontaktseite fuer Formular- und Routing-Tests.",
|
|
meta: {
|
|
title: "Playwright Kontakt",
|
|
description: "Seeded Kontaktseite fuer Playwright.",
|
|
keywords: ["playwright", "kontakt"],
|
|
},
|
|
blocks: [
|
|
{
|
|
type: "hero",
|
|
headline: "Kontakt fuer Testlauf",
|
|
headlineH1: true,
|
|
tagline: "Seed",
|
|
subline: "Diese Seite prueft das aktuelle ContactForm-Rendering.",
|
|
},
|
|
{
|
|
type: "contact-form",
|
|
anchorId: "kontaktformular",
|
|
headline: "Schreibe uns",
|
|
padding: { top: "md", bottom: "md" },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
_testdata: true,
|
|
active: true,
|
|
type: "page",
|
|
lang: "en",
|
|
translationKey: SEEDED_TEST_CONTENT.contact.translationKey,
|
|
name: "Playwright Contact",
|
|
path: SEEDED_TEST_CONTENT.contact.path,
|
|
teaserText: "Seeded contact page for form and routing tests.",
|
|
meta: {
|
|
title: "Playwright Contact",
|
|
description: "Seeded contact page for Playwright.",
|
|
keywords: ["playwright", "contact"],
|
|
},
|
|
blocks: [
|
|
{
|
|
type: "hero",
|
|
headline: "Contact for the test run",
|
|
headlineH1: true,
|
|
tagline: "Seed",
|
|
subline: "This page verifies the current contact form rendering.",
|
|
},
|
|
{
|
|
type: "contact-form",
|
|
anchorId: "contact-form",
|
|
headline: "Write to us",
|
|
padding: { top: "md", bottom: "md" },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
_testdata: true,
|
|
active: false,
|
|
type: "page",
|
|
lang: "de",
|
|
translationKey: SEEDED_TEST_CONTENT.inactive.translationKey,
|
|
name: "Playwright Inaktiv",
|
|
path: SEEDED_TEST_CONTENT.inactive.path,
|
|
teaserText: "Nicht aktive Seed-Seite fuer 404-Checks.",
|
|
meta: {
|
|
title: "Playwright Inaktiv",
|
|
description: "Nicht aktive Seed-Seite fuer Routing-Tests.",
|
|
keywords: ["playwright", "inactive"],
|
|
},
|
|
blocks: [
|
|
{
|
|
type: "richtext",
|
|
anchorId: "inactive",
|
|
headline: "Sollte nicht sichtbar sein",
|
|
tagline: "Seed",
|
|
padding: { top: "md", bottom: "md" },
|
|
imagePosition: "none",
|
|
text: "<p>Diese Seite ist absichtlich inaktiv und darf im Frontend nicht erscheinen.</p>",
|
|
},
|
|
],
|
|
},
|
|
] as const
|
|
|
|
export async function cleanupSeededTestContent(baseURL: string): Promise<number> {
|
|
const contentEntries = await listCollectionEntries<ContentEntry>(baseURL, "content")
|
|
// Cleanup runs before every seed pass so leftovers from aborted test runs
|
|
// are removed on the next successful global setup.
|
|
const seededEntries = contentEntries.filter((entry) => isSeededContentEntry(entry))
|
|
|
|
let deleted = 0
|
|
for (const entry of seededEntries) {
|
|
const entryId = getEntryId(entry)
|
|
if (!entryId) continue
|
|
|
|
const ok = await deleteCollectionEntry(baseURL, "content", entryId)
|
|
if (ok) deleted++
|
|
}
|
|
|
|
return deleted
|
|
}
|
|
|
|
export async function seedTestContent(baseURL: string): Promise<number> {
|
|
let created = 0
|
|
for (const entry of SEEDED_CONTENT_ENTRIES) {
|
|
await createCollectionEntry(baseURL, "content", entry as unknown as Record<string, unknown>)
|
|
created++
|
|
}
|
|
return created
|
|
}
|
|
|
|
export async function ensureSeededTestContent(baseURL: string): Promise<{ deleted: number; created: number }> {
|
|
const deleted = await cleanupSeededTestContent(baseURL)
|
|
const created = await seedTestContent(baseURL)
|
|
return { deleted, created }
|
|
}
|