content: replace scaffolding with bilingual pages and case studies
Ship the final German and English copy, compose every route from shared page primitives, and cover claims, parity and contact briefing in tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
86
src/app/core/content/content-parity.spec.ts
Normal file
86
src/app/core/content/content-parity.spec.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { APP_LOCALES } from '../i18n/locale';
|
||||
import { ROUTE_IDS } from '../routing/route-ids';
|
||||
import { CASE_STUDY_IDS } from './content.contracts';
|
||||
import { SITE_CONTENT_DATA } from './site-content';
|
||||
|
||||
const STRUCTURAL_KEYS = new Set([
|
||||
'id',
|
||||
'status',
|
||||
'control',
|
||||
'required',
|
||||
'routeId',
|
||||
'caseId',
|
||||
'referenceCaseId',
|
||||
'external',
|
||||
]);
|
||||
|
||||
function assertParity(left: unknown, right: unknown, path: string): void {
|
||||
if (Array.isArray(left) || Array.isArray(right)) {
|
||||
expect(Array.isArray(left), path).toBe(true);
|
||||
expect(Array.isArray(right), path).toBe(true);
|
||||
expect((left as unknown[]).length, path).toBe((right as unknown[]).length);
|
||||
(left as unknown[]).forEach((item, index) =>
|
||||
assertParity(item, (right as unknown[])[index], `${path}[${index}]`),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (left && right && typeof left === 'object' && typeof right === 'object') {
|
||||
const leftKeys = Object.keys(left).sort();
|
||||
const rightKeys = Object.keys(right).sort();
|
||||
expect(leftKeys, path).toEqual(rightKeys);
|
||||
|
||||
for (const key of leftKeys) {
|
||||
const nextPath = `${path}.${key}`;
|
||||
const leftValue = (left as Record<string, unknown>)[key];
|
||||
const rightValue = (right as Record<string, unknown>)[key];
|
||||
if (STRUCTURAL_KEYS.has(key)) {
|
||||
expect(leftValue, nextPath).toEqual(rightValue);
|
||||
} else {
|
||||
assertParity(leftValue, rightValue, nextPath);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof left === 'string' &&
|
||||
typeof right === 'string' &&
|
||||
(/featuredCaseIds\[\d+\]$/.test(path) || /options\[\d+\]\.value$/.test(path))
|
||||
) {
|
||||
expect(left, path).toBe(right);
|
||||
}
|
||||
}
|
||||
|
||||
describe('content parity', () => {
|
||||
it('keeps the German and English trees structurally aligned', () => {
|
||||
assertParity(SITE_CONTENT_DATA.de, SITE_CONTENT_DATA.en, 'site');
|
||||
});
|
||||
|
||||
it('uses different long-form copy in German and English', () => {
|
||||
for (const routeId of ROUTE_IDS) {
|
||||
const german = SITE_CONTENT_DATA.de.pages[routeId];
|
||||
const english = SITE_CONTENT_DATA.en.pages[routeId];
|
||||
|
||||
expect(german.title, routeId).not.toBe(english.title);
|
||||
expect(german.description, routeId).not.toBe(english.description);
|
||||
expect(german.hero.headline, routeId).not.toBe(english.hero.headline);
|
||||
|
||||
german.sections.forEach((section, index) => {
|
||||
const other = english.sections[index];
|
||||
expect(section.body?.join('\n'), `${routeId}.${section.id}`).not.toBe(
|
||||
other?.body?.join('\n'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
for (const caseId of CASE_STUDY_IDS) {
|
||||
const german = SITE_CONTENT_DATA.de.cases[caseId];
|
||||
const english = SITE_CONTENT_DATA.en.cases[caseId];
|
||||
expect(german.summary, caseId).not.toBe(english.summary);
|
||||
expect(german.situation, caseId).not.toBe(english.situation);
|
||||
}
|
||||
|
||||
expect(APP_LOCALES).toEqual(['de', 'en']);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user