mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
fix(cli): honor check navigation timeout (#2860)
* fix(cli): honor check navigation timeout * test(cli): clarify diagnostic timeout precedence
This commit is contained in:
@@ -542,7 +542,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
|
||||
| `--snapshots` | Write overview frames (annotated with labeled finding boxes when there are errors) plus `finding-NN-<code>.png` crops |
|
||||
| `--samples` / `--at` / `--at-transitions` | Control the seek grid (default 9 samples; `--at-transitions` adds tween boundaries) |
|
||||
| `--tolerance` | Allowed overflow in px before reporting (default 2) |
|
||||
| `--timeout` | Initial settle budget in ms (default 3000) |
|
||||
| `--timeout` | Initial render-ready budget in ms; also raises the page-navigation budget above its 10s floor (default 3000) |
|
||||
| `--no-contrast` | Skip the WCAG audit while iterating |
|
||||
| `--strict` | Exit non-zero on warnings too (default: only errors) |
|
||||
| `--caption-zone "<x0=..;y0=..;x1=..;y1=..>"` | Opt-in band gate: flags content whose center sits inside the fractional band (optional `severity`, `seek`) |
|
||||
|
||||
@@ -61,6 +61,9 @@ export interface SettledCompositionPage {
|
||||
}
|
||||
|
||||
export interface OpenSettledCompositionPageOptions {
|
||||
// Separate from the post-navigation render-ready budget. Diagnostic callers
|
||||
// without their own navigation knob keep the historical 10-second minimum.
|
||||
navigationTimeoutMs?: number;
|
||||
renderReadyTimeoutMs: number;
|
||||
renderReadyWarningSuffix: string;
|
||||
// Screenshot paths take the engine's software-GPU default; validate/check
|
||||
@@ -182,7 +185,7 @@ export async function openSettledCompositionPage(
|
||||
await options.beforeNavigate?.(page);
|
||||
await page.goto(url, {
|
||||
waitUntil: "domcontentloaded",
|
||||
timeout: resolveDiagnosticNavigationTimeoutMs(),
|
||||
timeout: resolveDiagnosticNavigationTimeoutMs(process.env, options.navigationTimeoutMs),
|
||||
});
|
||||
const renderReadyTimedOut = !(await waitForCompositionSettle(page, options));
|
||||
return { browser: chromeBrowser, page, renderReadyTimedOut };
|
||||
|
||||
@@ -86,7 +86,8 @@ export function createCheckCommand(
|
||||
},
|
||||
timeout: {
|
||||
type: "string",
|
||||
description: "Ms to wait for scripts and media to settle initially (default: 3000)",
|
||||
description:
|
||||
"Initial render-ready timeout in ms; also sets the navigation minimum (10s floor, default: 3000)",
|
||||
default: "3000",
|
||||
},
|
||||
contrast: {
|
||||
|
||||
@@ -155,6 +155,28 @@ it("carries raw browser geometry through the page driver and pipeline", async ()
|
||||
expect(mocks.serverClose).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("uses check --timeout for both navigation and render-ready settling", async () => {
|
||||
mountCanvasFixture();
|
||||
const page = fakePage();
|
||||
installSessionMock(page);
|
||||
|
||||
await runBrowserCheck(
|
||||
PROJECT,
|
||||
{ ...DEFAULT_CHECK_OPTIONS, samples: 1, contrast: false, timeout: 30_000 },
|
||||
{ kind: "none" },
|
||||
runAuditGrid,
|
||||
);
|
||||
|
||||
expect(openSettledCompositionPage).toHaveBeenCalledWith(
|
||||
"<html></html>",
|
||||
"http://127.0.0.1:3000",
|
||||
expect.objectContaining({
|
||||
navigationTimeoutMs: 30_000,
|
||||
renderReadyTimeoutMs: 30_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("round-trips the browser script's raw contrast candidates back into finish", async () => {
|
||||
// The U2 regression class: Node parses prepare's candidates for reporting,
|
||||
// but must hand the UNTOUCHED objects back to __contrastAuditFinish — the
|
||||
|
||||
@@ -165,6 +165,7 @@ export async function runBrowserCheck(
|
||||
try {
|
||||
const launchSettleStart = Date.now();
|
||||
const session = await openSettledCompositionPage(html, server.url, {
|
||||
navigationTimeoutMs: options.timeout,
|
||||
renderReadyTimeoutMs: options.timeout,
|
||||
renderReadyWarningSuffix: "checking the current page state",
|
||||
browserGpuMode: resolveCliChromeGpuMode(),
|
||||
@@ -225,6 +226,7 @@ export async function captureFindingCrops(
|
||||
const written: string[] = [];
|
||||
try {
|
||||
const session = await openSettledCompositionPage(html, server.url, {
|
||||
navigationTimeoutMs: options.timeout,
|
||||
renderReadyTimeoutMs: options.timeout,
|
||||
renderReadyWarningSuffix: "capturing finding crops",
|
||||
browserGpuMode: resolveCliChromeGpuMode(),
|
||||
|
||||
@@ -118,6 +118,23 @@ describe("resolveDiagnosticNavigationTimeoutMs", () => {
|
||||
resolveDiagnosticNavigationTimeoutMs({ PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS: "invalid" }),
|
||||
).toBe(10_000);
|
||||
});
|
||||
|
||||
it("raises the diagnostic navigation budget to a larger caller-provided minimum", () => {
|
||||
expect(resolveDiagnosticNavigationTimeoutMs({}, 30_000)).toBe(30_000);
|
||||
});
|
||||
|
||||
it("does not let a caller-provided minimum shorten the default budget", () => {
|
||||
expect(resolveDiagnosticNavigationTimeoutMs({}, 3_000)).toBe(10_000);
|
||||
});
|
||||
|
||||
it("does not let a caller-provided minimum shorten the environment override", () => {
|
||||
expect(
|
||||
resolveDiagnosticNavigationTimeoutMs(
|
||||
{ PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS: "90000" },
|
||||
30_000,
|
||||
),
|
||||
).toBe(90_000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseCompositionEntryArg", () => {
|
||||
|
||||
@@ -118,12 +118,20 @@ export function resolveBrowserTimeoutMsArg(raw: string | undefined): number | un
|
||||
return result.value;
|
||||
}
|
||||
|
||||
/** Navigation budget shared by snapshot/check/inspect browser diagnostics. */
|
||||
/**
|
||||
* Navigation budget shared by snapshot/check/inspect browser diagnostics.
|
||||
*
|
||||
* The environment variable remains the historical global override. Callers
|
||||
* with their own timeout knob can supply a minimum without shortening that
|
||||
* override or the existing 10-second default.
|
||||
*/
|
||||
export function resolveDiagnosticNavigationTimeoutMs(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
minimumTimeoutMs = 0,
|
||||
): number {
|
||||
const parsed = Number(env.PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : 10_000;
|
||||
const configured = Number.isFinite(parsed) && parsed > 0 ? parsed : 10_000;
|
||||
return Math.max(configured, minimumTimeoutMs);
|
||||
}
|
||||
|
||||
// ── --composition ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"files": 121
|
||||
},
|
||||
"hyperframes-cli": {
|
||||
"hash": "966972db5ab8f932",
|
||||
"hash": "42b621ca580541b6",
|
||||
"files": 11
|
||||
},
|
||||
"hyperframes-core": {
|
||||
|
||||
@@ -36,7 +36,7 @@ npx hyperframes check --samples 15 # denser timeline sweep (default 9)
|
||||
npx hyperframes check --at 1.5,4,7.25 # explicit hero-frame timestamps
|
||||
npx hyperframes check --at-transitions # also sample every tween start/end boundary
|
||||
npx hyperframes check --tolerance 4 # allowed overflow px before reporting (default 2)
|
||||
npx hyperframes check --timeout 5000 # ms for the initial settle (default 3000)
|
||||
npx hyperframes check --timeout 30000 # initial render-ready + navigation minimum in ms (defaults: 3000 / 10000)
|
||||
npx hyperframes check --no-contrast # skip the WCAG audit while iterating
|
||||
npx hyperframes check --strict # exit non-zero on warnings too (default: only errors)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user