const { test } = require('node:test'); const assert = require('node:assert/strict'); const { parseTodoFile, buildTable, regenerate, seqNum, SECTIONS } = require('./todo'); const { groupToSection, buildDiscrepancies, buildFinalSections } = require('./sync'); const SAMPLE_TODO = `# mozdIT Weboldal ## Projekt Áttekintés Next.js 15 alapú weboldal. --- ## ✅ Befejezett | Plane | Feladat | Státusz | |-------|---------|---------| | MITHOME-1 | Kezdőlap | ✅ | | MITHOME-15 | Prod app + domain konfiguráció + HTTPS | ✅ | --- ## 🚀 TODO (Soron következő — v1.0.1 roadmap) | Plane | Feladat | Státusz | Megjegyzés | |-------|---------|---------|-----------| | MITHOME-13 | CI pipeline | ⏳ | Elsődleges prioritás | --- ## 🔄 In Progress | Plane | Feladat | Státusz | Megjegyzés | |-------|---------|---------|-----------| | MITHOME-17 | Winston logger + Loki integráció | 🔄 | részben kész | --- ## 📋 Backlog (v1.0.2+) | Plane | Feladat | Státusz | |-------|---------|---------| | MITHOME-19 | Accessibility | 📋 | --- ## Technikai Stack - **Frontend**: Next.js 15 `; test('parseTodoFile parses sections and rows with notes', () => { const { sections, rows } = parseTodoFile(SAMPLE_TODO); assert.equal(sections.completed.rows.length, 2); assert.equal(sections.completed.header, '## ✅ Befejezett'); assert.equal(sections.todo.rows[0].note, 'Elsődleges prioritás'); assert.equal(sections.inProgress.rows[0].note, 'részben kész'); assert.equal(rows.length, 5); assert.equal(rows[1].section, 'completed'); assert.equal(rows[1].id, 'MITHOME-15'); }); test('parseTodoFile ignores table header and separator lines', () => { const { rows } = parseTodoFile(SAMPLE_TODO); assert.ok(!rows.some(r => r.name === 'Feladat')); }); test('groupToSection maps Plane groups', () => { assert.equal(groupToSection('completed'), 'completed'); assert.equal(groupToSection('started'), 'inProgress'); assert.equal(groupToSection('unstarted'), 'todo'); assert.equal(groupToSection('backlog'), 'backlog'); assert.equal(groupToSection('cancelled'), null); }); test('seqNum extracts trailing number from identifier', () => { assert.equal(seqNum('MITHOME-13'), 13); assert.equal(seqNum('MITHOME-1'), 1); assert.equal(seqNum('MITHOME-27'), 27); assert.equal(seqNum('MITHOME-'), 0); }); test('buildDiscrepancies detects mismatches, new issues, orphans and cancelled', () => { const planeIssues = [ { sequence_id: 1, name: 'Kezdőlap', state: { group: 'completed' } }, { sequence_id: 15, name: 'Prod app + domain konfiguráció + HTTPS', state: { group: 'backlog' } }, { sequence_id: 18, name: 'Adatvédelmi tájékoztató oldal', state: { group: 'completed' } }, { sequence_id: 30, name: 'Új feladat', state: { group: 'started' } }, { sequence_id: 40, name: 'Törölt feladat', state: { group: 'cancelled' } } ]; const { rows } = parseTodoFile(SAMPLE_TODO); const result = buildDiscrepancies(planeIssues, rows, 'MITHOME'); assert.equal(result.mismatches.length, 1); assert.equal(result.mismatches[0].id, 'MITHOME-15'); assert.equal(result.mismatches[0].fromSection, 'completed'); assert.equal(result.mismatches[0].toSection, 'backlog'); assert.equal(result.newIssues.length, 2); assert.deepEqual(result.newIssues.map(n => n.id), ['MITHOME-18', 'MITHOME-30']); assert.equal(result.orphans.length, 3); assert.deepEqual(result.orphans.map(o => o.id).sort(), ['MITHOME-13', 'MITHOME-17', 'MITHOME-19']); assert.deepEqual(result.cancelled, [{ id: 'MITHOME-40', name: 'Törölt feladat' }]); }); test('buildFinalSections keeps plane rows and applies decisions', () => { const planeIssues = [ { sequence_id: 1, name: 'Kezdőlap', state: { group: 'completed' } }, { sequence_id: 15, name: 'Prod app + domain konfiguráció + HTTPS', state: { group: 'backlog' } }, { sequence_id: 17, name: 'Winston logger + Loki integráció', state: { group: 'started' } }, { sequence_id: 30, name: 'Új feladat', state: { group: 'started' } } ]; const { rows } = parseTodoFile(SAMPLE_TODO); const buildData = buildDiscrepancies(planeIssues, rows, 'MITHOME'); const decisions = { moveToPlane: new Set(['MITHOME-15']), keepOrphan: new Set(['MITHOME-13', 'MITHOME-17', 'MITHOME-19']), addNew: new Set(['MITHOME-30']) }; const final = buildFinalSections(buildData, decisions); assert.deepEqual(final.completed.map(r => r.id), ['MITHOME-1']); assert.deepEqual(final.backlog.map(r => r.id), ['MITHOME-15', 'MITHOME-19']); assert.deepEqual(final.inProgress.map(r => r.id), ['MITHOME-17', 'MITHOME-30']); assert.equal(final.inProgress.find(r => r.id === 'MITHOME-17').note, 'részben kész'); }); test('regenerate preserves prefix/suffix and rebuilds sections', () => { const planeIssues = [ { sequence_id: 1, name: 'Kezdőlap', state: { group: 'completed' } }, { sequence_id: 15, name: 'Prod app + domain konfiguráció + HTTPS', state: { group: 'backlog' } }, { sequence_id: 13, name: 'CI pipeline', state: { group: 'unstarted' } }, { sequence_id: 17, name: 'Winston logger + Loki integráció', state: { group: 'started' } }, { sequence_id: 19, name: 'Accessibility', state: { group: 'backlog' } } ]; const { rows } = parseTodoFile(SAMPLE_TODO); const buildData = buildDiscrepancies(planeIssues, rows, 'MITHOME'); const decisions = { moveToPlane: new Set(['MITHOME-15']), keepOrphan: new Set(['MITHOME-13', 'MITHOME-17', 'MITHOME-19']), addNew: new Set() }; const final = buildFinalSections(buildData, decisions); const output = regenerate(SAMPLE_TODO, final); assert.ok(output.includes('# mozdIT Weboldal')); assert.ok(output.includes('Next.js 15 alapú weboldal.')); assert.ok(output.includes('## Technikai Stack')); assert.ok(output.includes('- **Frontend**: Next.js 15')); assert.ok(output.includes('| MITHOME-15 | Prod app + domain konfiguráció + HTTPS | 📋 |')); assert.ok(!output.includes('| MITHOME-15 | Prod app + domain konfiguráció + HTTPS | ✅ |')); assert.ok(output.includes('## ✅ Befejezett')); assert.ok(output.includes('| MITHOME-1 | Kezdőlap | ✅ |')); }); test('buildTable sorts rows by sequence number', () => { const table = buildTable(SECTIONS[0], [ { id: 'MITHOME-15', name: 'B' }, { id: 'MITHOME-1', name: 'A' } ]); const lines = table.split('\n'); assert.equal(lines[2], '| MITHOME-1 | A | ✅ |'); assert.equal(lines[3], '| MITHOME-15 | B | ✅ |'); }); // Regression: a previous run dropping the blank line after `---` must not merge // the separator with the section header (`---## ✅ Befejezett`). test('regenerate always separates `---` from section headers', () => { const planeIssues = [ { sequence_id: 1, name: 'Kezdőlap', state: { group: 'completed' } }, { sequence_id: 13, name: 'CI pipeline', state: { group: 'unstarted' } }, { sequence_id: 17, name: 'Winston logger + Loki integráció', state: { group: 'started' } }, { sequence_id: 19, name: 'Accessibility', state: { group: 'backlog' } } ]; const { rows } = parseTodoFile(SAMPLE_TODO); const buildData = buildDiscrepancies(planeIssues, rows, 'MITHOME'); const decisions = { moveToPlane: new Set(), keepOrphan: new Set(), addNew: new Set() }; const final = buildFinalSections(buildData, decisions); const corrupted = SAMPLE_TODO.replace('---\n\n## ✅ Befejezett', '---## ✅ Befejezett'); const output = regenerate(corrupted, final); assert.ok(output.includes('---\n\n## ✅ Befejezett'), 'header must be separated from ---'); assert.ok(!output.includes('---##'), 'no merged separator+header'); assert.ok(output.includes('## ✅ Befejezett')); });