feat: CORS iframes + closed shadow DOM parity#226
Draft
aryanku-dev wants to merge 4 commits into
Draft
Conversation
…arity Brings the same helper surface used by percy-nightwatch / percy-webdriverio into percy-selenium-python directly: DEFAULT_MAX_FRAME_DEPTH, clamp_frame_depth, normalize_ignore_selectors, is_unsupported_iframe_src, get_origin, resolve_max_frame_depth, resolve_ignore_selectors, and the PercyContextLost exception. No SDK version bump — Python doesn't share a utils package with the JS SDKs, so the helpers ship inline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements feature parity with percy-nightwatch / percy-webdriverio for cross-origin iframe serialization: - Replaces the flat single-level iframe scan with a recursive ``process_frame_tree`` walk bounded by ``DEFAULT_MAX_FRAME_DEPTH`` (5, overridable via ``maxIframeDepth`` option or ``percy.config.snapshot.maxIframeDepth``). - Adds an ancestor-URL cycle guard so frames that link back to a previously-visited URL stop descending instead of recursing forever. - Adds an ``enumerate_iframes_script`` JS helper that runs inside the current frame context and returns metadata for every iframe (src, srcdoc, percyElementId, dataPercyIgnore, matchesIgnoreSelector, index). Nested-frame discovery now uses this script in the child context so nested-frame origin comparisons are against the *immediate* parent origin, not the page origin. - ``data-percy-ignore`` attribute opt-out: any iframe with this attribute is dropped before any switch. - ``ignoreIframeSelectors`` option (and ``ignore_iframe_selectors`` / ``percy.config.snapshot.ignoreIframeSelectors``): selectors are baked into the in-browser enumeration script so matching iframes are dropped before being processed. - Post-switch URL re-check via ``is_unsupported_iframe_src``: after switching into a frame we read ``document.URL`` and bail if the loaded document is about:blank, about:srcdoc, a net-error page, or another unsupported scheme. - ``PercyContextLost`` recovery: if ``switch_to.parent_frame()`` fails at depth > 1 we raise ``PercyContextLost`` carrying the ``partial_capture`` collected so far. The top-level walk merges that partial capture into the final ``corsIframes`` payload before aborting sibling iteration (whose enumeration was performed in a now-lost context). All per-frame serialize calls force ``enableJavaScript=True`` to bypass the standard iframe inlining path inside PercyDOM. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ``expose_closed_shadow_roots`` (mirrored from percy-playwright's ``exposeClosedShadowRoots``) so that PercyDOM.serialize can capture closed-mode shadow DOM that ordinary DOM traversal cannot reach. Flow: 1. ``DOM.enable`` — gates non-Chromium drivers silently (Firefox/WebKit will fail this call and we no-op without touching the page). 2. ``DOM.getDocument`` with ``depth=-1, pierce=True`` — walks the full DOM tree including every shadow root. 3. Recurse the tree, collecting (host, shadowRoot) backend-node pairs for each ``shadowRootType=='closed'`` entry. Subtrees inside an iframe's ``contentDocument`` are skipped — their JS execution contexts can't see the page's WeakMap. 4. Create ``window.__percyClosedShadowRoots`` (same key PercyDOM uses). 5. For each pair, ``DOM.resolveNode`` both ends, then ``Runtime.callFunctionOn`` to stash the shadow root in the WeakMap keyed by its host element. Wired into ``percy_snapshot`` immediately after PercyDOM injection and re-primed after ``driver.refresh()`` inside ``capture_responsive_dom`` (the WeakMap is destroyed on navigation). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Brings percy-selenium-python to parity with the canonical Percy CORS iframe + closed shadow DOM feature set.
Implemented
data-percy-ignoreattribute opt-outignoreIframeSelectorsoptionis_unsupported_iframe_srcPercyContextLostrecovery mergespartial_captureexpose_closed_shadow_roots)Skipped
Reference
Mirrored from percy/percy-nightwatch#869 (PER-7292-add-cors-iframe-support); CDP from percy/percy-playwright#609.
Test plan
🤖 Generated with Claude Code via /percy-sdk-sync