166 lines
6.0 KiB
JavaScript
166 lines
6.0 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import request from 'supertest';
|
|
import { createApp } from '../src/app.js';
|
|
|
|
process.env.AUTH_BYPASS = 'true';
|
|
|
|
const tenantId = '11111111-1111-4111-8111-111111111111';
|
|
const orderId = '22222222-2222-4222-8222-222222222222';
|
|
const businessId = '33333333-3333-4333-8333-333333333333';
|
|
const staffId = '44444444-4444-4444-8444-444444444444';
|
|
const assignmentId = '55555555-5555-4555-8555-555555555555';
|
|
|
|
test('GET /healthz returns healthy response', async () => {
|
|
const app = createApp();
|
|
const res = await request(app).get('/healthz');
|
|
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.body.ok, true);
|
|
assert.equal(res.body.service, 'krow-query-api');
|
|
assert.equal(typeof res.body.requestId, 'string');
|
|
assert.equal(typeof res.headers['x-request-id'], 'string');
|
|
});
|
|
|
|
test('GET /readyz reports database not configured when no database env is present', async () => {
|
|
delete process.env.DATABASE_URL;
|
|
delete process.env.DB_HOST;
|
|
delete process.env.DB_NAME;
|
|
delete process.env.DB_USER;
|
|
delete process.env.DB_PASSWORD;
|
|
delete process.env.INSTANCE_CONNECTION_NAME;
|
|
|
|
const app = createApp();
|
|
const res = await request(app).get('/readyz');
|
|
|
|
assert.equal(res.status, 503);
|
|
assert.equal(res.body.status, 'DATABASE_NOT_CONFIGURED');
|
|
});
|
|
|
|
test.afterEach(() => {
|
|
delete process.env.AUTH_BYPASS_CONTEXT;
|
|
});
|
|
|
|
test('createApp fails fast in protected env when auth bypass is enabled', async () => {
|
|
process.env.APP_ENV = 'staging';
|
|
process.env.AUTH_BYPASS = 'true';
|
|
|
|
assert.throws(() => createApp(), /AUTH_BYPASS must be disabled/);
|
|
|
|
delete process.env.APP_ENV;
|
|
process.env.AUTH_BYPASS = 'true';
|
|
});
|
|
|
|
test('GET unknown route returns not found envelope', async () => {
|
|
const app = createApp();
|
|
const res = await request(app).get('/query/unknown');
|
|
|
|
assert.equal(res.status, 404);
|
|
assert.equal(res.body.code, 'NOT_FOUND');
|
|
assert.equal(typeof res.body.requestId, 'string');
|
|
});
|
|
|
|
test('GET /query/tenants/:tenantId/orders returns injected query result', async () => {
|
|
const app = createApp({
|
|
queryService: {
|
|
listOrders: async (params) => {
|
|
assert.equal(params.tenantId, tenantId);
|
|
return [{
|
|
id: orderId,
|
|
orderNumber: 'ORD-1001',
|
|
title: 'Cafe Event Staffing',
|
|
status: 'OPEN',
|
|
}];
|
|
},
|
|
getOrderDetail: async () => assert.fail('getOrderDetail should not be called'),
|
|
listFavoriteStaff: async () => assert.fail('listFavoriteStaff should not be called'),
|
|
getStaffReviewSummary: async () => assert.fail('getStaffReviewSummary should not be called'),
|
|
getAssignmentAttendance: async () => assert.fail('getAssignmentAttendance should not be called'),
|
|
},
|
|
});
|
|
|
|
const res = await request(app)
|
|
.get(`/query/tenants/${tenantId}/orders`)
|
|
.set('Authorization', 'Bearer test-token');
|
|
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.body.items.length, 1);
|
|
assert.equal(res.body.items[0].id, orderId);
|
|
});
|
|
|
|
test('GET /query/tenants/:tenantId/assignments/:assignmentId/attendance returns injected attendance', async () => {
|
|
const app = createApp({
|
|
queryService: {
|
|
listOrders: async () => assert.fail('listOrders should not be called'),
|
|
getOrderDetail: async () => assert.fail('getOrderDetail should not be called'),
|
|
listFavoriteStaff: async () => assert.fail('listFavoriteStaff should not be called'),
|
|
getStaffReviewSummary: async () => assert.fail('getStaffReviewSummary should not be called'),
|
|
getAssignmentAttendance: async (params) => {
|
|
assert.equal(params.tenantId, tenantId);
|
|
assert.equal(params.assignmentId, assignmentId);
|
|
return {
|
|
assignmentId,
|
|
sessionStatus: 'OPEN',
|
|
events: [],
|
|
};
|
|
},
|
|
},
|
|
});
|
|
|
|
const res = await request(app)
|
|
.get(`/query/tenants/${tenantId}/assignments/${assignmentId}/attendance`)
|
|
.set('Authorization', 'Bearer test-token');
|
|
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.body.assignmentId, assignmentId);
|
|
assert.equal(res.body.sessionStatus, 'OPEN');
|
|
});
|
|
|
|
test('GET /query/tenants/:tenantId/businesses/:businessId/favorite-staff validates auth and handler wiring', async () => {
|
|
const app = createApp({
|
|
queryService: {
|
|
listOrders: async () => assert.fail('listOrders should not be called'),
|
|
getOrderDetail: async () => assert.fail('getOrderDetail should not be called'),
|
|
listFavoriteStaff: async (params) => {
|
|
assert.equal(params.tenantId, tenantId);
|
|
assert.equal(params.businessId, businessId);
|
|
return [{ staffId, fullName: 'Ana Barista' }];
|
|
},
|
|
getStaffReviewSummary: async () => assert.fail('getStaffReviewSummary should not be called'),
|
|
getAssignmentAttendance: async () => assert.fail('getAssignmentAttendance should not be called'),
|
|
},
|
|
});
|
|
|
|
const res = await request(app)
|
|
.get(`/query/tenants/${tenantId}/businesses/${businessId}/favorite-staff`)
|
|
.set('Authorization', 'Bearer test-token');
|
|
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.body.items[0].staffId, staffId);
|
|
});
|
|
|
|
test('GET /query/tenants/:tenantId/orders denies mismatched tenant scope before handler execution', async () => {
|
|
process.env.AUTH_BYPASS_CONTEXT = JSON.stringify({
|
|
user: { userId: 'test-user' },
|
|
tenant: { tenantId: '99999999-9999-4999-8999-999999999999', role: 'MANAGER' },
|
|
business: { businessId },
|
|
});
|
|
|
|
const app = createApp({
|
|
queryService: {
|
|
listOrders: async () => assert.fail('listOrders should not be called'),
|
|
getOrderDetail: async () => assert.fail('getOrderDetail should not be called'),
|
|
listFavoriteStaff: async () => assert.fail('listFavoriteStaff should not be called'),
|
|
getStaffReviewSummary: async () => assert.fail('getStaffReviewSummary should not be called'),
|
|
getAssignmentAttendance: async () => assert.fail('getAssignmentAttendance should not be called'),
|
|
},
|
|
});
|
|
|
|
const res = await request(app)
|
|
.get(`/query/tenants/${tenantId}/orders`)
|
|
.set('Authorization', 'Bearer test-token');
|
|
|
|
assert.equal(res.status, 403);
|
|
assert.equal(res.body.code, 'FORBIDDEN');
|
|
});
|