Repository navigation
Conversation
🦋 Changeset detectedLatest commit: e898382 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 |
plum117
marked this pull request as ready for review
October 10, 2026 14:29
plum117
marked this pull request as draft
October 10, 2026 14:29
Contributor
Author
|
Keeping draft until @wswebcreation approval |
|
plum117
added a commit
to plum117/visual-testing
that referenced
this pull request
Oct 10, 2026
…and keep the rows of the container Greptile review of webdriverio#1322: - the crop of each screenshot uses the scroll position of the container when the screenshot was taken, not the one before the lazy-loading wait. When content that loads above the visible rows moves the position, the container is scrolled again (at most 3 times, then a clear error) - a container that goes above or below the viewport gives a clear error: its first or last rows can not be in a screenshot (before, they were silently missing) - the ignore elements are measured right after each screenshot (with the scrollbar of the container still hidden) and mapped through the crop of each tile, so a sticky element is ignored at each place in the image and the layout is the layout of the screenshot. The mapping after the screenshot (rawExpandedContainerBcr) is removed Matrix (21 pages x Chrome BiDi, Classic, DPR 2, Edge, Firefox): 21/21 each, the ignore regions cover each element and nothing else. Mobile structure check: iOS simulator, Android ChromeDriver and native screenshots OK. New e2e test: a sticky title in the container, ignored, with another color (fails with the old code: 4.032 %). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plum117
force-pushed
the
feat/full-page-scroll-container
branch
from
October 10, 2026 18:11
5f6603e to
33e69af
Compare
…Container) In many apps the page itself does not scroll, a container does (for example a `main` element under a fixed header). A full page screenshot was then only the viewport (BiDi), or the top of the page again and again (scroll and stitch, webdriverio#125). New method option `scrollContainer` for `checkFullPageScreen()`, `saveFullPageScreen()` and `toMatchFullPageSnapshot()`. The image is the viewport with that container expanded: the rows above the container, its full content, then the rows below it. Columns next to the container (a sidebar) are only in the image for the first viewport. - New stitching `getScrollContainerFullPageScreenshotsData`: the first tile has all columns, the next tiles only the container columns (new `canvasXPosition` of a tile), the last screenshot gives the rows below. Always stitched, also in a BiDi session (a document screenshot does not show the content of a container). The container scrollbar is hidden with `hideScrollBars`, and the container is scrolled back in `finally`. - Ignore regions are mapped to that image (the scroll position of the container for its content, the hidden content for elements below it). - Mobile web: the viewport comes from the device rectangles (native screenshots), or is not higher than `innerHeight` (Android ChromeDriver screenshots can be higher). The service does not add its shadow padding to the body, which would cut the end of the container. - The tabbable commands do not support it and ignore it with a warning. Checked against the same page with the container expanded by CSS: 0% difference in Chrome (BiDi, Classic, DPR 2), Edge and Firefox; Safari, Android (ChromeDriver and native screenshots) and iOS checked by the structure of the image (every stripe once, at a fixed step). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and keep the rows of the container Greptile review of webdriverio#1322: - the crop of each screenshot uses the scroll position of the container when the screenshot was taken, not the one before the lazy-loading wait. When content that loads above the visible rows moves the position, the container is scrolled again (at most 3 times, then a clear error) - a container that goes above or below the viewport gives a clear error: its first or last rows can not be in a screenshot (before, they were silently missing) - the ignore elements are measured right after each screenshot (with the scrollbar of the container still hidden) and mapped through the crop of each tile, so a sticky element is ignored at each place in the image and the layout is the layout of the screenshot. The mapping after the screenshot (rawExpandedContainerBcr) is removed Matrix (21 pages x Chrome BiDi, Classic, DPR 2, Edge, Firefox): 21/21 each, the ignore regions cover each element and nothing else. Mobile structure check: iOS simulator, Android ChromeDriver and native screenshots OK. New e2e test: a sticky title in the container, ignored, with another color (fails with the old code: 4.032 %). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on, and start again when content above changes - A container that starts at a fractional row (for example under a header of 60.5 px) always failed: the browser keeps the scroll position in device pixels, so the container did not stop at the fractional position of the next screenshot, and this was taken as a change of the position. The scroll target is now a device pixel, the position after the wait is compared with the position that the browser reports right after the scroll (a difference of up to 1 px is rounding), and the tiles are made from rounded edges, so they touch without a gap. - A container with `scroll-snap-type: mandatory` always failed for the same reason: scroll snap is now turned off (inline `!important`) while the screenshots are taken, and put back after the scroll back. - When content loads above the visible rows during the screenshots (the browser keeps the visible rows in place), the earlier screenshots are out of date: the screenshots now start again from the top (at most 3 times), so the image has no repeated rows. Content that loads at the end after the container stopped there does not start again. - The feature is in 11.1.0, not in 11.0.0: the section in the v11 migration guide is removed, the changeset has the details. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At DPR 1.5 and 2.625 some tiles were 1 or 2 device rows off (0.1 to 0.3 % of the image): - Chrome reports the scroll position as a 32-bit float (596.6666870117188 for 895 device pixels), so the crop row and the canvas row were rounded in different directions. A canvas row and the screenshot row of the same content differ by the scroll position in device pixels (the top of the container cancels out), so the crop row now comes from the canvas row minus the rounded scroll position. - `clientTop` and `clientHeight` are rounded to whole pixels, but at DPR 2.625 Chrome draws a 6px border as 5.714px, so each tile also took 1 or 2 rows of the border. The content box now comes from the bounding box and the computed border widths, without a scrollbar that takes space. The matrix gives 0 % in Chrome (DPR 1, 1.5, 2), Edge and Firefox (DPR 1, 2) for all 12 pages, and at most 0.07 % (text) at DPR 2.625. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plum117
marked this pull request as ready for review
October 11, 2026 01:15
plum117
force-pushed
the
feat/full-page-scroll-container
branch
from
October 11, 2026 01:16
33e69af to
dd6b23c
Compare
…re its layout before the scroll back - An ignored element in the container was measured with its whole box, also the part that the container hides, so the region could cover pixels outside the container (for example a sidebar). The box is now clipped to each ancestor that clips its overflow (not for a fixed element). - The container was scrolled back while its scrollbar was still hidden. A scrollbar that takes space changes the layout, so near the end the container stopped at another position (4537 instead of 4699 px with a 300 px scrollbar). The scrollbar now comes back first, then the scroll back with scroll snap still off, then scroll snap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntaining block chain An absolute element escapes the static ancestors below its positioned ancestor, and a fixed element escapes all ancestors below one with a transform (or a filter, contain, ...). The clip of the ignore region now follows that chain, so a visible absolute child of a static `overflow: hidden` wrapper keeps its whole region. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…containing block for ignore regions A wrapper with `translate`, `rotate`, `scale`, `backdrop-filter`, `container-type`, `content-visibility: auto|hidden` or `will-change` of these is the containing block of its absolute and fixed descendants, so its overflow clips them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plum117
marked this pull request as draft
October 11, 2026 02:07
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #125
Why
In many apps the page itself does not scroll, a container does (for example a
mainelement under a fixed header, withhtml, body { height: 100%; overflow: hidden }). A full page screenshot of such an app was:html/body, which do not move (the screenshots of Using checkFullPageScreen method, capturing images with duplicate viewport and is not scrolling to the bottom of the page #125). A maintainer proposed an option that points to the element that scrolls.What
A new method option
scrollContainerforcheckFullPageScreen(),saveFullPageScreen()andtoMatchFullPageSnapshot():The image is the viewport with that container expanded: the rows above the container (a header), the full content of the container, then the rows below it (a footer). Without the option nothing changes, so no baseline changes.
getScrollContainerFullPageScreenshotsData(methods/screenshots.ts): the first tile has all columns (header and the first part of the container), the next tiles only the columns of the container (new optionalcanvasXPositionof a tile, so a sidebar is not repeated), and the last screenshot gives the rows below the container. Lazy content that makes the container longer is followed. The container scrollbar is hidden withhideScrollBars,hideAfterFirstScrollworks, and the container is scrolled back to its start position infinally.transform,translate,rotate,scale,filter,contain,container-type, ... make a wrapper its containing block), so a hidden part of an element does not ignore pixels outside the container.innerHeight(Android ChromeDriver screenshots are 56 px higher than the viewport). The service does not add its shadow padding to the body in this mode: in an app shell the body has the height of the viewport, so the padding cut the end of the container.tests/specs/v10.browsingContexts.spec.tswith a local app-shell page (it fails onmain: 70.9%), also with scroll snap and a header of 60.5 px (it fails with the first version of this PR); a changeset (minor). The feature ships after 11.0.0, so it is not in the v11 migration guide; the option needs a line in the WebdriverIO docs (method options).Test
Matrix: 12 test pages (header, header + footer, sidebar, a sticky title in the container with
hideAfterFirstScroll,scroll-behavior: smooth, a container with border and padding, a container without overflow, scroll snapy mandatory, a header of 60.5 px, content that loads above the visible rows, content that loads at the end,dir="rtl") × start positions of the container (top, middle, end), a not-awaited$()element, and a visible container scrollbar, with ignore regions in and below the container. The expected image is the same page with the container expanded by CSS, made with the existing full page command:Not counted as failures, checked by hand: with a header of 60.5 px the expected page is 1 to 2 device pixels higher, because it rounds its height up to whole CSS pixels (the common rows are equal); for content that loads above, and for scroll snap on Android, the harness measures the start position before the page moves it (the image is equal). With
hideScrollBars: falseand an overlay scrollbar, the scrollbar is in each screenshot of the container, as the page scrollbar is in a normal full page screenshot.The review rounds of Greptile found 5 more cases, each reproduced in Chrome and fixed with unit tests that fail without the fix: an ignored element that goes out of the container (its region covered a sidebar), the scroll back with a scrollbar of 300 px that takes space (4537 instead of 4699 px), an absolute element positioned by an ancestor above a static
overflow: hiddenwrapper, and wrappers withtranslate(and the other properties that make a containing block).Before this review, a header of 60.5 px and scroll snap always gave an error, content that loaded above gave a repeated band (8.42%), and at DPR 1.5 and 2.625 some tiles were 1 or 2 device rows off (up to 0.28%).
iOS 26.3 simulator (iPhone 16 Pro) on the last commit: 8 pages by the structure of the image, exact height, scroll back, and the ignore region of an element in the container (also across a tile seam). All core and visual-service unit tests, lint and types pass. The local Chrome suites (
test.local.chrome.v10,.jasmine,.emulation,test.local.desktop.multi) pass; the new e2e test with scroll snap and a header of 60.5 px fails with the first version of this PR.🤖 Generated with Claude Code