import type { Field } from 'payload' import { describe, expect, it } from 'vitest' import { ApplicationForm } from '@/ApplicationForm/config' import { ApplicationPhase } from '@/ApplicationPhase/config' import { Footer } from '@/Footer/config' import { Header } from '@/Header/config' import { NewsletterForm } from '@/NewsletterForm/config' import { SiteSettings } from '@/SiteSettings/config' import { aboutFields } from '@/collections/Pages/aboutFields' import { homeFields } from '@/collections/Pages/homeFields' import { netzwerkFields } from '@/collections/Pages/netzwerkFields' import { participationFields } from '@/collections/Pages/participationFields' import { pressIndexFields } from '@/collections/Pages/pressIndexFields' function fieldPaths(fields: Field[], prefix = ''): string[] { return fields.flatMap((field) => { if (!('name' in field) || typeof field.name !== 'string') { return 'fields' in field && Array.isArray(field.fields) ? fieldPaths(field.fields, prefix) : [] } const path = prefix ? `${prefix}.${field.name}` : field.name const children = 'fields' in field && Array.isArray(field.fields) ? fieldPaths(field.fields, path) : [] return [path, ...children] }) } function findField(fields: Field[], path: string): Field | undefined { const [name, ...rest] = path.split('.') const field = fields.find((candidate) => 'name' in candidate && candidate.name === name) if (!field || rest.length === 0) return field if (!('fields' in field) || !Array.isArray(field.fields)) return undefined return findField(field.fields, rest.join('.')) } describe('Payload field inventory', () => { it('keeps obsolete page controls out of the schema', () => { const paths = [ ...fieldPaths(homeFields), ...fieldPaths(participationFields), ...fieldPaths(aboutFields), ...fieldPaths(pressIndexFields), ...fieldPaths(netzwerkFields), ] expect(paths).not.toEqual( expect.arrayContaining([ 'home.application', 'home.form', 'participation.applicationForm', 'participation.form', 'participation.eligibility.secondaryCta', 'participation.eligibility.nudgeCta', 'participation.applicationWays.recommendedLabel', 'participation.applicationWays.fallbackCta', 'participation.applicationWays.ways.featured', 'participation.applicationWays.ways.cta', 'about.highlights', 'pressIndex.events.detailLabel', 'pressIndex.news.readMoreLabel', 'pressIndex.downloads.kitLabel', 'pressIndex.downloads.kitMeta', 'pressIndex.downloads.kitFile', 'pressIndex.downloads.kitUrl', 'pressIndex.downloads.kitDownloadName', 'pressIndex.accreditation', 'netzwerk.jury.note', 'netzwerk.partners.premiumLabel', 'netzwerk.partners.defaultLogoColor', 'netzwerk.sponsoring.footnotePrefix', 'netzwerk.sponsoring.footnoteLabel', 'netzwerk.sponsoring.footnoteUrl', 'netzwerk.sponsoring.formEyebrow', 'netzwerk.sponsoringForm.packages', 'netzwerk.sponsoringForm.step1Eyebrow', 'netzwerk.sponsoringForm.step1Heading', 'netzwerk.sponsoringForm.requiredPackageError', ]), ) }) it('retains rendered page controls and authoritative relationships', () => { const paths = [ ...fieldPaths(homeFields), ...fieldPaths(participationFields), ...fieldPaths(aboutFields), ...fieldPaths(pressIndexFields), ...fieldPaths(netzwerkFields), ] expect(paths).toEqual( expect.arrayContaining([ 'home.hero', 'home.winners.featured', 'home.videoModal.video', 'participation.process.steps', 'participation.awardsGrid.cards', 'about.testimonials.items', 'pressIndex.events.statusLabels', 'pressIndex.downloads.contactName', 'pressIndex.downloads.contactImage', 'pressIndex.downloads.contactImageAlt', 'netzwerk.jury.members', 'netzwerk.patronage.greetingVideo', 'netzwerk.patronage.greetingVideoButtonLabel', 'netzwerk.patronage.greetingVideoTitle', 'netzwerk.patronage.greetingVideoDescription', 'netzwerk.patronage.greetingVideoCloseLabel', 'netzwerk.partners.tiers', 'netzwerk.partners.modal.websiteLabel', 'netzwerk.sponsoringForm.steps', 'netzwerk.sponsoringForm.requiredFieldError', ]), ) }) it('keeps shared multi-page and site-wide content in Globals', () => { const globals = [ApplicationForm, ApplicationPhase, NewsletterForm, Header, Footer, SiteSettings] const slugs = globals.map((global) => global.slug) expect(slugs).toEqual([ 'application-form', 'application-phase', 'newsletter-form', 'header', 'footer', 'site-settings', ]) expect(fieldPaths(ApplicationForm.fields)).toEqual(expect.arrayContaining(['section', 'form'])) expect(fieldPaths(ApplicationPhase.fields)).toEqual(expect.arrayContaining(['activePhase', 'phases'])) expect(fieldPaths(NewsletterForm.fields)).toEqual(expect.arrayContaining(['evaluation', 'completed'])) }) it('exposes exactly two editable sponsoring step labels', () => { expect(findField(netzwerkFields, 'netzwerk.sponsoringForm.steps')).toMatchObject({ minRows: 2, maxRows: 2, }) }) it('limits the Netzwerk greeting upload to video media', () => { const field = findField(netzwerkFields, 'netzwerk.patronage.greetingVideo') expect(field).toMatchObject({ type: 'upload', relationTo: 'media', filterOptions: { mimeType: { contains: 'video', }, }, }) expect(field).not.toHaveProperty('defaultValue') }) it('limits the press contact upload to image media', () => { const field = findField(pressIndexFields, 'pressIndex.downloads.contactImage') expect(field).toMatchObject({ type: 'upload', relationTo: 'media', filterOptions: { mimeType: { contains: 'image', }, }, }) expect(field).not.toHaveProperty('defaultValue') }) })