ReviewOS

stacks/very-happy-dom

Locator.boundingBox() is missing, now that the rect resolves through the cascade

#1609
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Problem

typeof page.locator('.card').boundingBox              // 'undefined'
typeof page.locator('.card').scrollIntoViewIfNeeded   // 'undefined'

boundingBox() was not worth adding before #1600, because getBoundingClientRect() read only the inline style and would have reported 0 × 0 for anything sized by a stylesheet. That is no longer true — the rect now resolves through the cascade, so the numbers are there and nothing exposes them at the locator level.

wildloop's specs use boundingBox 9 times and scrollIntoViewIfNeeded 4.

Why it matters

boundingBox() is the honest way to ask a size question, and the workaround —

const box = (await loc.elementHandle()).getBoundingClientRect()

— drops out of the locator API and skips the strict-mode check, so on two matches it silently measures the first.

It also needs to be clear about what it cannot answer. There is no layout pass, so x and y are always 0 (asserted as such in test/box-metrics-cascade.test.ts). A boundingBox() returning { x: 0, y: 0, width: 120, height: 40 } is right about half of that and made-up about the other half, and the half that is made-up is the half people use it for: overlap, ordering, "is this above the fold". That has to be documented at the method, not only in a test.

Proposed scope

  • locator.boundingBox() — resolve strictly, return getBoundingClientRect()'s { x, y, width, height }, and return null for an element that is not rendered, as Playwright does. The doc comment must say x/y are always the origin.
  • locator.scrollIntoViewIfNeeded() — VirtualElement.scrollIntoView (:1959) resets _scrollTop/_scrollLeft to 0 and fires scroll, which is as much as is meaningful without layout. Exposing it as a resolving no-op is better than leaving the method missing, because in Playwright it is a step before an action rather than an assertion, and a missing method throws where a no-op would have let the spec through. Same requirement: say so at the method.

Deliberately out of scope: making x/y real. That needs a layout pass, which is a different project, and guessing coordinates would be worse than reporting the origin.

Acceptance

  • boundingBox() on an element sized by a stylesheet reports that size, and agrees with getComputedStyle.
  • boundingBox() returns null for a display: none element.
  • Two matches throw the strict-mode error rather than measuring the first.
  • x/y are asserted to be 0, so a future change cannot start reporting coordinates without the test noticing.

Found while assessing whether wildloop's Playwright specs could port here.

Sign in to comment on this issue.