Skip to content

fix(expect): honor timeout when page event loop is blocked - #42948

Closed
Alok Pandey (alok-108) wants to merge 1 commit into
microsoft:mainfrom
alok-108:fix-expect-frozen-page-timeout
Closed

Alok Pandey (alok-108) wants to merge 1 commit into
microsoft:mainfrom
alok-108:fix-expect-frozen-page-timeout

Conversation

@alok-108

Copy link
Copy Markdown
Contributor

Description

Fixes #42880

In Frame.expect(), Step 2 performs a one-shot expect check prior to entering the auto-retry backoff loop. Previously, _expectInternal() was always invoked with noAbort: true, replacing progress with nullProgress unconditionally.

Because nullProgress.race() does not race against the progress controller's abort promise or deadline timer, if the page's event loop was blocked (e.g. an infinite JS loop, renderer freeze, or deadlocked page), the one-shot evaluation in selectors.callOnSelector() would never complete or abort. Even if the caller passed { timeout: 5000 } or { timeout: 500 }, the assertion hung indefinitely until the outer test runner timeout killed the test.

This change restricts noAbort to impossible timeouts (!progress.timeout || progress.timeout <= 100, such as { timeout: 1 }), which were the original motivation for allowing an immediate one-shot check without an instant abort when the element is already present. For all regular timeouts, progress is preserved so that when the configured timeout deadline is reached, progress.race() properly aborts and reports Timeout <duration>ms exceeded.

Testing

  • Added regression test should not hang when event loop is blocked in tests/page/expect-timeout.spec.ts.
  • Verified all 86 boolean assertions in tests/page/expect-boolean.spec.ts pass, including all with impossible timeout test cases.
  • Verified all tests in tests/page/expect-timeout.spec.ts, tests/page/expect-to-have-text.spec.ts, and tests/page/expect-matcher-result.spec.ts pass.
  • Verified npm run eslint, npm run tsc, and npm run build pass with 0 errors.

@alok-108

Copy link
Copy Markdown
Contributor Author

Dmitry Gozman (@dgozman) the issue has P3-collecting-feedback on it and the earlier fix got declined as not-so-bug. So I'm not sure if you actually want this fixed. Don't want to keep pushing a PR that's out of scope.

Should I leave it open, turn it into a draft, or close it?

If you do want it fixed, the approach I took bounds the initial one-shot probe for real timeouts (timeout > 100). That way the expect timeout actually gets honored instead of falling through to the test timeout. The regression test blocks the page event loop and checks that toBeVisible({ timeout: 5000 }) fails around 5s.

If you'd rather go a different route, like racing the one-shot probe against the progress abort promise while suppressing logs (same as #40901), I can rework the PR. Let me know what you want me to do.

@dgozman

Copy link
Copy Markdown
Collaborator

Thank you for the PR. We are not sure about fixing the issue this way. I've marked #42880 and "collecting feedback" so that we can measure how often this issue happens in the wild, and what it would take to fix it. We are not accepting PRs for it just yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: expect(locator).toBeVisible() ignores its timeout when the page is unresponsive; hangs until test timeout

2 participants