import { orderConsistWagons } from './consist-order.util'; // Built train: A-B-C-D coupled in that order. Slots are created by the wagon // PLAN, so their sequenceNo says nothing about where the wagon actually sits. const TRAIN = ['A', 'B', 'C', 'D']; const slot = (sequenceNo: number, physicalWagonId: string | null) => ({ sequenceNo, physicalWagonId, }); describe('orderConsistWagons', () => { it('draws slots in the train coupling order, not slot order', () => { // Plan order says D then B; the train says B sits ahead of D. const drawn = orderConsistWagons([slot(1, 'D'), slot(2, 'B')], { physicalWagonIdsInOrder: TRAIN, }); expect(drawn.map((w) => w.physicalWagonId)).toEqual(['B', 'D']); expect(drawn.map((w) => w.position)).toEqual([1, 2]); }); it('interleaves empty consist wagons in their real place', () => { // Loaded slots on A and C; B and D ride along empty. The empties used to be // appended after every loaded slot, so the drawing was never the train. const drawn = orderConsistWagons( [slot(1, 'A'), slot(2, 'C'), slot(98, 'B'), slot(99, 'D')], { physicalWagonIdsInOrder: TRAIN }, ); expect(drawn.map((w) => w.physicalWagonId)).toEqual(['A', 'B', 'C', 'D']); }); it('keeps every wagon in place when a load moves between wagons', () => { // Load sat on A (slot 1); staff drag it onto empty D. The move repins the // slot, so the SAME slot now reads as wagon D and A falls back to empty. const before = orderConsistWagons([slot(1, 'A'), slot(98, 'D')], { physicalWagonIdsInOrder: TRAIN, }); const after = orderConsistWagons([slot(1, 'D'), slot(98, 'A')], { physicalWagonIdsInOrder: TRAIN, }); // A is drawn first and D last, before and after — the train did not shuffle. expect(before.map((w) => w.physicalWagonId)).toEqual(['A', 'D']); expect(after.map((w) => w.physicalWagonId)).toEqual(['A', 'D']); }); it('follows a train-builder reorder without touching any slot row', () => { const slots = [slot(1, 'A'), slot(2, 'B')]; // Builder swaps the coupling order; the slots are untouched. const drawn = orderConsistWagons(slots, { physicalWagonIdsInOrder: ['B', 'A', 'C', 'D'], }); expect(drawn.map((w) => w.physicalWagonId)).toEqual(['B', 'A']); }); it('draws back-to-front when the caller reverses the train', () => { const drawn = orderConsistWagons([slot(1, 'A'), slot(2, 'C')], { physicalWagonIdsInOrder: [...TRAIN].reverse(), reverseWagonOrder: true, }); expect(drawn.map((w) => w.physicalWagonId)).toEqual(['C', 'A']); }); it('parks unpinned slots last, in slot order', () => { const drawn = orderConsistWagons([slot(9, null), slot(4, null), slot(1, 'C')], { physicalWagonIdsInOrder: TRAIN, }); expect(drawn.map((w) => [w.physicalWagonId, w.sequenceNo])).toEqual([ ['C', 1], [null, 4], [null, 9], ]); }); it('falls back to slot order when there is no built train', () => { // Frozen schedules and loose-wagon schedules pass no physical order. const drawn = orderConsistWagons([slot(2, 'X'), slot(1, 'Y')], { physicalWagonIdsInOrder: [], }); expect(drawn.map((w) => w.sequenceNo)).toEqual([1, 2]); const reversed = orderConsistWagons([slot(1, 'X'), slot(2, 'Y')], { physicalWagonIdsInOrder: [], reverseWagonOrder: true, }); expect(reversed.map((w) => w.sequenceNo)).toEqual([2, 1]); }); });