feat: support element screenshots of elements in a frame in WebDriver BiDi sessions (v9 `switchFrame()`, v10 `context.frame()`)
メンテナーはふだん 1 日以内に返信
@plum117 がすでに取り組んでいます。
2026年10月9日 から。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 50/100
- issue の種類
- 機能追加
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- testing-qa
調査の方向性
Start with packages/image-comparison-core/src/methods/takeElementScreenshots.ts and screenshots.ts, then inspect images.ts for the ignore-region path. Add unit coverage for nested frames, borders, padding, and scroll, and remove the skip from tests/specs/v10.browsingContexts.spec.ts. Done means the v9 and v10 frame cases produce the same screenshot with 0% mismatch.
索引モデルが issue の本文から書いたものです。
説明
Is your feature request related to a problem? Please describe.
In a WebDriver BiDi session (the default for Chrome, Edge and Firefox since WebdriverIO v9), checkElement() / toMatchElementSnapshot() of an element inside an iframe does not work:
- WebdriverIO v9, frame reached with
browser.switchFrame(): the image is wrong. It is moved by the position of the iframe in the page. A baseline made in the same way is also wrong, so the test can pass with a wrong image. - WebdriverIO v10:
switchFrame()is removed for BiDi sessions, and its replacementcontext.frame()fails:WebDriver Bidi command "browsingContext.captureScreenshot" failed with error: invalid argument - Invalid input in "clip".
With WebDriver Classic ('wdio:enforceWebDriverClassic': true, Appium, Safari), it works in v9 and v10.
Test: the same box outside a frame (baseline) and inside an iframe at margin: 60px 0 0 30px. Expected: 0% mismatch. Local headless Chrome 154, @wdio/visual-service 10.1.0 (with the WebdriverIO v10 changes of #1227).
| How the frame is reached | v9.32.0 BiDi | v10.0.0-alpha.163 BiDi | v9 Classic | v10 Classic |
|---|---|---|---|---|
browser.switchFrame($('iframe')) |
69.587% (image moved by 30/60 px) | error: switchFrame removed for BiDi |
0% | 0% |
(await browser.url(url)).frame('iframe') |
not in v9 | error: Invalid input in "clip" |
not in v9 | error: needs BiDi |
Reproduction (fixtures tests/fixtures/v10/frame.html and box.html from #1222, on the wdio0-v10-compliance branch):
it('compares the same box outside and inside a frame', async () => {
await browser.url(boxPage)
await browser.checkElement(await $('#target'), 'frame-box') // baseline
// v9
await browser.url(framePage)
await browser.switchFrame($('iframe'))
console.log(await browser.checkElement(await $('#target'), 'frame-box')) // 69.587, expected 0
await browser.switchFrame(null)
// v10
const frame = await (await browser.url(framePage)).frame('iframe')
console.log(await browser.checkElement(await frame.$('#target'), 'frame-box')) // throws "Invalid input in clip"
})
tests/specs/v10.browsingContexts.spec.ts (#1222) has the v10 case as it.skip.
Root cause
In the BiDi element screenshot (takeElementScreenshots.ts#L46 and #L77):
getElementRect()gives the position of the element in the frame document (x 40, y 40 in the test).takeBase64BiDiScreenshot()captures the top-level context (screenshots.ts#L546), with that position as theclip.
The clip misses the element by the position of the iframe (30/60 px).
Describe the solution you'd like
Support element screenshots of elements in frames in BiDi sessions, for v9 switchFrame() and v10 context.frame().
Proposed method (tested outside the service): compute the element rect in the top-level document with a client-side script that runs in the element's own document and adds the content-box position of each parent iframe:
function getElementRectInTopDocument (el, origin) {
const r = el.getBoundingClientRect()
let x = r.left, y = r.top, win = el.ownerDocument.defaultView
while (win !== win.top) {
const frameEl = win.frameElement // null for a cross-origin frame
if (!frameEl) return null
const fr = frameEl.getBoundingClientRect()
const style = win.parent.getComputedStyle(frameEl)
x += fr.left + frameEl.clientLeft + parseFloat(style.paddingLeft)
y += fr.top + frameEl.clientTop + parseFloat(style.paddingTop)
win = win.parent
}
// 'document' origin: add the scroll of the top-level page. 'viewport' origin: no scroll.
return origin === 'document'
? { x: x + win.scrollX, y: y + win.scrollY, width: r.width, height: r.height }
: { x, y, width: r.width, height: r.height }
}
Run it with element.execute(getElementRectInTopDocument, origin). In v9 (after switchFrame()) and in v10 (context.frame()), element.execute() runs in the frame document (browser.execute() runs in the top-level page in v10).
Result with the clip from this script:
| Rect | Mismatch | |
|---|---|---|
v9 switchFrame() |
x 70, y 100 (was 40, 40) | 0.000% (was 69.587%) |
v10 context.frame() |
x 70, y 100 | 0.000% (was an error) |
Service changes:
- Add the client-side script.
- In both BiDi element functions, use it in place of
getElementRect(). KeepgetElementRect()as the fallback when the script returnsnull. autoElementScroll:scrollElementIntoViewonly scrolls inside the frame. With the'viewport'origin, the top-level page must also show the iframe.- Ignore regions:
images.ts#L621also usesgetElementRect(), so elements in a frame used inignoreprobably have the same offset (not tested). - Tests: unit tests for the script (nested frames, iframe border and padding, scroll), and remove
.skipfromtests/specs/v10.browsingContexts.spec.ts.
Describe alternatives you've considered
- Use WebDriver Classic for these tests (
'wdio:enforceWebDriverClassic': true). This works now, but it disables BiDi for the whole session. - Capture the frame context directly: not possible,
browsingContext.captureScreenshotonly accepts a top-level context. - Cross-origin frames:
frameElementisnull, so the script cannot read the iframe position. Possible solution (not tested): BiDibrowsingContext.locateNodeswith thecontextlocator in the parent context gives the iframe element, andscript.callFunctionin the parent gives its position. Else keep the current behavior and log a warning.
Additional context
- Related, closed: #1156 / #1155 (wrong emulation detection inside a frame, which caused blank images with the fallback path on Firefox). From the analysis in #1156, the fallback path (
takeScreenshot+ crop) has the same frame offset when it is used for other reasons, for exampleresizeDimensions(not tested). - Limit of the method: a part of the element that the iframe does not show (iframe too small or scrolled) is not in the image, because the capture is of the top-level page.
- 主要言語
- TypeScript
- スター
- 156
- フォーク
- 62
- 平均マージ
- 2時間 2分
- マージ済み PR(30日)
- 111
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
webdriverio/visual-testing のほかの issue
-
Proposal: a noise-tolerant compare mode with pixelmatch 8's windowSize対応中かも @plum117 が 5 日前に担当しました。 オープンenhancement
webdriverio/visual-testing#1311 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
bug: the visual service fails on Android Chrome through Appium 3 in the default WebDriver BiDi session (workaround: `wdio:enforceWebDriverClassic`)対応中かも @plum117 が 5 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
webdriverio/visual-testing#1232 · コメント 2 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
Wait for Screenshot to Match対応中かも @plum117 が 4 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
webdriverio/visual-testing#690 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
Using checkFullPageScreen method, capturing images with duplicate viewport and is not scrolling to the bottom of the page対応中かも @plum117 が 4 日前に担当しました。 オープンhelp wanted
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
webdriverio/visual-testing#125 · コメント 2 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
webdriverio/visual-testing の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
stellar/stellar-dev-skill#151 ·
メンテナーはふだん 1 日以内に返信
-
area:arcade game ready-for-agent
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
fderuiter/deruiter.dev#2281 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
scope: data grid type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 2 日以内に返信
-
fix(frontend): correct VITE_IS_DEVELPOMENT typo in shared/app.ts and align dev environment flagsオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
vicharanashala/ajrasakha#1439 ·
メンテナーはふだん 1 日以内に返信
-
Add: TV5Monde Asieオープンapproved check:passed streams:add
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信