fix(mobile): bound reads by operation budget with last-read grace (#1099)
Closed
TO
19h ago+620+620+012345678901234567890123456789-187-187-012345678901234567890123456789
What and why
- On
@e2e-dev/mobilea snapshot or screenshot that hung held the step until the test timeout (#1099). Every device read now runs under the operation's budget (InputBudget.read,packages/mobile/src/support.ts), so a hung read fails the step asOPERATION_TIMEOUT(orACTION_MAY_HAVE_COMMITTEDonce an input of that operation went out). - Bounding reads alone broke slow polls: on iOS a snapshot takes 1-2 s, so the last read of
waitFor/expect/toHaveScreenshotgot cut at the deadline and failed as a hang instead ofLOCATOR_NOT_FOUND. - Core fix:
ReadWindow(packages/e2e/src/internal/time.ts). Each read of one wait gets the time left plus the slowest read that wait already finished, capped by the running phase's deadline. A read cut off within that tail ends the wait as a normal timeout; a read that hung with more time left is still the failure. @e2e-dev/mobilenow needse2e >=0.21.4(this PR's e2e patch changeset ships it): on 0.21.3 core, mobile reads would end at the deadline with no last-read grace.- No public type change:
ReadWindowis internal;OperationContext.timeoutMsdocs note the last read can get more than the deadline leaves.
Issue
Fixes #1099
Verified
Ran it locally: no device run. Unit evidence on the head merged with main (f4e8c8e1a + nit 7f1d05ed8):
- Reverting the read bound (
readWithin-> direct call) fails 6 mobile tests, e.g. "bounds a snapshot by the operation budget" and "takes no second snapshot for a capture the budget abandoned". - Reverting the slowest-read grace in
ReadWindow.timeoutMs()fails 5 core tests (time, locator-engine, locator-wait-for), e.g. "lets a slow last resolve finish past the deadline: a late match resolves". - Reverting the slowest-read term in
ReadWindow.cutOff()fails "ends on a read cut off within the longest read time of the deadline, and fails on one that hung with more left". pnpm checkpasses; e2e (3171), mobile (420), web (290) unit suites pass.
| main | this branch |
|---|---|
| A hung snapshot holds the step until the test timeout | The step fails at its own timeout |
(with bounded reads only) a slow last iOS read in expect fails as a hang | The last read finishes; a missing node is LOCATOR_NOT_FOUND / ASSERTION_FAILED |
Checklist
- Changeset added (
pnpm changeset) for any change to a published package, or the change is testbed, docs, or CI only. - Breaking change: title carries
!, the changeset body names what breaks and what replaces it, and the deprecation warning landed a window earlier (stability policy in CONTRIBUTING.md). - Docs updated in the same PR: the
docs/**/*.mdxpage for the behavior, andskills/e2e/if the skill describes it. - Contract change: emitted
.d.tsreviewed,tests/types/sdk-types.tsupdated; wire change edits the schema and both fixtures. - Engine contract change (
e2e/engine): changesets fore2e,@e2e-dev/web, and@e2e-dev/mobile.