diff --git a/src/content/loader.test.ts b/src/content/loader.test.ts new file mode 100644 index 0000000..5f4f3b7 --- /dev/null +++ b/src/content/loader.test.ts @@ -0,0 +1,75 @@ +import { describe, it, expect } from 'vitest'; +import { loadFragmentsFromGlob } from './loader.ts'; + +/** + * PIPE-01 enforcement: a schema violation in any /content/seasons/**.yaml + * or /content/seasons/**\/fragments/*.md file MUST fail the build. + * + * The exported `loadFragmentsFromGlob(yamlGlob, mdGlob)` helper accepts + * mocked glob outputs so we can prove the schema rejects bad input the + * same way `import.meta.glob` would feed real files into the build-time + * loader (which throws and bubbles up through Vite, exiting non-zero). + * + * Per .planning/phases/01-foundations-and-doctrine/01-RESEARCH.md + * § Validation Architecture (PIPE-01 row): "Vitest run with mocked + * import.meta.glob" — that's this file. + */ +describe('PIPE-01: content schema validation', () => { + it('returns [] when both globs are empty', () => { + expect(loadFragmentsFromGlob({}, {})).toEqual([]); + }); + + it('parses valid YAML fragments', () => { + const yamlGlob = { + '/content/seasons/00-demo/fragments.yaml': ` +fragments: + - id: season0.demo.test + season: 0 + body: "demo body" +`, + }; + const result = loadFragmentsFromGlob(yamlGlob); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + id: 'season0.demo.test', + season: 0, + body: 'demo body', + }); + }); + + it('THROWS on a numeric-id violation (stable-string-ID rule)', () => { + const yamlGlob = { + '/content/seasons/01-soil/fragments.yaml': ` +fragments: + - id: 42 + season: 1 + body: "this should fail because id must be a string matching the season. regex" +`, + }; + expect(() => loadFragmentsFromGlob(yamlGlob)).toThrow(/\[content\] schema violation/); + }); + + it('THROWS when season is out of [0,7] range', () => { + const yamlGlob = { + '/content/seasons/99-bogus/fragments.yaml': ` +fragments: + - id: season99.bogus.test + season: 99 + body: "season 99 doesn't exist" +`, + }; + expect(() => loadFragmentsFromGlob(yamlGlob)).toThrow(/\[content\] schema violation/); + }); + + it('THROWS when Markdown frontmatter omits required id', () => { + const mdGlob = { + '/content/seasons/01-soil/fragments/no-id.md': `--- +season: 1 +--- + +Body text without an id frontmatter key. +`, + }; + expect(() => loadFragmentsFromGlob({}, mdGlob)).toThrow(/\[content\] schema violation/); + }); +});