import { cleanup, render, screen, within } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { CmsRouteProvider, type CmsRouteData } from '@/spa/cmsRoute' import Participation from '@/spa/pages/Participation' const viewport = vi.hoisted(() => ({ mobile: false })) vi.mock('@/spa/hooks/useIsMobile', () => ({ useIsMobile: () => viewport.mobile, })) vi.mock('next/navigation', () => ({ usePathname: () => '/teilnahme', useRouter: () => ({ push: vi.fn(), replace: vi.fn() }), })) vi.mock('@/spa/components/WegZurAuszeichnungSection', () => ({ default: () =>
, })) vi.mock('@/spa/components/AwardsGridSection', () => ({ default: () =>
, })) vi.mock('@/spa/components/forms/ApplicationFormSection', () => ({ ApplicationFormSection: () =>
, })) vi.mock('@/spa/components/ui/UnoptimizedImage', () => ({ default: ({ alt }: { alt: string }) =>
, })) const participationRoute: CmsRouteData = { collection: 'pages', doc: { id: 'participation-page', slug: 'teilnahme', spaPath: '/teilnahme', participation: { eligibility: { eyebrow: 'CMS eligibility eyebrow', heading: 'CMS ELIGIBILITY\nHEADING', description: 'CMS eligibility introduction.', primaryCta: { label: 'CMS eligibility CTA', url: '/kontakt' }, criteria: [ { num: 'A', title: 'First CMS criterion', body: 'First CMS criterion body.', icon: 'mapPin', }, { num: 'B', title: 'Second CMS criterion', body: 'Second CMS criterion body.', icon: 'users', }, ], notes: [ { title: 'First CMS note', body: 'First CMS note body.', icon: 'building2' }, { title: 'Second CMS note', body: 'Second CMS note body.', icon: 'userCheck' }, ], nudgeText: 'CMS eligibility conclusion.', }, datesBanner: { heading: 'CMS important dates', description: 'CMS dates description.', mobileItems: [{ date: 'Mobile date', label: 'Mobile label' }], desktopItems: [{ date: 'Desktop date', label: 'Desktop label' }], }, }, }, } const renderParticipation = () => render( , ) describe('participation eligibility hierarchy', () => { beforeEach(() => { viewport.mobile = false }) afterEach(() => cleanup()) it('keeps CMS eligibility content and its CTA authoritative inside semantic groups', () => { renderParticipation() const section = screen.getByTestId('eligibility-section') const criteria = within(section).getAllByTestId('eligibility-criterion') const notes = within(section).getAllByTestId('eligibility-note') const cta = within(section).getByRole('link', { name: 'CMS eligibility CTA' }) expect(within(section).getByRole('heading', { level: 2 }).textContent).toBe( 'CMS ELIGIBILITYHEADING', ) expect(within(section).getByText('CMS eligibility introduction.')).toBeTruthy() expect(criteria.map((row) => row.textContent)).toEqual([ 'AFirst CMS criterionFirst CMS criterion body.', 'BSecond CMS criterionSecond CMS criterion body.', ]) expect(criteria.every((row) => row.tagName === 'LI')).toBe(true) expect(criteria[0]?.parentElement?.tagName).toBe('OL') expect(notes.map((note) => note.textContent)).toEqual([ 'First CMS noteFirst CMS note body.', 'Second CMS noteSecond CMS note body.', ]) expect(within(section).getByText('CMS eligibility conclusion.')).toBeTruthy() expect(cta.getAttribute('href')).toBe('/kontakt') expect(within(section).getAllByRole('link')).toHaveLength(1) }) it('provides restrained group and dates-transition hooks on desktop', () => { renderParticipation() expect(screen.getByTestId('eligibility-header').style.background).toBe('rgb(255, 255, 255)') expect(screen.getByTestId('eligibility-criteria-group').style.background).toBe( 'rgb(244, 246, 248)', ) expect(screen.getByTestId('eligibility-summary').style.background).toBe('rgb(17, 29, 85)') expect(screen.getByTestId('important-dates-transition').style.borderTopWidth).toBe('8px') expect(screen.getByRole('heading', { name: 'CMS important dates', level: 3 })).toBeTruthy() expect(screen.getByText('Desktop date')).toBeTruthy() expect(screen.queryByText('Mobile date')).toBeNull() }) it('keeps criteria, notes, and conclusion in a single readable mobile order', () => { viewport.mobile = true renderParticipation() const section = screen.getByTestId('eligibility-section') const criteriaGroup = within(section).getByTestId('eligibility-criteria-group') const notesGroup = within(section).getByTestId('eligibility-notes-group') const summary = within(section).getByTestId('eligibility-summary') const rows = within(criteriaGroup).getAllByTestId('eligibility-criterion') expect(rows.map((row) => row.getAttribute('data-order'))).toEqual(['1', '2']) expect(rows.every((row) => row.style.gridTemplateColumns === '40px 1fr')).toBe(true) expect( criteriaGroup.compareDocumentPosition(notesGroup) & Node.DOCUMENT_POSITION_FOLLOWING, ).toBeTruthy() expect( notesGroup.compareDocumentPosition(summary) & Node.DOCUMENT_POSITION_FOLLOWING, ).toBeTruthy() expect(screen.getByTestId('important-dates-transition').style.borderTopWidth).toBe('5px') expect(screen.getByTestId('important-date-item').getAttribute('data-order')).toBe('1') expect(screen.getByTestId('important-date-item').style.gridTemplateColumns).toBe( 'minmax(112px, 0.9fr) minmax(0, 1.1fr)', ) expect(screen.getByText('Mobile date')).toBeTruthy() expect(screen.queryByText('Desktop date')).toBeNull() }) })