Files
support_backend/tests/load/admin-reporting.load.ts
T

70 lines
2.3 KiB
TypeScript
Raw Normal View History

/**
* specs/016-load-concurrency-testing User Story 5 / FR-007: load/throughput baseline for the
* 015-reporting-dashboards admin endpoints — pure database aggregation reads, no third-party
* cost (unlike ai-support-flow.load.ts). Run against a real running dev server:
* `npx tsx tests/load/admin-reporting.load.ts`.
*
* Signs in as the project's own seeded admin account once (a session JWT is reusable across
* requests, unlike 002-saas-integration's single-use integration tokens), then cycles across
* all four dashboards so the report reflects a realistic mix of the endpoint group, not just one
* route.
*/
import { runLoadTest } from './autocannon.config';
const API_URL = process.env.LOAD_TEST_API_URL ?? 'http://localhost:4501';
const CONNECTIONS = Number(process.env.LOAD_TEST_CONNECTIONS ?? 10);
const DURATION_SEC = Number(process.env.LOAD_TEST_DURATION_SEC ?? 10);
const ADMIN_EMAIL = process.env.LOAD_TEST_ADMIN_EMAIL ?? 'admin@supporthub.internal';
const ADMIN_PASSWORD = process.env.LOAD_TEST_ADMIN_PASSWORD ?? 'ChangeMe123!';
const DASHBOARD_PATHS = [
'/admin/reports/management',
'/admin/reports/support',
'/admin/reports/ai',
];
async function signIn(): Promise<string> {
const response = await fetch(`${API_URL}/auth/login`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email: ADMIN_EMAIL, password: ADMIN_PASSWORD }),
});
if (!response.ok) {
throw new Error(
`Admin sign-in failed (${response.status}) — set LOAD_TEST_ADMIN_EMAIL/PASSWORD if the seeded admin credentials differ.`,
);
}
const body = (await response.json()) as { data: { token: string } };
return body.data.token;
}
async function main(): Promise<void> {
const token = await signIn();
let requestIndex = 0;
await runLoadTest('admin-reporting', {
url: API_URL,
connections: CONNECTIONS,
duration: DURATION_SEC,
requests: [
{
method: 'GET',
headers: { authorization: `Bearer ${token}` },
setupRequest: (request) => {
request.path = DASHBOARD_PATHS[requestIndex % DASHBOARD_PATHS.length];
requestIndex += 1;
return request;
},
},
],
});
}
main()
.then(() => process.exit(0))
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
process.exit(1);
});