fix(import): validate/normalize imported data, guard Excel I/O (#3)
- loadFromJSON and the localStorage startup load now run employees through normalizeEmployees(): fills missing constraints, drops unusable rows, de-duplicates ids, and discards invalid vacation ranges — preventing later crashes (e.g. c.neverDays on undefined) and same-day double-books. - Excel import is wrapped in try/catch with a typeof XLSX guard and user feedback; the Excel export button gets the same guard. - createEmployee reuses the shared defaultConstraints() factory. Adds normalizeEmployees tests (defaults, dropping, dedup, vacations) and a loadFromJSON normalization test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
e851bb2833
commit
065876ced4
5 files changed
+118
-18
No files matched your search
+42
-1
@@ -1,5 +1,5 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { addHistoryEntries, removeHistoryEntry, loadFromJSON, saveToJSON } from '../js/data.js';
|
||||
import { addHistoryEntries, removeHistoryEntry, loadFromJSON, saveToJSON, normalizeEmployees } from '../js/data.js';
|
||||
|
||||
function makeState(history = []) {
|
||||
return {
|
||||
@@ -123,4 +123,45 @@ function makeState(history = []) {
|
||||
assert.deepEqual(parsed.settings, { moderatorsPerDay: 2 }, 'settings round-trip');
|
||||
}
|
||||
|
||||
// normalizeEmployees: missing constraints are filled with defaults
|
||||
{
|
||||
const out = normalizeEmployees([{ id: 'a', name: 'Alice' }]);
|
||||
assert.equal(out.length, 1, 'employee kept');
|
||||
assert.deepEqual(out[0].constraints.neverDays, [], 'neverDays defaulted');
|
||||
assert.equal(out[0].constraints.minGapDays, 14, 'minGapDays defaulted to 14');
|
||||
assert.equal(out[0].constraints.maxPerMonth, null, 'maxPerMonth defaulted to null');
|
||||
}
|
||||
|
||||
// normalizeEmployees: rows without a usable name are dropped
|
||||
{
|
||||
const out = normalizeEmployees([{ id: 'a', name: ' ' }, { id: 'b' }, null, 42]);
|
||||
assert.equal(out.length, 0, 'nameless/invalid rows dropped');
|
||||
}
|
||||
|
||||
// normalizeEmployees: duplicate ids are de-duplicated to distinct ids
|
||||
{
|
||||
const out = normalizeEmployees([{ id: 'dup', name: 'A' }, { id: 'dup', name: 'B' }]);
|
||||
assert.equal(out.length, 2, 'both kept');
|
||||
assert.notEqual(out[0].id, out[1].id, 'duplicate id resolved');
|
||||
}
|
||||
|
||||
// normalizeEmployees: invalid vacation ranges dropped, valid kept
|
||||
{
|
||||
const out = normalizeEmployees([{ id: 'a', name: 'A', constraints: { vacations: [
|
||||
{ from: '2026-05-10', to: '2026-05-05' }, // reversed → dropped
|
||||
{ from: '2026-06-01', to: '2026-06-07' } // valid → kept
|
||||
] } }]);
|
||||
assert.equal(out[0].constraints.vacations.length, 1, 'only valid vacation kept');
|
||||
assert.equal(out[0].constraints.vacations[0].from, '2026-06-01', 'valid vacation preserved');
|
||||
}
|
||||
|
||||
// loadFromJSON: employees without constraints are normalized (no later crash)
|
||||
{
|
||||
const loaded = loadFromJSON(JSON.stringify({
|
||||
employees: [{ id: 'x', name: 'NoConstraints' }],
|
||||
calendar: { holidays: [], companyClosures: [] }, history: []
|
||||
}));
|
||||
assert.ok(Array.isArray(loaded.employees[0].constraints.neverDays), 'constraints present after load');
|
||||
}
|
||||
|
||||
console.log('All data tests passed.');
|
||||
Reference in new issue
Block a user