Use case
"Is this element actually visible in the viewport right now?" is a common check for lazy-loading images, sticky headers, infinite scrolling, cookie banners and scroll-into-view behavior. The library's element state keywords answer attached/visible in the CSS sense, but not whether the element is inside the current viewport, and certainly not how much of it is.
Playwright covers this with toBeInViewport({ ratio }), backed by IntersectionObserver. Browser library has no equivalent: users today must hand-roll an Evaluate JavaScript snippet with an IntersectionObserver, a Promise and manual polling — boilerplate that is easy to get wrong and gets copy-pasted between suites.
A float getter fits the assertion-engine model perfectly and is strictly more expressive than a boolean keyword: > 0 reproduces toBeInViewport, == 0 reproduces not.toBeInViewport, and >= 0.5 covers the ratio option that a boolean never could.
Proposed keyword / arguments
Get Viewport Intersection Ratio selector assertion_operator=None assertion_expected=None message=None
| Argument |
Description |
selector |
Element selector, strict mode applies. |
assertion_operator / assertion_expected / message |
Standard assertion-engine arguments with auto-retry; numeric operators (==, >, >=, <, <=) apply. |
Returns a float between 0.0 (fully outside the viewport) and 1.0 (fully inside), the IntersectionObserver intersection ratio of the element versus the viewport.
*** Test Cases ***
Hero Is Visible After Load
New Page ${URL}
Get Viewport Intersection Ratio id=hero > 0
Call To Action Is At Least Half Visible
Scroll To Element id=cta
Get Viewport Intersection Ratio id=cta >= 0.5
Footer Is Not In Viewport Initially
Get Viewport Intersection Ratio css=footer == 0
${ratio} = Get Viewport Intersection Ratio id=banner
With Set Retry Assertions For, the assertion auto-retries — e.g. waiting until a lazily loaded element scrolls into view.
Playwright API
The wrapper computes the same IntersectionObserver-based ratio Playwright's assertion uses.
Implementation notes
protobuf/playwright.proto: new selector-in / float-out RPC (or reuse an existing generic element-request shape).
node/playwright-wrapper: resolve the locator and evaluate the intersection ratio via Playwright's injected utilities (same mechanism as toBeInViewport).
Browser/keywords/getters.py: new keyword with @with_assertion_polling and float_str_verify_assertion-style numeric assertion, tags Getter, Assertion, PageContent.
- Docs +
inv build stub regen, atest with a long scrollable page (element out of view, partially in view, fully in view).
Backwards compatibility
Purely additive: a new keyword, no changes to any existing keyword.
Use case
"Is this element actually visible in the viewport right now?" is a common check for lazy-loading images, sticky headers, infinite scrolling, cookie banners and scroll-into-view behavior. The library's element state keywords answer attached/visible in the CSS sense, but not whether the element is inside the current viewport, and certainly not how much of it is.
Playwright covers this with
toBeInViewport({ ratio }), backed byIntersectionObserver. Browser library has no equivalent: users today must hand-roll anEvaluate JavaScriptsnippet with anIntersectionObserver, a Promise and manual polling — boilerplate that is easy to get wrong and gets copy-pasted between suites.A float getter fits the assertion-engine model perfectly and is strictly more expressive than a boolean keyword:
> 0reproducestoBeInViewport,== 0reproducesnot.toBeInViewport, and>= 0.5covers the ratio option that a boolean never could.Proposed keyword / arguments
selectorassertion_operator/assertion_expected/message==,>,>=,<,<=) apply.Returns a float between
0.0(fully outside the viewport) and1.0(fully inside), theIntersectionObserverintersection ratio of the element versus the viewport.With
Set Retry Assertions For, the assertion auto-retries — e.g. waiting until a lazily loaded element scrolls into view.Playwright API
ratiooption)The wrapper computes the same
IntersectionObserver-based ratio Playwright's assertion uses.Implementation notes
protobuf/playwright.proto: new selector-in / float-out RPC (or reuse an existing generic element-request shape).node/playwright-wrapper: resolve the locator and evaluate the intersection ratio via Playwright's injected utilities (same mechanism astoBeInViewport).Browser/keywords/getters.py: new keyword with@with_assertion_pollingandfloat_str_verify_assertion-style numeric assertion, tagsGetter, Assertion, PageContent.inv buildstub regen, atest with a long scrollable page (element out of view, partially in view, fully in view).Backwards compatibility
Purely additive: a new keyword, no changes to any existing keyword.