feat(backend): implement v2 domain slice and live smoke

This commit is contained in:
zouantchaw
2026-03-11 18:23:55 +01:00
parent bc068373e9
commit fe43ff23cf
40 changed files with 5191 additions and 99 deletions

View File

@@ -6,9 +6,42 @@ import { __resetIdempotencyStoreForTests } from '../src/services/idempotency-sto
process.env.AUTH_BYPASS = 'true';
const tenantId = '11111111-1111-4111-8111-111111111111';
const businessId = '22222222-2222-4222-8222-222222222222';
const shiftId = '33333333-3333-4333-8333-333333333333';
function validOrderCreatePayload() {
return {
tenantId,
businessId,
orderNumber: 'ORD-1001',
title: 'Cafe Event Staffing',
serviceType: 'EVENT',
shifts: [
{
shiftCode: 'SHIFT-1',
title: 'Morning Shift',
startsAt: '2026-03-11T08:00:00.000Z',
endsAt: '2026-03-11T16:00:00.000Z',
requiredWorkers: 2,
roles: [
{
roleCode: 'BARISTA',
roleName: 'Barista',
workersNeeded: 2,
payRateCents: 2200,
billRateCents: 3500,
},
],
},
],
};
}
beforeEach(() => {
process.env.IDEMPOTENCY_STORE = 'memory';
delete process.env.IDEMPOTENCY_DATABASE_URL;
delete process.env.DATABASE_URL;
__resetIdempotencyStoreForTests();
});
@@ -21,34 +54,65 @@ test('GET /healthz returns healthy response', async () => {
assert.equal(typeof res.body.requestId, 'string');
});
test('GET /readyz reports database not configured when no database env is present', async () => {
const app = createApp();
const res = await request(app).get('/readyz');
assert.equal(res.status, 503);
assert.equal(res.body.ok, false);
assert.equal(res.body.status, 'DATABASE_NOT_CONFIGURED');
});
test('command route requires idempotency key', async () => {
const app = createApp();
const res = await request(app)
.post('/commands/orders/create')
.set('Authorization', 'Bearer test-token')
.send({ payload: {} });
.send(validOrderCreatePayload());
assert.equal(res.status, 400);
assert.equal(res.body.code, 'MISSING_IDEMPOTENCY_KEY');
});
test('command route is idempotent by key', async () => {
const app = createApp();
test('command route is idempotent by key and only executes handler once', async () => {
let callCount = 0;
const app = createApp({
commandHandlers: {
createOrder: async () => {
callCount += 1;
return {
orderId: '44444444-4444-4444-8444-444444444444',
orderNumber: 'ORD-1001',
status: 'OPEN',
shiftCount: 1,
shiftIds: [shiftId],
};
},
acceptShift: async () => assert.fail('acceptShift should not be called'),
clockIn: async () => assert.fail('clockIn should not be called'),
clockOut: async () => assert.fail('clockOut should not be called'),
addFavoriteStaff: async () => assert.fail('addFavoriteStaff should not be called'),
removeFavoriteStaff: async () => assert.fail('removeFavoriteStaff should not be called'),
createStaffReview: async () => assert.fail('createStaffReview should not be called'),
},
});
const first = await request(app)
.post('/commands/orders/create')
.set('Authorization', 'Bearer test-token')
.set('Idempotency-Key', 'abc-123')
.send({ payload: { order: 'x' } });
.send(validOrderCreatePayload());
const second = await request(app)
.post('/commands/orders/create')
.set('Authorization', 'Bearer test-token')
.set('Idempotency-Key', 'abc-123')
.send({ payload: { order: 'x' } });
.send(validOrderCreatePayload());
assert.equal(first.status, 200);
assert.equal(second.status, 200);
assert.equal(first.body.commandId, second.body.commandId);
assert.equal(callCount, 1);
assert.equal(first.body.orderId, second.body.orderId);
assert.equal(first.body.idempotencyKey, 'abc-123');
assert.equal(second.body.idempotencyKey, 'abc-123');
});