import { describe, expect, test } from 'vitest'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { parseStatus } from '../src/parser.ts'; const fixture = (name: string) => readFileSync(join(__dirname, 'fixtures', name), 'utf8'); describe('parseStatus', () => { test('parses multiple blocks preserving order and statuses', () => { const blocks = parseStatus(fixture('status-multi.md')); expect(blocks).toHaveLength(3); expect(blocks.map((b) => b.slug)).toEqual(['task-a', 'task-b', 'task-c']); expect(blocks.map((b) => b.status)).toEqual(['in_progress', 'blocked', 'open']); }); test('parses Blocker field when present', () => { const blocks = parseStatus(fixture('status-multi.md')); const blocked = blocks.find((b) => b.slug === 'task-b'); expect(blocked?.blocker).toBe('task-a'); }); test('Blocker field is null when absent', () => { const blocks = parseStatus(fixture('status-multi.md')); const ready = blocks.find((b) => b.slug === 'task-c'); expect(ready?.blocker).toBeNull(); }); test('returns empty array for STATUS.md without task blocks', () => { expect(parseStatus('# Task Board\n_Updated: 2026-05-22_\n\nNo tasks yet.\n')).toEqual([]); }); test.each([ 'real-books-STATUS.md', 'real-claude-skills-STATUS.md', 'real-projects-meta-mcp-STATUS.md', ])('parses real STATUS.md fixture %s without crashing and yields ≥1 block', (name) => { const blocks = parseStatus(fixture(name)); expect(blocks.length).toBeGreaterThan(0); for (const b of blocks) { expect(b.slug).toMatch(/^[a-z0-9][a-z0-9-]*$/); expect(b.status).toMatch(/^(open|in_progress|paused|blocked|done)$/); expect(b.status_emoji).toMatch(/^(⚪|🔴|🟡|🔵|🟢)$/u); expect(b.title.length).toBeGreaterThan(0); } }); test('ignores blocks whose H2 has no known status emoji', () => { const text = '## 🚀 [some-task] — title\n**Status:** custom\n**Branch:** master\n---\n'; expect(parseStatus(text)).toEqual([]); }); test('parses a single active block with all fields', () => { const blocks = parseStatus(fixture('status-single-block.md')); expect(blocks).toHaveLength(1); expect(blocks[0]).toEqual({ slug: 'board-viewer-pointers', title: 'pre-impl: fill Domain conventions with design-context pointers', status: 'in_progress', status_emoji: '🔴', where_stopped: 'только что промочен дизайн.', next_action: 'вставить блок в `.wiki/CLAUDE.md`.', blocker: null, branch: 'master', }); }); });