Repository navigation
fix: take a mobile full page screenshot again when it still shows the frame from before the scroll - #1346
fix: take a mobile full page screenshot again when it still shows the frame from before the scroll#1346plum117 wants to merge 2 commits into
Conversation
… frame from before the scroll On a busy device (a new emulator or simulator, a CI runner) the native screenshot after a scroll could still show the frame from before the scroll, also after `fullPageScrollTimeout`: the full page image then had a part two times and missed a part. When the page scrolled but its part of the new screenshot has the same pixels as in the previous screenshot, the screenshot is taken again after a wait (at least 500 ms), up to 3 times, then a warning. An area in one color (a blank part of the page) is not checked: a new screenshot of it can not give another image. For iOS and Android with native web screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: d739a97 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
… screenshots for a whole page - The check for a stale frame keeps the decoded previous screenshot, so each screenshot is decoded once (before: twice). - At most 3 new screenshots for a part of the page and 5 for the whole page, with one warning: a fixed overlay that fills the screen looks the same after each scroll, and cost up to 3 new screenshots for each part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| const x = Math.floor(area.imageXPosition) | ||
| const y = Math.floor(area.imageYPosition) | ||
| const width = Math.floor(area.imageWidth) | ||
| const height = Math.floor(area.imageHeight) | ||
|
|
||
| return !isUniformArea(image, x, y, width, height) | ||
| && hasSameArea(decodeUpright(previousScreenshot, isLandscape), image, x, y, width, height) |
There was a problem hiding this comment.
Rounding disables screenshot retries
isSameFrameArea compares the requested crop without the bounds limits used to build the full-page image. If an Android device has a 1080-pixel viewport and devicePixelRatio of 2.75, the width rounds to 393 CSS pixels and then back to 1081 image pixels. hasSameArea rejects that crop even when both screenshots are identical. No retry or warning happens, so a stale screenshot still repeats part of the page.
Limit the compared crop to the same available pixels used by makeFullPageBase64Image.
Knowledge Base Used:
Why
On a busy device (a new emulator or simulator, a CI runner), the native screenshot after a scroll can still show the frame from before the scroll, also after
fullPageScrollTimeout. The full page image then has a part of the page two times, and a part is missing. This is the common cause of the mobile e2e flakes in CI: the Android emulator job (for example run 38074791965: the baseline repeated a tile, 0.158 %) and the iOS simulator job (first viewport again, or an older tile again).What
getMobileFullPageNativeWebScreenshotsData(iOS, and Android with native web screenshots):fullPageScrollTimeout, at least 500 ms) and takes it again, up to 3 times.fullPageScrollTimeout. A whole page takes at most 5 new screenshots, with one warning, so a page that looks the same after each scroll (a fixed overlay that fills the screen) costs at most about 2.5 s.hasSameAreaandisUniformAreainutils/imageUtils.ts. A changeset (patch).Android with ChromeDriver screenshots and desktop are not changed: there the browser gives the screenshot from its own compositor.
Test
hasSameAreaandisUniformArea.pnpm test(lint, types, unit tests) passes.CI job times
main(median of 22–24 runs)* The warm-up hit the known viewport flake and a 5-minute request timeout before any screenshot. The gain of this PR is right images on a busy device, not time.
Battle test:
mainagainst this PR on real devicesThe same script against both builds (
saveFullPageScreenof a page of 20 stripes of 303 px; the image is right when every stripe is there once, at a fixed step), on an Android 16 emulator (native web screenshots, DPR 3) and an iOS 26.3 simulator (iPhone 16 Pro, DPR 3).Performance (default
fullPageScrollTimeout, 2 alternating rounds of 5 runs per build in the same device session, so the order does not change the result):main(median)All 40 runs gave a right image, without a new screenshot or a warning: on a device that is not busy, the cost is only the decode and the comparison.
Other scenarios:
mainfullPageScrollTimeout: 100(5 runs per device)fullPageScrollTimeout: 0, Android (5 runs)fullPageScrollTimeout: 0, iOS (5 runs)Known limit, not changed here: with
fullPageScrollTimeout: 0on iOS, about 96 CSS px of the page are missing at one place, onmainand with this PR (not a repeated part, so not an old frame). Safari changes the size of its toolbar during the scroll, and the screenshot is taken during that change. It does not occur with 100 ms.🤖 Generated with Claude Code