Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend locateNodes with a locator to get navigable's container element #811

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2960,6 +2960,7 @@ To <dfn>await a navigation</dfn> given |navigable|, |request|, |wait condition|,
browsingContext.Locator = (
browsingContext.AccessibilityLocator /
browsingContext.CssLocator /
browsingContext.ContainerLocator /
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we cannot have the container as part of the return value of the browsingContext.getTree command? It would be somewhat similar to the clientWindow field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that API currently does not include any shared references from script and would not allow expressing the ownership of the returned DOM element.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: we could probably plumb it via the getTree along with the other options we might need to define how to return the element but to me it looks like locateNodes is a better place compared to the getTree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a slight misconception here: sharedId for nodes doesn't depend on ownership. locateNodes also doesn't provide a way to set the ownership. I broadly think that's fine for this API; it doesn't seem more useful to hold a reference to the container element than the Window itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, when I was reviewing the locateNodes PR I recall there was the ownership parameter but indeed I do not see it after checking now. If we were to use the locateNodes for things other than a11y in Puppeteer, we would definitely need the ownership param to match the existing behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I recall now: so in CDP we retain the resulting collection and not nodes individually so that is still different to the API here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WebDriver model to this point is that the sharedId for a node is just an intrinsic property of the node, and returning it doesn't affect the lifetime of the node in any way. executeScript and friends also provide a way to take (shared) ownership of the (currently only root) return value.

We already have lots of APIs that return objects without providing any way to take ownership of them (notably anything returning a context). I don't immediately see why you'd need to take ownership of an iframe element with this kind of API; if something removes the iframe from the DOM you're probably in an unexpected state even if you still have a reference to the js object.

Anyway, I don't have a really strong opinion here, but if clients ~always want to know which iframe owns a nested browsing context, I think that getTree would work. If it's a rarer requirement, or there really is a strong use case for taking ownership of the iframe itself, then using either a separate command or a locator could work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify on the ownership: all element handles in Puppeteer (and maybe other clients) are retained until the client releases them. It allows getting the a handle to something and, for example, checking that it was disconnected for DOM or operating on temporary objects without polluting the global scope (e.g., creating some elements, retaining them via Puppeteer, using them in scripts later). The getter to obtain the container for a browsing context is the same kind of handle and should follow the same lifecycle.

Currently, we can evaluate using a sharedId to retain but it would be great to avoid the round trip.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we currently only have requirements to provide this data in a separate command because this data is not always needed. Therefore, I think we should not bring it into getTree to avoid the overhead of finding out the sharedId for each browsing context. I still think the locateNodes is probably the best place given that it returns nodes and any changes made to locateNodes (e.g., bringing the ownership parameter back) should also affect this method.

browsingContext.InnerTextLocator /
browsingContext.XPathLocator
)
Expand All @@ -2977,6 +2978,13 @@ browsingContext.CssLocator = {
value: text
}

browsingContext.ContainerLocator = {
type: "container",
value: {
context: text,
}
}

browsingContext.InnerTextLocator = {
type: "innerText",
value: text,
Expand Down Expand Up @@ -3776,6 +3784,18 @@ To <dfn>locate nodes using CSS</dfn> with given |navigable|, |context nodes|,

</div>

<div algorithm="locate the container element">
To <dfn>locate the container element</dfn> with given |navigable|:

1. Let |returned nodes| be an empty [=/list=].

1. If |navigable|'s [=navigable/container=] is not null,
append |navigable|'s [=navigable/container=] to |returned nodes|.

1. Return |returned nodes|.

</div>

<div algorithm="locate nodes using XPath">

To <dfn>locate nodes using XPath</dfn> with given |navigable|, |context nodes|,
Expand Down Expand Up @@ -4043,6 +4063,18 @@ The [=remote end steps=] with |session| and |command parameters| are:
1. Let |result nodes| be [=locate nodes using accessibility attributes=]
given |context nodes|, |selector|, and |maximum returned node count|.

<dt>|type| is the string "<code>container</code>"
<dd>

1. If |start nodes parameter| is not null,
return [=error=] with [=error code=] "<code>invalid argument</code>".

1. Let |selector| be |locator|["<code>value</code>"].

1. Let |child navigable| be |selector|["<code>context</code>"].

1. Let |result nodes| be [=locate the container element=] given |child navigable|.

1. Assert: |maximum returned node count| is null or [=list/size=] of |result nodes| is less
than or equal to |maximum returned node count|.

Expand Down