Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/scripts/smoke-sentry.ts
T

76 lines
2.6 KiB
TypeScript

/* eslint-disable no-console -- CLI tool: stdout/stderr are the user interface. */
/**
* Sentry smoke-test driver for apps/web.
*
* Hits the test routes registered in apps/web/app/routes/__test.* and
* verifies that the HTTP responses look right. Use against a deployed
* staging environment after enabling SENTRY_TEST_ROUTES=true.
*
* Usage:
* pnpm exec tsx apps/web/scripts/smoke-sentry.ts https://app.staging.example
*
* Exit codes:
* 0 — all probes returned the expected status code
* 1 — at least one probe failed; details are printed to stderr
*
* @see docs/improvement-plan/02-observability/sentry-wiring-web.md (Step 11)
*/
interface Probe {
path: string;
note: string;
expectedStatus: number | number[];
}
const probes: Probe[] = [
{
path: "/__test/client-throw",
note: "Client-side throw smoke route (loader returns 200, component throws on render)",
expectedStatus: 200,
},
];
async function runProbe(baseUrl: string, probe: Probe): Promise<{ probe: Probe; ok: boolean; status: number; bodySnippet: string }> {
const url = new URL(probe.path, baseUrl).toString();
const response = await fetch(url, { redirect: "manual" });
const body = await response.text();
const expectedStatuses = Array.isArray(probe.expectedStatus) ? probe.expectedStatus : [probe.expectedStatus];
return {
probe,
ok: expectedStatuses.includes(response.status),
status: response.status,
bodySnippet: body.slice(0, 200),
};
}
export async function runSmoke(baseUrl: string): Promise<number> {
if (!baseUrl) {
console.error("usage: smoke-sentry.ts <baseUrl>");
return 1;
}
console.log(`[smoke-sentry] target=${baseUrl}`);
const results = await Promise.all(probes.map((p) => runProbe(baseUrl, p)));
let failures = 0;
for (const r of results) {
if (r.ok) {
console.log(`[ok] ${r.probe.path} → ${r.status} (${r.probe.note})`);
} else {
failures += 1;
console.error(`[fail] ${r.probe.path} → ${r.status} expected=${r.probe.expectedStatus} body=${r.bodySnippet}`);
}
}
if (failures > 0) {
console.error(`[smoke-sentry] ${failures} probe(s) failed`);
return 1;
}
console.log("[smoke-sentry] all probes passed");
console.log("[smoke-sentry] verify in Sentry UI: a client-throw event with stack-trace pointing to __test.client-throw.tsx");
return 0;
}
const isMain = typeof process !== "undefined" && Array.isArray(process.argv) && process.argv[1] && import.meta.url === `file://${process.argv[1]}`;
if (isMain) {
const baseUrl = process.argv[2] ?? process.env.SENTRY_SMOKE_BASE_URL ?? "";
runSmoke(baseUrl).then((code) => process.exit(code));
}