Context
src/data/keyword-clusters.ts builds the primary keyword woven into the H1, <title>, meta description, and an H2 on all 9 domain-landing pages (consumed by src/pages/aws/[cert]/[domain].astro). titleCaseKeyword (line 99) and fixKeywordInitialisms (line 132) carry non-trivial casing rules (uppercase tokens like AWS / AIF-C01, hyphenated-code casing, lowercase function words, a first-word exception), and getSampleKeywordTerms (line 67) strips a generic-token denylist and enforces a length rule. None of it is tested, so a regression silently corrupts locked SEO output (for example aif-c01 rendering instead of AIF-C01) on every indexable domain page.
Scope
- Add
src/data/keyword-clusters.test.ts (co-located, Vitest). Pure-function tests only; no production change. Model the style on src/lib/seo-data.test.ts.
Cases to cover
titleCaseKeyword: initialisms stay uppercase (AWS, AIF-C01, CLF-C02); function words (for, and, the, of) lowercase mid-title but capitalized as the first word; hyphenated codes cased correctly.
fixKeywordInitialisms: lowercase aif-c01 / clf-c02 map to the official uppercase forms.
getSampleKeywordTerms: generic denylist tokens removed; the length rule applied; stable order.
Acceptance criteria
Context
src/data/keyword-clusters.tsbuilds the primary keyword woven into the H1,<title>, meta description, and an H2 on all 9 domain-landing pages (consumed bysrc/pages/aws/[cert]/[domain].astro).titleCaseKeyword(line 99) andfixKeywordInitialisms(line 132) carry non-trivial casing rules (uppercase tokens likeAWS/AIF-C01, hyphenated-code casing, lowercase function words, a first-word exception), andgetSampleKeywordTerms(line 67) strips a generic-token denylist and enforces a length rule. None of it is tested, so a regression silently corrupts locked SEO output (for exampleaif-c01rendering instead ofAIF-C01) on every indexable domain page.Scope
src/data/keyword-clusters.test.ts(co-located, Vitest). Pure-function tests only; no production change. Model the style onsrc/lib/seo-data.test.ts.Cases to cover
titleCaseKeyword: initialisms stay uppercase (AWS,AIF-C01,CLF-C02); function words (for,and,the,of) lowercase mid-title but capitalized as the first word; hyphenated codes cased correctly.fixKeywordInitialisms: lowercaseaif-c01/clf-c02map to the official uppercase forms.getSampleKeywordTerms: generic denylist tokens removed; the length rule applied; stable order.Acceptance criteria
src/data/keyword-clusters.test.tsexists and covers the cases above.npm run testpasses; no new dependencies; no production code changed.