Scrum4Me/__tests__/lib/product-doc-parser.test.ts
Madhura68 afafbca855 feat(PBI-96/T-1060): add frontmatter parser + serializer (P2-fix)
- lib/product-doc-parser.ts: parseProductDocMd(md) → {ok, frontmatter, body}
  | {ok:false, errors[]} met line-info bij YAML-fouten. Pattern gespiegeld
  uit lib/idea-plan-parser.ts.
- lib/product-doc-frontmatter.ts: setProductDocFrontmatterFields(md, patch)
  laat de server `last_updated` server-side normaliseren (P2-review-fix
  uit docs/recommendations/product-docs-storage-system-review-2026-05-16).
  Gebruikt yaml.parseDocument om field-ordering best-effort te behouden.
- todayIsoDate() helper voor 'yyyy-mm-dd' string.
- __tests__: 19 nieuwe tests groen — parse-success/fail-paden, en
  expliciete P2-coverage (vervangen + toevoegen last_updated, behoud
  overige velden + body).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:42:03 +02:00

141 lines
2.9 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { parseProductDocMd } from '@/lib/product-doc-parser'
const minimalValid = `---
title: "Deploy stappen"
status: draft
---
# Body
stappen hier
`
describe('parseProductDocMd — succes', () => {
it('parseert minimaal valide doc', () => {
const r = parseProductDocMd(minimalValid)
expect(r.ok).toBe(true)
if (!r.ok) return
expect(r.frontmatter.title).toBe('Deploy stappen')
expect(r.frontmatter.status).toBe('draft')
expect(r.body.startsWith('# Body')).toBe(true)
})
it('accepteert optionele velden (audience, applies_to, last_updated)', () => {
const md = `---
title: "Doc"
status: active
audience: [maintainer, contributor]
applies_to: PBI-96
last_updated: 2026-05-16
---
body
`
const r = parseProductDocMd(md)
expect(r.ok).toBe(true)
if (!r.ok) return
expect(r.frontmatter.audience).toEqual(['maintainer', 'contributor'])
expect(r.frontmatter.applies_to).toBe('PBI-96')
expect(r.frontmatter.last_updated).toBe('2026-05-16')
})
it('accepteert audience als single string', () => {
const md = `---
title: "Doc"
status: draft
audience: maintainer
---
body`
const r = parseProductDocMd(md)
expect(r.ok).toBe(true)
if (!r.ok) return
expect(r.frontmatter.audience).toBe('maintainer')
})
it('trimt leading whitespace van body', () => {
const md = `---
title: "x"
status: draft
---
body
`
const r = parseProductDocMd(md)
expect(r.ok).toBe(true)
if (!r.ok) return
expect(r.body.startsWith('body')).toBe(true)
})
})
describe('parseProductDocMd — fouten', () => {
it('weigert doc zonder frontmatter (regel 1 error)', () => {
const r = parseProductDocMd('# alleen body')
expect(r.ok).toBe(false)
if (r.ok) return
expect(r.errors[0].line).toBe(1)
expect(r.errors[0].message).toMatch(/yaml-frontmatter/i)
})
it('weigert doc zonder afsluitende `---`', () => {
const md = `---
title: "x"
status: draft
body
`
const r = parseProductDocMd(md)
expect(r.ok).toBe(false)
})
it('weigert frontmatter zonder title', () => {
const md = `---
status: draft
---
body`
const r = parseProductDocMd(md)
expect(r.ok).toBe(false)
if (r.ok) return
expect(r.errors.some((e) => e.message.includes('title'))).toBe(true)
})
it('weigert frontmatter zonder status', () => {
const md = `---
title: "x"
---
body`
const r = parseProductDocMd(md)
expect(r.ok).toBe(false)
if (r.ok) return
expect(r.errors.some((e) => e.message.includes('status'))).toBe(true)
})
it('weigert status buiten enum-set', () => {
const md = `---
title: "x"
status: wip
---
body`
const r = parseProductDocMd(md)
expect(r.ok).toBe(false)
})
it('geeft line-info bij bad yaml', () => {
const md = `---
title: "x
status: draft
---
body`
const r = parseProductDocMd(md)
expect(r.ok).toBe(false)
if (r.ok) return
expect(r.errors[0].line).toBeGreaterThan(0)
})
})