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

Implement browsingContext.locateNodes #547

Merged
merged 86 commits into from
Nov 2, 2023
Merged
Changes from 7 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
c7d9020
Implement browsingContext.locateNodes
jimevanssfdc Sep 14, 2023
70815c5
Fixing closing </div> tags
jimevanssfdc Sep 14, 2023
3273c1a
Fix variable usage
jimevanssfdc Sep 14, 2023
841dd88
More variable fixes
jimevanssfdc Sep 14, 2023
02b475d
Missed a variable instance
jimevanssfdc Sep 14, 2023
a44d832
Fixing ignored vars
jimevanssfdc Sep 14, 2023
8d736ff
Fix argument calls to algorithms
jimevanssfdc Sep 14, 2023
d12c49e
Fix typos from initial review
jimevanssfdc Sep 14, 2023
5f86c3e
Move to using script.ContextTarget for location instead of browsingCo…
jimevanssfdc Sep 17, 2023
65e042a
Missed a variable
jimevanssfdc Sep 17, 2023
de398fa
Remove JavaScriptLocator from spec for now
jimevanssfdc Sep 18, 2023
91343e5
Remove Frame locator
jimevanssfdc Sep 18, 2023
1103af6
Complete refactor
jimevanssfdc Sep 18, 2023
f9ad500
Fixing syntax errors
jimevanssfdc Sep 18, 2023
141d1be
Fix variable mixup
jimevanssfdc Sep 18, 2023
e35f766
Fix a variable syntax error
jimevanssfdc Sep 18, 2023
598d1de
Refer to correct variable in get elements by text
jimevanssfdc Sep 18, 2023
bd6084c
Remove unused variable
jimevanssfdc Sep 18, 2023
f6e4a16
Updating variable name to be more succint
jimevanssfdc Sep 18, 2023
2eca140
Fix return variable names to be more succinct
jimevanssfdc Sep 18, 2023
3dea404
Fix scoping root reference
jimevanssfdc Sep 18, 2023
91caa7f
Fix incorrect markup for <dl>
jimevanssfdc Sep 18, 2023
4d05a1d
Add forgotten equals sign
jimevanssfdc Sep 18, 2023
652eee3
Add reference to XPath snapshotItem
jimevanssfdc Sep 18, 2023
52216b4
Cosmetic update to locate using xpath algorithm
jimevanssfdc Sep 18, 2023
d26d4b0
Fix typo for matchCase attribute
jimevanssfdc Sep 18, 2023
2587025
Fix reference to result nodes
jimevanssfdc Sep 18, 2023
f6e6478
Fix return of nodes from CSS
jimevanssfdc Sep 18, 2023
bdfc7ba
Change TextLocator to use RegExp instead of other args
jimevanssfdc Sep 21, 2023
44f19fd
Merge branch 'main' into jimevans/locate-nodes
jimevans Sep 21, 2023
6da2cd8
Fix closing tag typo
jimevanssfdc Sep 21, 2023
7bf6647
Enable returning non-element nodes from XPath
jimevanssfdc Sep 22, 2023
fc0bb31
Missed vertical bar in find by text algorithm
jimevanssfdc Sep 22, 2023
70d5c2e
Tighten up language around calling RegExp.test()
jimevanssfdc Sep 22, 2023
a76f33f
Correct type to NodeRemoteValue
jimevans Sep 25, 2023
12e122c
Fix poor grammar
jimevans Sep 25, 2023
151ea70
Use <code> tag
jimevans Sep 25, 2023
dae6599
Remove erroneous space
jimevans Sep 28, 2023
8497c21
Rename algorithm for finding element by text
jimevanssfdc Oct 5, 2023
c00d75d
Address review comments
jimevanssfdc Oct 5, 2023
870a0b1
Handle review comments
jimevanssfdc Oct 6, 2023
4faf371
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 6, 2023
19e293e
First pass at replacing arrays with list
jimevanssfdc Oct 6, 2023
4dc30da
Reformat reading of command parameters
jimevanssfdc Oct 6, 2023
122a7a1
Fix syntax
jimevanssfdc Oct 6, 2023
e4605d1
Fix syntax
jimevanssfdc Oct 6, 2023
96d5079
Attempt to resolve locate by text issues
jimevanssfdc Oct 6, 2023
fa10dbc
Reomve unused variable
jimevanssfdc Oct 6, 2023
43752bf
Correct indentation
jimevanssfdc Oct 6, 2023
9d3f6f1
Aligning variable names and logic with property names
jimevanssfdc Oct 6, 2023
8f7d9c0
Fix missed variable name
jimevanssfdc Oct 6, 2023
552f203
Add note to indicate direct calls to XPath algorithms
jimevanssfdc Oct 6, 2023
98cc9f2
Move note into algorithm block
jimevanssfdc Oct 6, 2023
8988a1d
Update index.bs with correct punctuation
jimevans Oct 9, 2023
b97e723
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 9, 2023
165b4fc
Rename maxNodes to maxReturnedNodeCount
jimevanssfdc Oct 9, 2023
b137ed2
Update find by text algorithm to correctly find elements
jimevanssfdc Oct 10, 2023
9f57155
correct links to list/append
jimevanssfdc Oct 10, 2023
873a9e7
Attempt to specify string operations for locate by text
jimevanssfdc Oct 10, 2023
227da04
Attempt to fix infra links
jimevanssfdc Oct 10, 2023
f0eda02
Trying again to link to infra terms
jimevanssfdc Oct 10, 2023
efefd38
Correct substring case logic
jimevanssfdc Oct 10, 2023
3568ca4
Attempting to specify case-insensitivity in search
jimevanssfdc Oct 10, 2023
2eaa2b4
Link to Unicode spec for toUppercase
jimevanssfdc Oct 10, 2023
b3a2e59
Forgot a location of toUppercase
jimevanssfdc Oct 10, 2023
29a0314
Rename 'find by text' algorithm to 'find by inner text'
jimevanssfdc Oct 11, 2023
5516d01
Missed invocation of algorithm in previous commit
jimevanssfdc Oct 11, 2023
b66e363
Fix variable declaration
jimevanssfdc Oct 11, 2023
3d5b847
Missed location of changing 'text' to 'innerText'
jimevanssfdc Oct 11, 2023
aba2f66
remove extraneous 'return'
jimevanssfdc Oct 11, 2023
35f6a88
clean up command parameter property access
jimevanssfdc Oct 11, 2023
3c3eefd
more command parameter property access cleanup
jimevanssfdc Oct 11, 2023
d0bb5e1
Further grammar cleanup
jimevanssfdc Oct 11, 2023
13586ab
Still more grammar cleanup
jimevanssfdc Oct 11, 2023
a3cea57
Merge branch 'main' into jimevans/locate-nodes
jimevans Oct 12, 2023
297a11f
respond to code review comments
jimevanssfdc Oct 13, 2023
5572041
Add sandbox parameter to command parameters
jimevanssfdc Oct 13, 2023
99837f4
remove extraneous definition
jimevanssfdc Oct 13, 2023
c6f041e
Correct find by inner text algorithm to not early return
jimevanssfdc Oct 15, 2023
c8b7516
correct variable name typo
jimevanssfdc Oct 15, 2023
be123be
fix CDDL definition errors
jimevanssfdc Oct 26, 2023
0d77682
Add editorial change on assert
jimevans Oct 27, 2023
c14f010
Update defintion of 'invalid selector' error code
jimevanssfdc Oct 26, 2023
1d68171
Define behavior of inner text locator on empty string
jimevanssfdc Oct 26, 2023
fe2c9fc
Remove contextId from LocateNodesResult
jimevanssfdc Oct 27, 2023
ae9938d
Removed variable for 'serialization internal map'
jimevanssfdc Oct 27, 2023
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
322 changes: 322 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,7 @@ BrowsingContextCommand = (
browsingContext.Create //
browsingContext.GetTree //
browsingContext.HandleUserPrompt //
browsingContext.LocateNodes //
browsingContext.Navigate //
browsingContext.Print //
browsingContext.Reload //
Expand All @@ -1853,6 +1854,7 @@ BrowsingContextResult = (
browsingContext.CaptureScreenshotResult /
browsingContext.CreateResult /
browsingContext.GetTreeResult /
browsingContext.LocateNodesResult /
browsingContext.NavigateResult /
browsingContext.PrintResult
)
Expand Down Expand Up @@ -2089,6 +2091,48 @@ To <dfn>await a navigation</dfn> given |context|, |request|, |wait condition|, a

</div>

#### The browsingContext.Locator Type #### {#type-browsingContext-Locator}

[=remote end definition=] and [=local end definition=]

<pre class="cddl remote-cddl local-cddl">
browsingContext.Locator = (
jimevans marked this conversation as resolved.
Show resolved Hide resolved
browsingContext.CssLocator /
browsingContext.FrameLocator /
browsingContext.ScriptLocator /
browsingContext.TextLocator /
browsingContext.XPathLocator
)

browsingContext.CssLocator = {
type: "css",
value: text
}

browsingContext.FrameLocator = {
jimevans marked this conversation as resolved.
Show resolved Hide resolved
type: "frame"
shs96c marked this conversation as resolved.
Show resolved Hide resolved
}

browsingContext.JavaScriptLocator {
jimevans marked this conversation as resolved.
Show resolved Hide resolved
type: "script",
functionDeclaration: text
}

browsingContext.TextLocator {
OrKoN marked this conversation as resolved.
Show resolved Hide resolved
jimevans marked this conversation as resolved.
Show resolved Hide resolved
type: "text",
value: text,
? match: "full" / "partial"
}

browsingContext.XPathLocator {
type: "xpath",
value: text
}
</pre>

The <code>browsingContext.Locator</code> type is a provides details on the strategy
jimevans marked this conversation as resolved.
Show resolved Hide resolved
for locating a node in a document.

#### The browsingContext.Navigation Type #### {#type-browsingContext-Navigation}

[=remote end definition=] and [=local end definition=]
Expand Down Expand Up @@ -2725,6 +2769,284 @@ The [=remote end steps=] with <var ignore>session</var> and |command parameters|

1. Return [=success=] with data null.

</div>
#### The browsingContext.locateNodes Command #### {#command-browsingContext-locateNodes}
jimevans marked this conversation as resolved.
Show resolved Hide resolved

The <dfn export for=commands>browsingContext.locateNodes</dfn> command returns a
list of all nodes matching the specified locators.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

<dl>
<dt>Command Type</dt>
<dd>
<pre class="cddl remote-cddl">
browsingContext.LocateNodes = (
method: "browsingContext.locateNodes",
params: browsingContext.LocateNodesParameters
)

browsingContext.LocateNodesParameters = {
jimevans marked this conversation as resolved.
Show resolved Hide resolved
context: browsingContext.BrowsingContext,
locators: [ + browsingContext.Locator ],
? startNode: script.SharedReference,
jimevans marked this conversation as resolved.
Show resolved Hide resolved
? waitTimeout: js-uint
shs96c marked this conversation as resolved.
Show resolved Hide resolved
jimevans marked this conversation as resolved.
Show resolved Hide resolved
}
</pre>
</dd>
<dt>Result Type</dt>
<dd>
<pre class="cddl local-cddl">
browsingContext.LocateNodesResult = {
context: browsingContext.BrowsingContext,
jimevans marked this conversation as resolved.
Show resolved Hide resolved
nodes: [ * script.RemoteNodeValue ]
jimevans marked this conversation as resolved.
Show resolved Hide resolved
}
</pre>
</dd>
</dl>

<div algorithm="locate nodes using CSS">
To <dfn>locate nodes using CSS</dfn> with given |context|, |context nodes|,
|selector| and <var ignore>session</var>:

1. Let |returned nodes| be an empty array.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. For each |context node| of |context nodes|:

1. Let |elements| be the result of calling querySelectorAll() on |context| with |context node|
as this and |selector| as the argument. If this causes an exception to be thrown,
return [=error=] with [=error code=] [=invalid selector=].

1. Append |elements| to |returned nodes|

1. Return |returned nodes|.

</div>

<div algorithm="locate nodes using XPath">
To <dfn>locate nodes using XPath</dfn> with given |context|, |context nodes|
jimevans marked this conversation as resolved.
Show resolved Hide resolved
|selector| and <var ignore>session</var>:

1. Let |returned nodes| be an empty array.

1. For each |context node| of |context nodes|:

1. Let |evaluateResult| be the result of calling evaluate on |context|, with arguments |selector|,
jimevans marked this conversation as resolved.
Show resolved Hide resolved
|context node|, null, ORDERED_NODE_SNAPSHOT_TYPE, and null.

1. Let |index| be 0.

1. Let |length| be the result of getting the property "snapshotLength" from
|evaluateResult|. If this throws an XPathException return [=error=] with
[=error code=] [=invalid selector=], otherwise if this throws any other
exception return return [=error=] with [=error code=] [=unknown error=].
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. Repeat, while |index| is less than |length|:

1. Let |node| be the result of calling snapshotItem with evaluateResult
as this and index as the argument.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. If |node| is not an element return [=error=] with [=error code=]
Copy link
Member

Choose a reason for hiding this comment

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

It definitely seems like we could support returning non-Element nodes here. Maybe even non-nodes if we can select them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@jgraham We can support returning non-element nodes, and I'll update the PR to reflect that. However, I would like to retain the restriction to only return nodes from XPath, since the command is locateNodes.

[=invalid selector=].

1. Append |node| to |returned nodes|.

1. Increment |index| by 1.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. Return |returned nodes|
jimevans marked this conversation as resolved.
Show resolved Hide resolved

</div>

<div algorithm="locate nodes using text">
jimevans marked this conversation as resolved.
Show resolved Hide resolved
To <dfn>locate nodes using text</dfn> with given |context|, |context nodes|,
|selector|, |match| and <var ignore>session</var>:

1. Let |returned nodes| be an empty array.

1. For each |context node| of |context nodes|:

1. Let |element nodes| be the result of calling querySelectorAll() on |context| with |context node|
as this and "*" as the argument. If this causes an exception to be thrown,
return [=error=] with [=error code=] [=invalid selector=].

1. Let |elements| be the result of converting |element nodes| to an array.

1. If |match| is "partial", append the results of calling
<code>|elements|.filter((e) => e.innerText.contains(|selector|))</code>
to |returned nodes|, otherwise append the results of calling
<code>|elements|.filter((e) => e.innerText === |selector|)</code>,

1. Return |returned nodes|.

</div>

<div algorithm="locate nodes using script">
To <dfn>locate nodes using script</dfn> with given |context|, |context nodes|,
|function declaration| and <var ignore>session</var>:

1. Let |returned nodes| be an empty array.

1. For each |context node| of |context nodes|:

1. Let |script result| be the result of executing the function in |context| defined
by the |function declaration| using |context node| as an argument.

1. If |script result| is an error, return [=error=] with
[=error code=] [=invalid selector=].

1. If |script result| is not a node list, return [=error=] with
[=error code=] [=invalid selector=].

1. Append |script result| to |returned nodes|.

1. Return |returned nodes|

</div>

<div algorithm="locate a frame context">
To <dfn>locate a frame context</dfn> with given |context|, |context nodes|
and |session|:

1. If length of |context nodes| is not equal to 1, return [=error=] with
[=error code=] [=invalid selector=].

1. Let |frame node| be the 0th element of |context nodes|.

1. Let |serialization options| be a [=/map=] matching the
<code>script.SerializationOptions</code> production with the fields
set to their default values.

1. Let |result ownership| be none.

1. Let |context target| be the a [=/map=] matching of the
<code>script.ContextTarget</code> production with the context field
set to the [=browsing context id=] of |context|.

1. Let |realm| be the result of [=trying=] to [=get a realm from a target=]
given |context target|.

1. Let |window proxy| be the result of [=serialize as a remote value=] with |frame node|,
|serialization options|, |result ownership|, a new map as <var ignore>serialization internal map</var>,
|realm| and |session|.

1. Return |window proxy|

</div>

<div algorithm="remote end steps for browsingContext.locateNodes">
The [=remote end steps=] with |session| and |command parameters| are:

1. Let |context id| be the value of the <code>context</code> field of
|command parameters|.

1. Let |context| be the result of [=trying=] to [=get a browsing context=]
with |context id|.

1. Assert: |context| is not null.

1. Let |locators| be the value of the <code>locators</code> field
of |command parameters|.

1. Assert: |locators| is not null.

1. Assert: |locators| length is > 0.

1. Let |start node parameter| be the value of the <code>startNode</code> field
of |command parameters|.

1. Let |start node| be the node corresponding to the documentElement of |context|.

1. If |start node parameter| is not null, set |start node| to the result of [=trying=] to
[=deserialize local value=] given |start node parameter|, and |session|.

1. Let |wait timeout| be the value of the <code>waitTimeout</code> field of |command
parameters| if present, or 0 otherwise.

1. Let |expiration time| be the current time plus |wait timeout| milliseconds.

1. Let |result nodes| be an empty array.

1. Perform the following steps until the current time is greater than |expiration time|
jimevans marked this conversation as resolved.
Show resolved Hide resolved
or |result nodes| is not empty.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. Let |context nodes| be an empty array.
jimevans marked this conversation as resolved.
Show resolved Hide resolved

1. Append |start node| to |context nodes|.

1. For each |locator| in |locators|:

1. Let |type| be the value of the type property of |locator|.

1. In the following list of conditions and associated steps, run the first set
jimevans marked this conversation as resolved.
Show resolved Hide resolved
of steps for which the associated condition is true, if any:

<dl>

<dt>|type| is the string "<code>css</code>"
<dd>
1. Let |selector| be the value of the value property of |locator|.

1. Let |context nodes| be a result of [=trying=] to [=locate nodes using css=]
given |context|, |context nodes|, |selector| and |session|.

<dt>|type| is the string "<code>xpath</code>"
<dd>
1. Let |selector| be the value of the value property of |locator|.

1. Let |context nodes| be a result of [=trying=] to [=locate nodes using xpath=]
given |context|, |context nodes|, |selector| and |session|.

<dt>|type| is the string "<code>frame</code>"
<dd>
1. Let |window proxy| be the result of [=trying=] to [=locate a frame context=]
given |context|, |context nodes|, |selector| and |session|.

1. Let |context| be the context property of the value property of |window proxy|.

1. Let |context nodes| be an empty array.

1. Append the node corresponding to the documentElement of |context| to
|context nodes|.

<dt>|type| is the string "<code>script</code>"
<dd>
1. Let |function declaration| be the value of the function declaration
property of |locator|.

1. Let |context nodes| be a result of [=trying=] to [=locate nodes using script=]
given |context|, |context nodes|, |function declaration| and |session|.

<dt>|type| is the string "<code>text</code>"
<dd>
1. Let |selector| be the value of the value property of |locator|.

1. Let |match| be the value of the match property of |locator| if
present, otherwise "full".

1. Let |context nodes| be a result of [=trying=] to [=locate nodes using text=]
given |context|, |context nodes|, |selector|, |match| and |session|

jimevans marked this conversation as resolved.
Show resolved Hide resolved
1. Append |context nodes| to |result nodes|

1. Let |serialization options| be a [=/map=] matching the
<code>script.SerializationOptions</code> production with the fields
set to their default values.

1. Let |result ownership| be none.

1. Let |context target| be the a [=/map=] matching of the
<code>script.ContextTarget</code> production with the context field
set to the [=browsing context id=] of |context|.

1. Let |realm| be the result of [=trying=] to [=get a realm from a target=]
given |context target|.

1. Let |result| be a [=/map=] matching the <code>browsingContext.LocateNodesResult</code>
production, with the <code>context</code> field set to |context| and the <code>nodes</code>
field set to the result of [=serialize as a remote value=] with |result nodes|,
|serialization options|, |result ownership|, a new map as <var ignore>serialization internal map</var>,
|realm| and |session|.

1. Return [=success=] with data |result|.

</div>

#### The browsingContext.navigate Command #### {#command-browsingContext-navigate}
Expand Down