manicanldes-backend/test/inventory-policy.spec.ts

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);
},
);
});