import assert from 'node:assert/strict'; import { buildScheduleColumns, sanitizeCell } from '../js/excel.js'; const employees = [ { id: 'a1', name: 'Anna Müller' }, { id: 'b1', name: 'Bernd Schulz' }, { id: 'c1', name: 'Carla Weber' } ]; // Single employee per day { const assignments = [ { date: '2026-04-01', employeeId: 'a1' }, { date: '2026-04-02', employeeId: 'b1' } ]; const cols = buildScheduleColumns(assignments, employees); assert.deepEqual(cols.names, ['Anna Müller', 'Bernd Schulz'], 'names per single-entry day'); assert.deepEqual(cols.dates, ['01.04.2026', '02.04.2026'], 'dates formatted DD.MM.YYYY'); } // Two employees per day → joined with " & ", alphabetical { const assignments = [ { date: '2026-04-01', employeeId: 'b1' }, // Bernd inserted first { date: '2026-04-01', employeeId: 'a1' } // Anna inserted second ]; const cols = buildScheduleColumns(assignments, employees); assert.equal(cols.names.length, 1, 'one column per date'); assert.equal(cols.names[0], 'Anna Müller & Bernd Schulz', 'names alphabetical, joined with " & "'); assert.equal(cols.dates[0], '01.04.2026', 'one date entry'); } // Three employees per day { const assignments = [ { date: '2026-04-01', employeeId: 'c1' }, { date: '2026-04-01', employeeId: 'a1' }, { date: '2026-04-01', employeeId: 'b1' } ]; const cols = buildScheduleColumns(assignments, employees); assert.equal(cols.names[0], 'Anna Müller & Bernd Schulz & Carla Weber', 'three names joined alphabetical'); } // Multiple dates with multiple employees, dates ascending { const assignments = [ { date: '2026-04-02', employeeId: 'a1' }, { date: '2026-04-01', employeeId: 'b1' }, { date: '2026-04-01', employeeId: 'a1' } ]; const cols = buildScheduleColumns(assignments, employees); assert.deepEqual(cols.dates, ['01.04.2026', '02.04.2026'], 'dates sorted ascending'); assert.deepEqual(cols.names, ['Anna Müller & Bernd Schulz', 'Anna Müller'], 'names per column in date order'); } // Unknown employeeId: empty string slot, sorted with other names { const assignments = [ { date: '2026-04-01', employeeId: 'a1' }, { date: '2026-04-01', employeeId: 'unknown' } ]; const cols = buildScheduleColumns(assignments, employees); // Empty-string sorts before 'Anna Müller' assert.equal(cols.names[0], ' & Anna Müller', 'unknown employee → empty string in join'); } // sanitizeCell: formula-triggering leading chars get an apostrophe prefix { assert.equal(sanitizeCell('=1+1'), "'=1+1", 'leading = neutralized'); assert.equal(sanitizeCell('+cmd'), "'+cmd", 'leading + neutralized'); assert.equal(sanitizeCell('-2'), "'-2", 'leading - neutralized'); assert.equal(sanitizeCell('@x'), "'@x", 'leading @ neutralized'); assert.equal(sanitizeCell('Anna Müller'), 'Anna Müller', 'normal name unchanged'); } // buildScheduleColumns: a malicious name is sanitized in the output cell { const cols = buildScheduleColumns( [{ date: '2026-04-01', employeeId: 'x' }], [{ id: 'x', name: '=HYPERLINK("http://evil")' }] ); assert.ok(cols.names[0].startsWith("'="), 'formula name prefixed with apostrophe'); } console.log('All excel tests passed.');