[Feature]: Extend isVisible/toBeVisible API to include overlap detection
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
- #43861 của @microsoft-playwright-automation — đã đóng, không merge
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 15/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- testing-qa, typescript
Hướng nghiên cứu
This is an API design question, so start by deciding whether the flag goes on isVisible/toBeVisible or a new isNotOverlapped/toBeNotOverlapped method, and get maintainer agreement first. The issue's snippet uses document.elementFromPoint on sample points inside the element, with pointer-events temporarily set to all, and the example expects toBeVisible({checkOverlaps: true}) to fail when #big-box covers #small-box. Done means a settled API plus a test covering that case and the default behaviour staying unchanged.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
🚀 Feature Request
Extend the isVisible and toBeVisible calls to have an optional flag checkOverlaps (or enforceNotOverlapped if we want to be more precise), which would check if the element is overlapped by another one and thus not visible. For backward-compatibility, the flag would have a default value of false, in which case isVisible/toBeVisible would work exactly the same way as it does now.
If there is a strong argument for keeping these existing APIs unchanged, a new method could also be introduced (e.g. isNotOverlapped/toBeNotOverlapped).
Here's a possible implementation (does not consider transformations yet) that we use in our codebase to check overlaps.
function isElementNotOverlapped (element: Locator): Promise<boolean> {
return element.evaluate((el) => {
// pointer-events: none interferes with elementFromPoint so we temporarily set the property to all
const originalPointerEvents = el.style.pointerEvents
el.style.pointerEvents = 'all'
const rect = el.getBoundingClientRect()
const getStyleValueAsNumber = (styleProperty: string) => {
return Number(window.getComputedStyle(el, null).getPropertyValue(styleProperty)
.replace('px', ''))
}
const paddingLeft = getStyleValueAsNumber('padding-left')
const paddingRight = getStyleValueAsNumber('padding-right')
const paddingTop = getStyleValueAsNumber('padding-top')
const paddingBottom = getStyleValueAsNumber('padding-bottom')
const borderRadiusTopLeft = getStyleValueAsNumber('border-top-left-radius')
const borderRadiusTopRight = getStyleValueAsNumber('border-top-right-radius')
const borderRadiusBottomLeft = getStyleValueAsNumber('border-bottom-left-radius')
const borderRadiusBottomRight = getStyleValueAsNumber('border-bottom-right-radius')
const isPointVisible = (x: number, y: number) => {
const elementAtPoint = document.elementFromPoint(x, y)
return el.contains(elementAtPoint) || elementAtPoint === el
}
const pointsToCheckOffset = 2
const leftEdgeToCheck = rect.left + paddingLeft + pointsToCheckOffset
const topEdgeToCheck = rect.top + paddingTop + pointsToCheckOffset
const rightEdgeToCheck = rect.right - paddingRight - pointsToCheckOffset
const bottomEdgeToCheck = rect.bottom - paddingBottom - pointsToCheckOffset
const pointsToCheck = [
// top-left corner
{x: leftEdgeToCheck + (borderRadiusTopLeft / 3), y: topEdgeToCheck + (borderRadiusTopLeft / 3)},
// top-right corner
{x: rightEdgeToCheck - (borderRadiusTopRight / 3), y: topEdgeToCheck + (borderRadiusTopRight / 3)},
// bottom-left corner
{x: leftEdgeToCheck + (borderRadiusBottomLeft / 3), y: bottomEdgeToCheck - (borderRadiusBottomLeft / 3)},
// bottom-right corner
{x: rightEdgeToCheck - (borderRadiusBottomRight / 3), y: bottomEdgeToCheck - (borderRadiusBottomRight / 3)},
// center
{x: rect.left + (rect.width / 2), y: rect.top + (rect.height / 2)}
]
const result = pointsToCheck.every((point) => isPointVisible(point.x, point.y))
el.style.pointerEvents = originalPointerEvents
return result
})
Example
await page.goto('data:text/html,<html><body style="margin: 0;">' +
'<div id="small-box" style="background-color: green; height: 50px; width: 50px; position: fixed; top: 80px">' +
'</div><div id="big-box" style="background-color: brown; height: 100px; width: 100px; position: fixed;">' +
'</div></html>')
const smallBox = page.locator('#small-box')
// Passes
await expect(smallBox).toBeVisible()
// Passes
await expect(smallBox).toBeInViewport()
// Does not pass, since overlapped by `#big-box`.
await expect(smallBox).toBeVisible({checkOverlaps: true})
Motivation
As described in this previous issue (as well as this one), isVisible currently does not consider overlaps at all, so if an element is fully behind another one, isVisible may still return true for it. It would be useful to be able to test that an element is actually visible on the screen, since some visual bugs can offer due to overlapping elements and these are currently hard to write tests for using Playwright. Modern web apps often feature a lot of popups, modals etc. that may overlap other content on the screen.
Previously tracked in https://github.com/microsoft/playwright/issues/34778.
- Ngôn ngữ chính
- TypeScript
- Star
- 99.1k
- Fork
- 6.8k
- Merge trung bình
- 17 giờ 6 phút
- Pull request đã merge (30 ngày)
- 306
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/playwright
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 76/100
microsoft/playwright#43987 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
microsoft/playwright#43986 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: Embedded number/range inputs contribute their `value` attribute, not their current value, to accessible namesCó thể đã có người làm @lazerg đã nhận 1 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 35/100
microsoft/playwright#43984 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 64/100
microsoft/playwright#43983 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
microsoft/playwright#43981 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của microsoft/playwright
Issue tương tự
-
status: needs triage
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 68/100
mastra-ai/mastra#29706 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
lingdojo/kana-dojo#33802 · 1 bình luận · 5 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
cloudflare/workerd#8290 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area: build-and-ci possible-duplicate S3: minor
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
manaflow-ai/cmux#38889 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
ValentinH/react-easy-crop#670 ·