Skip to content
Closed
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
114 changes: 114 additions & 0 deletions rfcs/context_uuid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# RFC 87: `testdriver` Extend the mechanisms for giving browsing contexts ids.

Choose a reason for hiding this comment

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

While the RFC title says "browsing contexts ids", is this / should this be actually IDs for Windows (and other realms)?
When we navigate from URL A to URL B (within the same browsing context), we need to, and the draft PR web-platform-tests/wpt#29803 does, distinguish these two.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's a bit ambiguous, or rather you can do both. In the PR, if you have an browsing context container with a uuid in the src attribute, that can be used as the uuid irespective of the current url of the loaded document. But if you have a noopener window you'd need to pass the uuid into subsequent URLs loaded in order to keep the same one, or otherwise generate a new one to get a different id for each document loaded. Which you want depends on what you're trying to achieve.


## Summary

Allow contexts to be identified using either a `testdriver_id`
property on the (window) global, or a `uuid` query parameter, either
on the container `src` attribute (for nested browsing contexts) or the
actual resource URL.

## Details

When interacting with either browsing contexts or scripting realms
(hereafter: contexts) other than the test window, it's necessary to
have an identifier for the context that's available both on the js
side and can also be used by WebDriver to identify the context in
question.

Because of the limitations of the WebDriver-based testdriver setup, we
don't have an existing UUID for each context which could be reused for
this purpose. Instead the `testdriver-extra.js` file in wptrunner
has a `get_window_id` function that takes a `WindowProxy` object,
looks for a `__wptrunner_id` property, if not present sets it to a new
UUID, and then returns the value. Then on the wptrunner side, we use
WebDriver to search the tree of open contexts, executing script in
each one to find the window with that property set.

This setup works OK for cases where the cross-origin policy allows
setting the property. We also support the case where the non-test
window includes testdriver.js and can postMessage a request to the
top-level window to initiate an action; with some work this allows
supporting any case where it's possible to get a js handle between the
test window and the top-level window. However we have no support for
noopener cases or COOP headers, or other cases where it's not possible
to pass messages between windows using js alone.

To address these use cases, we propose allowing the use of a `uuid`
query parameter on URLs, which will provide an alternate identifier
for the window that loads the URL.

In addition we propose updating the `__wptrunner_id` property name to
`testdriver_id`, and making it a documented part of the harness
setup. This will allow the default implementation of testdriver.js to
refer to the property directly rather than it being part of the
wptrunner implementation.

testdriver will get a new function `get_context_id(ctx)`, with the
following behaviour:
* If `ctx` is a string, return `ctx`.
* If ctx is a WindowProxy with a readable `location.href` which parses
Copy link
Member

Choose a reason for hiding this comment

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

By the 2-years-in-stable policy I've suggested elsewhere, we could use URLSearchParams:
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams#browser_compatibility

as a URL and has a `uuid` query parameter, return the UUID parameter.
* If ctx is a WindowProxy and it has a `testdriver_id` attribute,
return the value of the attribute, or if it doesn't have such an
attribute, but the Window is writable from the current context, set
`testdriver_id` to a new id and return that.
* If `ctx` is a nested browsing context container with a `src`
attribute (for `iframe`, `frame`, `embed`) or `data` attribute (for
`object`) and the attribute value parses as a URL with a uuid
query parameter, return the uuid parameter.

On the wptrunner side, we keep the same behaviour of searching through
the tree of browsing contexts, but in addition we parse `uuid` query
strings out of the attribute values of nested context containers and
the URLs of loaded documents, and match those against the target URL.

In this system a specific context may have more than one associated id
(if the various ways of setting it differ), but we can use any
associated id to get to the browsing context.

For noopener cases, we can now provide a uuid in the URL and use that
to invoke testdriver actions on the remote context:

```
// Use the server subn to generate a UUID
let uuid = "{{uuid()}}"
open(`child.html?uuid=${uuid}`)
// [...] stuff to ensure child is loaded etc.
// In this case the context identifier is used directly
test_driver.delete_all_cookies(uuid)
```

We can also access a cross-origin-nested context:
```
<iframe src=https://{{host}}:{{ports[https][1]}}/file.html?uuid={{uuid()}}></iframe>
<script>
onload = () => {
let frame = frames[0];
test_driver.delete_all_cookies(frame)
}
</script>
```

TODO: How should this extend to other resources such as worker scripts. For
Copy link
Member

Choose a reason for hiding this comment

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

Did you intend to leave the TODO here?

current testdriver functionality it doesn't make much sense to run in
a worker, but once we have cross-context messaging we might want to
send messages to a worker we can't access via js.

Choose a reason for hiding this comment

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

COEP tests contain script injection into workers/service workers (executor_js_path and sw_executor_js_path in /wpt/html/cross-origin-embedder-policy/credentialless/resources/common.js). I don't know the details though. FYI @ArthurSonzogni


## Risks

This may clash with existing use of a uuid parameter on URLs. A full
CI runs should be done to avoid unexpected changes to the test
results.

The system of having multiple ids for a given context is complex. In
particular there's a risk that once we have WebDriver implementations
that natively support providing an id to each context
(e.g. WebDriver-BiDi) we won't want to support this kind of slightly
hacky approach, but tests may depend on the implementation
details. That was the original reason for `__wptrunner_id` being
clearly an implementation detail.

## References

[PR 29803](https://github.com/web-platform-tests/wpt/pull/29803)
contains a prototype implementation of this.