import { assertShipment, assertReturn, advanceTracking, } from '../src/fulfillment/fulfillment.policy'; describe('shipping and return blueprint policies', () => { it('requires payment and bounds partial shipments', () => { expect(() => assertShipment(true, 5, 2, 3)).not.toThrow(); expect(() => assertShipment(false, 5, 0, 1)).toThrow(); for (const quantity of [0, -1, 0.5, 4]) expect(() => assertShipment(true, 5, 2, quantity)).toThrow(); expect(() => assertShipment(true, 0, 0, 1)).toThrow(); expect(() => assertShipment(true, 5, -1, 1)).toThrow(); }); it('does not regress tracking on duplicated or out-of-order events', () => { expect(advanceTracking('PLANNED', 'SHIPPED')).toBe('SHIPPED'); expect(advanceTracking('SHIPPED', 'DELIVERED')).toBe('DELIVERED'); expect(advanceTracking('DELIVERED', 'SHIPPED')).toBe('DELIVERED'); expect(advanceTracking('DELIVERED', 'DELIVERED')).toBe('DELIVERED'); }); it('counts existing and pending returns and enforces the configured window', () => { const input = { delivered: 5, returned: 1, pending: 1, requested: 3, deliveredAt: new Date(0), now: new Date(86400000), windowDays: 1, }; expect(() => assertReturn(input)).not.toThrow(); for (const change of [ { requested: 4 }, { requested: 0 }, { requested: 0.5 }, { delivered: -1 }, { now: new Date(86400001) }, { now: new Date(-1) }, { windowDays: -1 }, { deliveredAt: new Date('invalid') }, ]) expect(() => assertReturn({ ...input, ...change })).toThrow(); }); });