58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
export interface HttpFailureContext {
|
|
role?: string;
|
|
url: string;
|
|
status: number;
|
|
location?: string | null;
|
|
html?: string;
|
|
extra?: string;
|
|
serverLogs?: string;
|
|
}
|
|
|
|
export class HttpDiagnostics {
|
|
static clipString(str: string, max = 1200): string {
|
|
if (str.length <= max) return str;
|
|
return str.substring(0, max) + `... [clipped ${str.length - max} chars]`;
|
|
}
|
|
|
|
static formatHttpFailure({ role, url, status, location, html, extra, serverLogs }: HttpFailureContext): string {
|
|
const lines = [
|
|
`HTTP Failure: ${status} for ${url}`,
|
|
role ? `Role: ${role}` : null,
|
|
location ? `Location: ${location}` : null,
|
|
extra ? `Extra: ${extra}` : null,
|
|
html ? `HTML Body (clipped):\n${this.clipString(html)}` : 'No HTML body provided',
|
|
serverLogs ? `\n--- Server Log Tail ---\n${serverLogs}` : null,
|
|
].filter(Boolean);
|
|
|
|
return lines.join('\n');
|
|
}
|
|
|
|
static assertHtmlContains(html: string, mustContain: string | string[], context: HttpFailureContext): void {
|
|
const targets = Array.isArray(mustContain) ? mustContain : [mustContain];
|
|
for (const target of targets) {
|
|
if (!html.includes(target)) {
|
|
const message = this.formatHttpFailure({
|
|
...context,
|
|
extra: `Expected HTML to contain: "${target}"`,
|
|
html,
|
|
});
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
static assertHtmlNotContains(html: string, mustNotContain: string | string[], context: HttpFailureContext): void {
|
|
const targets = Array.isArray(mustNotContain) ? mustNotContain : [mustNotContain];
|
|
for (const target of targets) {
|
|
if (html.includes(target)) {
|
|
const message = this.formatHttpFailure({
|
|
...context,
|
|
extra: `Expected HTML NOT to contain: "${target}"`,
|
|
html,
|
|
});
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
}
|
|
}
|