test(01-04): PIPE-01 enforcement — schema violations throw at content load
- 2 happy-path tests: empty globs, valid YAML round-trip - 3 throw assertions covering the schema-violation matrix: * numeric id (violates stable-string-ID rule) * season out of [0,7] range * Markdown frontmatter missing required id - All 5 tests pass; full Phase-1 suite remains green - Proves the throws that fail npm run build at module-eval time
This commit is contained in:
@@ -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<N>.<slug> 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/);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user