Bug 228270 - Elements cloned into an iframe cannot be accessed by webdriver
Summary: Elements cloned into an iframe cannot be accessed by webdriver
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebDriver (show other bugs)
Version: Safari 14
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-07-24 16:50 PDT by MoLow
Modified: 2021-09-20 18:37 PDT (History)
10 users (show)

See Also:


Attachments
Patch (3.17 KB, patch)
2021-07-24 16:52 PDT, MoLow
no flags Details | Formatted Diff | Diff
Patch (3.36 KB, patch)
2021-08-03 02:40 PDT, MoLow
no flags Details | Formatted Diff | Diff
Patch (3.36 KB, patch)
2021-08-03 10:35 PDT, MoLow
no flags Details | Formatted Diff | Diff
Patch (3.39 KB, patch)
2021-08-03 23:30 PDT, MoLow
moshe: review?
ews-feeder: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description MoLow 2021-07-24 16:50:53 PDT
when cloning/creating elements inside an iframe, trying to access the element using Webdriver results in a `cannot serialize cyclic structures` Error.
this is since iframe.contentWindow.Node !== Node and the checkCyclic method fails to determine the cloned element is an element.
a minimal reproduction for creating such an element can be found here http://jsbin.testim.io/duq/3
Comment 1 MoLow 2021-07-24 16:52:51 PDT
Created attachment 434175 [details]
Patch
Comment 3 Sam Sneddon [:gsnedders] 2021-07-27 08:54:01 PDT
Comment on attachment 434175 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=434175&action=review

(Non-reviewer r-)

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:213
> +          (value.nodeType == NodeType.ELEMENT || value.nodeType == NodeType.DOCUMENT || value instanceof ShadowRoot);

The "value instanceof ShadowRoot" check still suffers from the exact same problem as described above.

My suggestion here would be something like:

let constructor = value.constructor;
do {
    if (constructor.name === "Element") return true;
} while(constructor = Object.getPrototypeOf(constructor));
return false;

(With whatever else is needed to make that safe, not thought too much about this! Still need to check that value is a non-null object, at least.)

Also: per spec this is just used by https://w3c.github.io/webdriver/#dfn-internal-json-clone-algorithm, and in that case per spec we simply want to check if its an instanceof Element; so do we even want to allow other Nodes?
Comment 4 James Graham 2021-07-27 09:22:58 PDT
It would be useful to get a web platform test covering this case if there isn't already such a test. I don't know if/how one can write such a test in the WebKit tree, but I can help with submitting a test directly to https://github.com/web-platform-tests/wpt if required.
Comment 5 Radar WebKit Bug Importer 2021-07-31 16:51:16 PDT
<rdar://problem/81371385>
Comment 6 MoLow 2021-08-03 02:40:54 PDT
Created attachment 434821 [details]
Patch
Comment 7 MoLow 2021-08-03 02:41:40 PDT
(In reply to Sam Sneddon [:gsnedders] from comment #3)
> Comment on attachment 434175 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=434175&action=review
> 
> (Non-reviewer r-)
> 
> > Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:213
> > +          (value.nodeType == NodeType.ELEMENT || value.nodeType == NodeType.DOCUMENT || value instanceof ShadowRoot);
> 
> The "value instanceof ShadowRoot" check still suffers from the exact same
> problem as described above.
> 
> My suggestion here would be something like:
> 
> let constructor = value.constructor;
> do {
>     if (constructor.name === "Element") return true;
> } while(constructor = Object.getPrototypeOf(constructor));
> return false;
> 
> (With whatever else is needed to make that safe, not thought too much about
> this! Still need to check that value is a non-null object, at least.)
> 
> Also: per spec this is just used by
> https://w3c.github.io/webdriver/#dfn-internal-json-clone-algorithm, and in
> that case per spec we simply want to check if its an instanceof Element; so
> do we even want to allow other Nodes?

I have added a fix for shadow root - in a somwhat more performant way
Comment 8 MoLow 2021-08-03 02:42:11 PDT
(In reply to James Graham from comment #4)
> It would be useful to get a web platform test covering this case if there
> isn't already such a test. I don't know if/how one can write such a test in
> the WebKit tree, but I can help with submitting a test directly to
> https://github.com/web-platform-tests/wpt if required.

Thanks for that! I have submitted a PR with a test for this: https://github.com/web-platform-tests/wpt/pull/29877
Comment 9 MoLow 2021-08-03 10:35:30 PDT
Created attachment 434840 [details]
Patch
Comment 10 MoLow 2021-08-03 23:30:46 PDT
Created attachment 434888 [details]
Patch
Comment 11 youenn fablet 2021-09-14 07:29:59 PDT
Comment on attachment 434888 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=434888&action=review

> Source/WebKit/ChangeLog:8
> +        Added a new test at https://github.com/web-platform-tests/wpt/pull/29877

We probably want a non-regression test, either the WPT one or a WebKit specific one in this patch.
Comment 12 MoLow 2021-09-14 07:55:05 PDT
(In reply to youenn fablet from comment #11)
> Comment on attachment 434888 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=434888&action=review
> 
> > Source/WebKit/ChangeLog:8
> > +        Added a new test at https://github.com/web-platform-tests/wpt/pull/29877
> 
> We probably want a non-regression test, either the WPT one or a WebKit
> specific one in this patch.

I am not sure I understand. can you describe what such a test will perform? thanks
Comment 13 youenn fablet 2021-09-14 07:59:39 PDT
You added a test in WPT (webdriver/tests/switch_to_frame/switch_webelement.py).
I guess we would want to run this test as part of WebKit CI, or run an equivalent but WebKit-specific test if we do not have ways to run WPT WebDriver tests yet.
I am not familiar with how WebDriver is being tested in WebKit.
Comment 14 Tyler Wilcock 2021-09-14 09:08:15 PDT
You can import WPTs with the `Tools/Scripts/import-w3c-tests` script. For example:

Tools/Scripts/import-w3c-tests --tip-of-tree web-platform-tests/webdriver/tests/switch_to_frame

Assuming WebKit can run WebDriver WPTs (I'm also not sure), you may want to make the import a separate bug and patch, since it will pull in a few other tests too. You'd need to create test expectations for the newly imported tests — the new one you added would presumably be marked as fail. Then this patch would mark the test as passing.

Here's an example of a bug / patch that imports WPTs and sets expectations: https://bugs.webkit.org/show_bug.cgi?id=225369
Comment 15 Tyler Wilcock 2021-09-14 09:10:41 PDT
Setting expectations is done by running the tests. The test runner will notice the newly imported tests are missing them and write new ones.

Tools/Scripts/run-webkit-tests --debug LayoutTests/imported/w3c/web-platform-tests/webdriver/tests/switch_to_frame
Comment 16 Devin Rousso 2021-09-20 18:37:09 PDT
Comment on attachment 434888 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=434888&action=review

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:33
> +var NodeType = {

Style: `const`?

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:34
> +    ELEMENT: 1,

Style: Is there a reason to uppercase these?  We normally CamelCase enums.

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:36
> +    DOCUMENT_FRAGMENT_NODE: 11

Style: missing trailing comma

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:37
> +  };

Style: odd indentation

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:207
> +    _isElement(value) {

Style: `{` on it's own line

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js:212
> +        return ((typeof value == 'object' && value != null) ||

Style: please use `===` and `!==` unless you have a really good reason not to
Style: we prefer `"`
Style: can we split this into separate `if` or something?  Maybe use some early-returns and separate each line out so it's easier to read?