54 lines
1.7 KiB
TypeScript
54 lines
1.7 KiB
TypeScript
import { randomUUID } from 'node:crypto';
|
|
import {
|
|
adjustedBalance,
|
|
assertReplay,
|
|
commandHash,
|
|
} from '../src/inventory/inventory.policy';
|
|
import {
|
|
reservationSchema,
|
|
adjustmentSchema,
|
|
} from '../src/inventory/inventory.schemas';
|
|
import { variantSchema } from '../src/catalog/catalog.schemas';
|
|
|
|
describe('inventory and catalogue input policy', () => {
|
|
it('protects reserved stock and integer capacity', () => {
|
|
expect(adjustedBalance(10, 5, -5)).toBe(5);
|
|
expect(() => adjustedBalance(10, 5, -6)).toThrow(
|
|
'Insufficient available stock',
|
|
);
|
|
expect(() => adjustedBalance(0, 0, -1)).toThrow();
|
|
expect(() => adjustedBalance(2_000_000_000, 0, 1)).toThrow(
|
|
'Stock balance limit',
|
|
);
|
|
});
|
|
it('distinguishes idempotent request payloads', () => {
|
|
const hash = commandHash('stock', 1, 'reason');
|
|
expect(() => assertReplay(hash, hash)).not.toThrow();
|
|
expect(() => assertReplay(hash, commandHash('stock', 2, 'reason'))).toThrow(
|
|
'different request',
|
|
);
|
|
});
|
|
it('bounds reservation quantity and duration', () => {
|
|
const input = {
|
|
stockItemId: randomUUID(),
|
|
quantity: 1,
|
|
idempotencyKey: randomUUID(),
|
|
};
|
|
expect(reservationSchema.parse(input).ttlMinutes).toBe(15);
|
|
expect(
|
|
reservationSchema.safeParse({ ...input, ttlMinutes: 61 }).success,
|
|
).toBe(false);
|
|
expect(
|
|
adjustmentSchema.safeParse({ ...input, delta: 0, reason: 'bad' }).success,
|
|
).toBe(false);
|
|
});
|
|
it.each(['0.00', '-1.00', '1.001', '01.00', '10000000000.00'])(
|
|
'rejects invalid prices %s',
|
|
(price) => {
|
|
expect(
|
|
variantSchema.safeParse({ name: 'Test', sku: 'SKU', price }).success,
|
|
).toBe(false);
|
|
},
|
|
);
|
|
});
|