From d99bb685dd5673293f38c2b17552d0a798490abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E8=89=AF?= <1204183885@qq.com> Date: Wed, 4 Nov 2026 16:43:03 +0800 Subject: [PATCH] test(web-shell): wait for the restored card before clicking continue (#16286) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nightly `web-shell Browser Regression` dies in the generated-UI retention case at `expect.poll(() => text).toBeDefined()`: the click on `#continue-analysis` produces no prompt request, so the capture route never fires (run 41771749222, job 126382801964). The same case passes on a dev machine — 6/6 runs here — so this is a host-timing shape, not a product defect. Wait for the card's continue control to be enabled, give dispatch a CI-sized budget, and fail with the card and status state when nothing is dispatched. The next nightly then names the cause instead of `undefined`. --- .../client/e2e/generated-ui.retention.spec.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/web-shell/client/e2e/generated-ui.retention.spec.ts b/packages/web-shell/client/e2e/generated-ui.retention.spec.ts index 899a262e058..a926324f1e2 100644 --- a/packages/web-shell/client/e2e/generated-ui.retention.spec.ts +++ b/packages/web-shell/client/e2e/generated-ui.retention.spec.ts @@ -499,10 +499,32 @@ async function reviewSnapshot(page: Page, app: FrameLocator) { text = body.prompt[0].text; await route.fulfill({ status: 409, json: { error: 'captured by test' } }); }; + // A restored card finishes its first paint asynchronously, and a click that + // lands before the host accepts continuations is swallowed with no request + // and no error: the nightly run failed on the missing dispatch, not on the + // copy below. Wait for the button the app gates continuations on, then give + // dispatch a CI-sized budget so a loaded host is not read as a broken card. + await expect(app.locator('#continue-analysis')).toBeEnabled(); await page.route('**/session/*/prompt', capture); try { await app.locator('#continue-analysis').click(); - await expect.poll(() => text).toBeDefined(); + const deadline = Date.now() + (process.env['CI'] ? 20_000 : 5_000); + while (!text && Date.now() < deadline) { + await page.waitForTimeout(100); + } + if (!text) { + const cardState = await app + .locator('#status') + .getAttribute('data-state') + .catch(() => null); + const status = await app + .locator('#continuation-status') + .textContent() + .catch(() => null); + throw new Error( + `continue never dispatched a prompt request (card=${cardState}, status=${status})`, + ); + } await expect(app.locator('#continuation-status')).toContainText( 'Not sent.', );