/** * ENFORCEMENT, IN ONE PLACE (C-356). * * The head-authority contract is enforced by the shared package, not by eleven * site test suites: `applyHead` is typed `() => void`, and an argument that * reaches it at runtime anyway is DROPPED with a loud message. * * Both halves are tested here because both are load-bearing: * - the TYPE stops a type-checked caller at build (`pnpm type-check`, wired as * the fleet's pre-deploy gate by C-303/C-316); * - the RUNTIME stops the caller who is not type-checked — a `.vue` SFC whose * script block never sees `vue-tsc`, an `as any`, or a plain-JS site * (just-posh is exactly that: `jsconfig.json`, `.js` sources, no type-check * script at all). That caller is not hypothetical; it is the fleet. * * The failure MODE is deliberately asymmetric — see the assertions at the end. */ import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest' const applied: unknown[] = [] vi.mock('@unhead/vue', () => ({ useHead: (input: unknown) => { applied.push(input) }, })) // The composable reads its config from the `__DCS_SEO__` build-time global. const SEO = { global: { siteName: 'Fixture Co', siteUrl: 'https://fixture.example.com', titleTemplate: '%s | Fixture Co', defaultTitle: 'Fixture Co', defaultDescription: 'The approved description.', }, pages: { home: { title: 'Approved Title', description: 'The approved description.' }, }, } const { useSEO, HEAD_OVERRIDE_REFUSED_MESSAGE } = await import('./useSEO') const { buildHeadTags } = await import('../seo/headTags') type ApplyHeadWithOverride = (overrides: Record) => void beforeEach(() => { applied.length = 0 ;(globalThis as Record).__DCS_SEO__ = SEO }) afterEach(() => { vi.restoreAllMocks() delete (globalThis as Record).__DCS_SEO__ }) describe('applyHead re-asserts the baked head', () => { test('with no arguments it emits the seo.yaml-resolved head', () => { const { applyHead } = useSEO('home', '/') applyHead() expect(applied).toHaveLength(1) const head = applied[0] as { title: string; meta: Array<{ name?: string; content: string }> } expect(head.title).toBe('Approved Title | Fixture Co') expect(head.meta.find((m) => m.name === 'description')!.content).toBe('The approved description.') }) test('the type says () => void — an override is a COMPILE error, not a runtime option', () => { // NOTE: the compile-time assertion is NOT here. `packages/cms/tsconfig.json` // excludes `**/*.test.ts`, so a `@ts-expect-error` in this file would never // be evaluated by `pnpm type-check` — a comment dressed as a gate. The real // pin is `APPLY_HEAD_TAKES_NO_ARGUMENTS` in `src/seo/headContract.ts`, which // is a checked source file; kill-tested by re-adding the parameter (tsc then // reports TS2322 on that line). This test covers the RUNTIME half only. const { applyHead } = useSEO('home', '/') expect(applyHead).toHaveLength(0) applyHead() expect(applied).toHaveLength(1) }) }) describe('an override that reaches the runtime is REFUSED, not obeyed', () => { test('the emitted head is byte-identical to the no-argument call', () => { const errors: string[] = [] vi.spyOn(console, 'error').mockImplementation((m: unknown) => { errors.push(String(m)) }) const a = useSEO('home', '/') a.applyHead() const clean = JSON.stringify(applied[0]) applied.length = 0 const b = useSEO('home', '/') ;(b.applyHead as unknown as ApplyHeadWithOverride)({ title: 'Hand-written Title', description: 'Hand-written description.', keywords: 'hand, written', }) expect(JSON.stringify(applied[0])).toBe(clean) expect(JSON.stringify(applied[0])).not.toContain('Hand-written') expect(errors.join('\n')).toContain('IGNORED') expect(errors.join('\n')).toContain('.dcs/seo.yaml is the only writer') expect(errors.join('\n')).toContain('title, description, keywords') }) test('KILL-TEST: without the refusal the override WOULD have won', () => { // The old behaviour, reproduced through the resolver the composable calls: // `overrides?.title ?? resolved.title`. This is the exact line that shipped // 93 divergences; it is asserted here so the fix cannot be quietly undone // without this test going red. const errors: string[] = [] vi.spyOn(console, 'error').mockImplementation((m: unknown) => errors.push(String(m))) const overridden = buildHeadTags('home', '/', SEO as never, { title: 'Hand-written Title' }) expect(overridden.title).toBe('Hand-written Title') const { applyHead } = useSEO('home', '/') ;(applyHead as unknown as ApplyHeadWithOverride)({ title: 'Hand-written Title' }) expect((applied[0] as { title: string }).title).toBe('Approved Title | Fixture Co') }) test('the refusal names the offending page slug and the ignored keys', () => { const errors: string[] = [] vi.spyOn(console, 'error').mockImplementation((m: unknown) => errors.push(String(m))) const { applyHead } = useSEO('home', '/') ;(applyHead as unknown as ApplyHeadWithOverride)({ title: 'x', schemas: [] }) expect(errors[0]).toContain('page slug: home') expect(errors[0]).toContain('ignored keys: title, schemas') expect(errors[0]).toContain(HEAD_OVERRIDE_REFUSED_MESSAGE.slice(0, 60)) }) test('the failure mode is ASYMMETRIC on purpose: SEO stays correct, the build does not fall over', () => { // A production throw would take a paying customer's page down over a // metadata mistake. Dropping the override cannot: the worst case is that // the page serves the OWNER-APPROVED value. vi.spyOn(console, 'error').mockImplementation(() => {}) const { applyHead } = useSEO('home', '/') expect(() => (applyHead as unknown as ApplyHeadWithOverride)({ title: 'x' })).not.toThrow() expect((applied[0] as { title: string }).title).toBe('Approved Title | Fixture Co') }) test('a null / undefined argument is not treated as a violation', () => { const errors: string[] = [] vi.spyOn(console, 'error').mockImplementation((m: unknown) => errors.push(String(m))) const { applyHead } = useSEO('home', '/') ;(applyHead as unknown as (o?: unknown) => void)(undefined) ;(applyHead as unknown as (o?: unknown) => void)(null) expect(errors).toEqual([]) expect(applied).toHaveLength(2) }) })