mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 11:55:47 -06:00
test(ui-e2e): scale Control UI wait budget for loaded CI runners (#123623)
ui-e2e intermittently failed with `page.waitForFunction: Timeout 10000ms exceeded` on loaded CI runners (model-agent-scoping, terminal-embedded), both green on rerun. The 10s deadlines were repo-imposed at the mock Gateway helper and readiness helper, plus twelve per-test setDefaultTimeout sprinkles. Give the harness one owner for the wait budget: 30s under CI, 10s locally, mirroring the ui-e2e vitest config's existing expect.poll reasoning. Suite-created contexts inherit it, so two per-test overrides are deleted outright.
This commit is contained in:
committed by
GitHub
parent
5c3fd2fbe9
commit
c9152fef4e
@@ -6,7 +6,11 @@ import type {
|
||||
AllowedApprovalSnapshot,
|
||||
PendingApprovalSnapshot,
|
||||
} from "../../../packages/gateway-protocol/src/index.js";
|
||||
import { installMockGateway, type MockGatewayControls } from "../test-helpers/control-ui-e2e.ts";
|
||||
import {
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
type MockGatewayControls,
|
||||
} from "../test-helpers/control-ui-e2e.ts";
|
||||
import { createControlUiE2eSuite } from "./control-ui-e2e-suite.test-support.ts";
|
||||
|
||||
const suite = createControlUiE2eSuite({
|
||||
@@ -109,7 +113,7 @@ async function createSurface(params: {
|
||||
});
|
||||
openContexts.add(context);
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
await page.clock.setFixedTime(new Date(APPROVAL_NOW_MS));
|
||||
const pageErrors: string[] = [];
|
||||
page.on("pageerror", (error) => pageErrors.push(String(error)));
|
||||
|
||||
@@ -5,6 +5,7 @@ import { chromium, type Browser } from "playwright";
|
||||
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
@@ -38,7 +39,7 @@ describeControlUiE2e("Control UI chat file links", () => {
|
||||
viewport: { height: 900, width: 1280 },
|
||||
});
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(15_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
try {
|
||||
const gateway = await installMockGateway(page, {
|
||||
historyMessages: [
|
||||
@@ -192,7 +193,7 @@ describeControlUiE2e("Control UI chat file links", () => {
|
||||
});
|
||||
try {
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(15_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
const gateway = await installMockGateway(page, {
|
||||
methodResponses: {
|
||||
"sessions.files.get": {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { chromium, type Browser, type BrowserContext, type Page } from "playwrig
|
||||
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
@@ -132,7 +133,7 @@ async function newRecordedPage(label: string): Promise<RecordedPage> {
|
||||
viewport,
|
||||
});
|
||||
page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
return { browser, context, page, rawVideoDir };
|
||||
} catch (error) {
|
||||
await page?.close().catch(() => {});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import path from "node:path";
|
||||
import type { BrowserContext, Page } from "playwright";
|
||||
import { expect, it } from "vitest";
|
||||
import { installMockGateway } from "../test-helpers/control-ui-e2e.ts";
|
||||
import { controlUiE2eWaitTimeoutMs, installMockGateway } from "../test-helpers/control-ui-e2e.ts";
|
||||
import { createControlUiE2eSuite } from "./control-ui-e2e-suite.test-support.ts";
|
||||
|
||||
const suite = createControlUiE2eSuite({
|
||||
@@ -123,7 +123,7 @@ async function openChat(
|
||||
viewport: { height: 900, width: 1280 },
|
||||
});
|
||||
page = await context.newPage();
|
||||
page.setDefaultTimeout(15_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
const gateway = await installMockGateway(page, {
|
||||
deferredMethods,
|
||||
methodResponses: { "models.authStatus": authStatus, ...extraMethodResponses },
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from "../../../src/test-utils/openclaw-test-state.js";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
type ControlUiE2eServer,
|
||||
@@ -470,7 +471,7 @@ async function createBrowserPage(
|
||||
const page = await context.newPage();
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", (error) => errors.push(String(error)));
|
||||
page.setDefaultTimeout(15_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
const evidenceStartIndex = proxy.evidence.length;
|
||||
const response = await page.goto(withGatewayUrl(baseUrl, gatewayUrl), {
|
||||
timeout: controlUiSettleTimeoutMs,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { ConnectErrorDetailCodes } from "../../../packages/gateway-protocol/src/connect-error-details.js";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
@@ -51,7 +52,7 @@ async function createCredentialPage(): Promise<{
|
||||
});
|
||||
openContexts.add(context);
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
const gateway = await installMockGateway(page, { deferredMethods: ["connect"] });
|
||||
const response = await page.goto(server.baseUrl);
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { chromium, type Browser, type BrowserContext, type Page } from "playwrig
|
||||
import { afterAll, afterEach, beforeAll, describe } from "vitest";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
type ControlUiE2eServer,
|
||||
@@ -57,6 +58,8 @@ export function createControlUiE2eSuite(options: ControlUiE2eSuiteOptions): Cont
|
||||
throw new Error("Control UI E2E browser accessed before suite setup");
|
||||
}
|
||||
const context = await browser.newContext(contextOptions);
|
||||
// Harness owns the wait budget; per-test setDefaultTimeout sprinkles defeat CI scaling.
|
||||
context.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
openBrowserContexts.add(context);
|
||||
return context;
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { ConnectErrorDetailCodes } from "../../../packages/gateway-protocol/src/connect-error-details.js";
|
||||
import {
|
||||
canRunPlaywrightChromium,
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
resolvePlaywrightChromiumExecutablePath,
|
||||
startControlUiE2eServer,
|
||||
@@ -34,7 +35,7 @@ async function createPage(): Promise<Page> {
|
||||
});
|
||||
openContexts.add(context);
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,8 +236,6 @@ suite.define(() => {
|
||||
viewport: { height: 900, width: 1440 },
|
||||
},
|
||||
async ({ page }) => {
|
||||
page.setDefaultTimeout(10_000);
|
||||
|
||||
const gateway = await installMockGateway(page, {
|
||||
historyMessages: [
|
||||
{
|
||||
@@ -407,8 +405,6 @@ suite.define(() => {
|
||||
viewport: { height: 900, width: 1440 },
|
||||
},
|
||||
async ({ page }) => {
|
||||
page.setDefaultTimeout(10_000);
|
||||
|
||||
const gateway = await installMockGateway(page, {
|
||||
assistantAgentId: "work",
|
||||
defaultAgentId: "work",
|
||||
|
||||
@@ -3,7 +3,11 @@ import path from "node:path";
|
||||
import type { BrowserContext, Page } from "playwright";
|
||||
import { expect, it } from "vitest";
|
||||
import { createControlUiE2eSuite } from "../../e2e/control-ui-e2e-suite.test-support.ts";
|
||||
import { installMockGateway, waitForControlUiRoute } from "../../test-helpers/control-ui-e2e.ts";
|
||||
import {
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
waitForControlUiRoute,
|
||||
} from "../../test-helpers/control-ui-e2e.ts";
|
||||
|
||||
const suite = createControlUiE2eSuite({
|
||||
name: "Control UI Workboard routing",
|
||||
@@ -64,7 +68,7 @@ async function newRecordedPage(label: string): Promise<{
|
||||
viewport: { width: 1600, height: 1000 },
|
||||
});
|
||||
const page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
return { context, page, rawVideoDir };
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import type {
|
||||
WorkboardStatus,
|
||||
} from "../../lib/workboard/index.ts";
|
||||
import {
|
||||
controlUiE2eWaitTimeoutMs,
|
||||
installMockGateway,
|
||||
type MockGatewayControls,
|
||||
type MockGatewayRequest,
|
||||
@@ -302,7 +303,7 @@ async function newRecordedPage(label: string): Promise<RecordedPage> {
|
||||
viewport,
|
||||
});
|
||||
page = await context.newPage();
|
||||
page.setDefaultTimeout(10_000);
|
||||
page.setDefaultTimeout(controlUiE2eWaitTimeoutMs);
|
||||
return { context, page, rawVideoDir };
|
||||
} catch (error) {
|
||||
await page?.close().catch(() => {});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Page } from "playwright";
|
||||
import { controlUiE2eWaitTimeoutMs } from "./control-ui-e2e.ts";
|
||||
|
||||
/** A sent connect request is not the delivered Gateway handshake. */
|
||||
export async function waitForControlUiGatewayReady(page: Page): Promise<void> {
|
||||
@@ -23,11 +24,11 @@ export async function waitForControlUiGatewayReconnecting(page: Page): Promise<v
|
||||
return app?.runtime?.context?.gateway?.snapshot?.phase === "reconnecting";
|
||||
},
|
||||
undefined,
|
||||
{ timeout: 10_000 },
|
||||
{ timeout: controlUiE2eWaitTimeoutMs },
|
||||
),
|
||||
page
|
||||
.locator(".sidebar-identity-card__status", { hasText: "Reconnecting…" })
|
||||
.waitFor({ state: "visible", timeout: 10_000 }),
|
||||
.waitFor({ state: "visible", timeout: controlUiE2eWaitTimeoutMs }),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,12 @@ type ControlUiRouteTarget = {
|
||||
// wait browser-local, but allow enough time for the router to finish committing.
|
||||
const CONTROL_UI_ROUTE_TIMEOUT_MS = 60_000;
|
||||
|
||||
// Loaded CI runners regularly stall real Chromium renders past 10s; the larger
|
||||
// CI budget trades failure latency, not coverage (mirrors the ui-e2e vitest
|
||||
// config's expect.poll budget). Local runs keep the snappy 10s deadline.
|
||||
export const controlUiE2eWaitTimeoutMs =
|
||||
process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true" ? 30_000 : 10_000;
|
||||
|
||||
/**
|
||||
* Wait for the browser router to commit a route, not merely update the URL.
|
||||
* Browser-local polling keeps readiness independent of host-side CDP scheduling.
|
||||
@@ -2268,7 +2274,7 @@ function createMockGatewayControls(page: Page, defaultSessionKey: string): MockG
|
||||
return Boolean(gateway?.requests.some((request) => request.method === targetMethod));
|
||||
},
|
||||
method,
|
||||
{ timeout: 10_000 },
|
||||
{ timeout: controlUiE2eWaitTimeoutMs },
|
||||
);
|
||||
const requests = await getRequests(method);
|
||||
const request = requests.at(-1);
|
||||
|
||||
Reference in New Issue
Block a user