Skip to content

Commit 7c8c5f9

Browse files
committed
[testdriver] Add an execute_script function to testdriver.
This provides a direct way to execute script in another browsing context.
1 parent 14560be commit 7c8c5f9

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

rfcs/execute_script.md

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# RFC 89: `testdriver` Add an `execute_script` method.
2+
3+
## Summary
4+
5+
Add an `execute_script` method to testdriver that takes a js function,
6+
arguments to pass to the function, and the context id to execute it it
7+
in a remote context. If the function returns a promise we return the
8+
resolved value of the promise, otherwise we return the return value of
9+
the function.
10+
11+
## Details
12+
13+
Sometimes a test window wants to check the status of something in a
14+
remote window. It's possible to do this in a number of ways, for
15+
example by posting messages from the remote window to the test
16+
window. However in cross-origin cases messge passing on the js side
17+
can be difficult or impossible. In addition when tests are defined in
18+
the test window, it's useful to avoid putting complex logic in other
19+
browsing contexts because these won't have the same error handling
20+
properties as the test window.
21+
22+
A simple way to solve these problems is to provide a mechansim to
23+
execute script in a different context. This isn't possible using
24+
content APIs alone, but is possible in WebDriver, and we can reuse
25+
that to define a `execute_script` function that works across contexts:
26+
27+
```
28+
execute_script(fn, args, context)
29+
```
30+
31+
`body` is a js function for the script to execute. To pass it to the
32+
remote context, this is converted to a string using
33+
`toString()`. `args` is null or an array of arguments to pass to the
34+
function on the remote side. Arguments are passed as JSON. `context`
35+
is an object that can be resolved as a testdriver context id to
36+
identify the remote context (see [RFC
37+
88](https://github.com/web-platform-tests/rfcs/pull/88). If the return
38+
value of the function when executed in the remote context is a promise
39+
the promise returned by `execute_script` resolves to the resolved
40+
value of that promise. Otherwise the `execute_script` promise resolves
41+
to the return value of the function.
42+
43+
The wptrunner implementation uses [Execute Async
44+
Script](https://w3c.github.io/webdriver/#execute-async-script). We
45+
wrap the provided script text and arguments into an `Execute Async
46+
Script` call as:
47+
48+
```
49+
let callback = arguments[arguments.length - 1];
50+
let rv = ({function_string}).apply(null, {json.dumps(args)});
51+
return Promise.resolve(rv).then(callback)
52+
``
53+
54+
## Example
55+
56+
```
57+
<iframe src="child.html"></iframe>
58+
<script>
59+
setup({single_test: true});
60+
onload = {
61+
let value = test_driver.execute_script(async (elemId) => {
62+
await new Promise(resolve => onload(resolve))
63+
return document.getElementById(elemId).textContent
64+
}, ["test"], iframe.contentWindow);
65+
assert_equals(value, "PASS");
66+
done();
67+
}
68+
</script>
69+
```
70+
71+
## Risks
72+
73+
WebDriver is single-threaded, so all the WebDriver-based actions need
74+
to be queued. That means that waiting for a promise in a remote
75+
context blocks all testdriver functionality that uses WebDriver, and
76+
also blocks the harness from returning results. This implies a high
77+
risk of timeouts.
78+
79+
## References
80+
81+
[PR 29803](https://github.com/web-platform-tests/wpt/pull/29803)
82+
contains a prototype implementation of this.

0 commit comments

Comments
 (0)