diff --git a/src/session.js b/src/session.js index 8a61604..da36cd6 100644 --- a/src/session.js +++ b/src/session.js @@ -42,7 +42,7 @@ export function proposeAssignment(session, spec) { export function commitAssignment(session, spec, source, stackId) { let stack = session.stacks.find((candidate) => candidate.id === stackId); if (!stack) { - stack = { id: stackId, spec, count: 0 }; + stack = { id: stackId, spec: { ...spec }, count: 0 }; session.stacks.push(stack); session.stacks.sort((a, b) => a.id.localeCompare(b.id)); } else { @@ -55,7 +55,9 @@ export function commitAssignment(session, spec, source, stackId) { } stack.count += 1; - const entry = { entryId: session.nextEntryId++, spec, stackId, source }; + // entry.spec ist das Protokoll dessen, was tatsaechlich gescannt wurde, und muss + // unabhaengig vom Stapel-Spec bleiben - eigene Kopie, kein geteiltes Objekt. + const entry = { entryId: session.nextEntryId++, spec: { ...spec }, stackId, source }; session.entries.push(entry); return entry; } @@ -64,7 +66,13 @@ function dropEmptyStacks(session) { session.stacks = session.stacks.filter((stack) => stack.count > 0); } -/** Nimmt den zuletzt erfassten Eintrag zurueck. */ +/** + * Nimmt den zuletzt erfassten Eintrag zurueck - nicht die zuletzt ausgefuehrte + * Handlung. Die Oberflaeche zeigt neben der Rueckgaengig-Flaeche stets den + * zuletzt erfassten Eintrag an, und genau der wird hier zurueckgenommen. Ein + * zwischenzeitliches Umsortieren (moveEntry) oder Entfernen (removeEntry) + * eines anderen Eintrags bleibt davon unberuehrt. + */ export function undoLast(session) { const entry = session.entries.pop(); if (!entry) return null; @@ -84,7 +92,7 @@ export function moveEntry(session, entryId, stackId) { let to = session.stacks.find((candidate) => candidate.id === stackId); if (!to) { - to = { id: stackId, spec: entry.spec, count: 0 }; + to = { id: stackId, spec: { ...entry.spec }, count: 0 }; session.stacks.push(to); session.stacks.sort((a, b) => a.id.localeCompare(b.id)); } diff --git a/test/session.test.js b/test/session.test.js index 35e2b82..b7e27ed 100644 --- a/test/session.test.js +++ b/test/session.test.js @@ -102,3 +102,48 @@ test('removeEntry entfernt einen einzelnen Eintrag', () => { assert.equal(session.entries.length, 1); assert.equal(session.stacks[0].count, 1); }); + +test('Ergaenzung des Stapel-Specs veraendert nicht das Spec eines frueheren Eintrags', () => { + const session = createSession(); + const unvollstaendig = { ...s64(), partNumber: null }; + const entry1 = scan(session, unvollstaendig); + const stack = session.stacks.find((s) => s.id === entry1.stackId); + assert.notEqual(stack.spec, entry1.spec, 'Stapel-Spec und Eintrags-Spec duerfen kein gemeinsames Objekt sein'); + assert.deepEqual(stack.spec, entry1.spec, 'inhaltlich sind beide Specs zunaechst gleich'); + assert.equal(entry1.spec.partNumber, null); + + const vollstaendiger = s64(); + scan(session, vollstaendiger); + + assert.equal(entry1.spec.partNumber, null, 'das Spec des ersten Eintrags darf durch eine spaetere Ergaenzung des Stapel-Specs nicht veraendert werden'); + assert.equal(stack.spec.partNumber, 'M386A8K40BM1-CRC4Y'); +}); + +test('moveEntry legt fuer einen neuen Stapel eine eigene Kopie des Specs an', () => { + const session = createSession(); + const unvollstaendig = { ...s32(), partNumber: null }; + const a = scan(session, unvollstaendig); + moveEntry(session, a.entryId, 'Z'); + const stapelZ = session.stacks.find((s) => s.id === 'Z'); + assert.notEqual(stapelZ.spec, a.spec, 'Stapel-Spec und Eintrags-Spec duerfen kein gemeinsames Objekt sein'); + + stapelZ.spec.partNumber = 'M393A4K40BB1-CTD'; + assert.equal(a.spec.partNumber, null, 'eine Ergaenzung des neu angelegten Stapel-Specs darf das Eintrags-Spec nicht veraendern'); +}); + +test('undoLast-Vertrag: nach einem Umsortieren wird weiterhin der zuletzt erfasste Eintrag zurueckgenommen', () => { + const session = createSession(); + const a = scan(session, s64()); + const b = scan(session, s32()); + moveEntry(session, a.entryId, 'B'); + // Zuletzt ausgefuehrte Handlung war das Umsortieren von a; zuletzt erfasst wurde jedoch b. + const entfernt = undoLast(session); + assert.equal(entfernt.entryId, b.entryId, 'undoLast nimmt den zuletzt erfassten Eintrag zurueck, nicht die zuletzt ausgefuehrte Handlung (das Umsortieren)'); + assert.equal(session.entries.length, 1); + assert.equal(session.entries[0].entryId, a.entryId); + assert.equal(session.entries[0].stackId, 'B', 'das Umsortieren von a bleibt von der Rueckname des unbeteiligten Eintrags b unberuehrt'); + const stapelA = session.stacks.find((s) => s.id === 'A'); + const stapelB = session.stacks.find((s) => s.id === 'B'); + assert.equal(stapelA, undefined, 'Stapel A ist seit dem Umsortieren leer und wurde bereits entfernt'); + assert.equal(stapelB.count, 1, 'Stapel B enthaelt weiterhin a, nur b wurde zurueckgenommen'); +});