-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Make testharness tests run in a top-level browsing context #13966
Conversation
@jugglinmike This is the alternative to #13881. @lukebjerring if you have the ability to generate a complete run of this to look for regressions that would be very helpful. I fixed some problems I found in a m-c run, but there were a few other issues remaining. |
da1f337
to
7b7a748
Compare
5acbb3d
to
0e5347a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By no means a complete review, but from a quick look through.
protocol.base.execute_script(self.script % format_map, async=True) | ||
test_window = protocol.testharness.get_test_window(self.window_id, parent_window) | ||
|
||
protocol.base.execute_script("window.open('about:blank', '%s', 'noopener')" % self.window_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that Edge will shortly be using this and doesn't support noopener
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opening from an iframe apparently works in older versions of Safari:
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentWindow.open('about:blank', 'window_id');
document.body.removeChild(iframe);
Though Edge's behavior isn't what we want. From the child window:
> !!opener
true
> opener.document
X Permission denied
We can just null out the window's opener
property:
var win = open('about:blank');
win.opener = null;
This feels a little artificial. Is it important that the window be disowned specifically? If so, maybe we could inject an anchor with target="_blank" rel="noreferrer"
and click on the link. That's spec'd to disown the window, and it works in Edge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I"m not super worried about this; any test that depends on the opener being null at the moment is already broken. I only used noopener to prove that we aren't depending on the opener any more,
In the medium term I hope that everyone will implement the Create Window
webdriver endpoint, which is inteded to have exactly the behaviour we require here and also returns the handle of the new window so we can delete the window finding code. I'm happy to do the more complex solution in the interim if people think that it's important, but otherwise I would tend to argue that this good enough for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to worry about older versions of Safari; it's almost exclusively Edge that's my concern here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anyone happen to have Edge set up so we can verify if this PR works there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's try explicitly setting window.open().opener = null, because I don't think that can make anything worse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't think wrong; I tried this and Chrome crashes (or maybe there's an uncaught exception due to trying to set a readonly property).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgraham https://gist.github.com/fb3941b207c8d9ff3f3343a7bf302165 (this is with Selenium)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgraham https://gist.github.com/c939fd3a4276f3bc056e175e483e57a5 (edge_webdriver)
@jgraham EDIT: In case someone with access to https://wpt.fyi/admin/results/upload wants to get a PR into wpt.fyi in future, I just:
|
Whoops - @jgraham I didn't realise affected tests would be like, 19 css tests. |
@lukebjerring I pushed a separate branch to Bocoup's fork which included a commit to enable results |
Err, my bad on pushing 3d0c723, reverted. |
3d0c723
to
0e5347a
Compare
tools/wptrunner/wptrunner/executors/testharness_webdriver_resume.js
Outdated
Show resolved
Hide resolved
protocol.base.execute_script(self.script % format_map, async=True) | ||
test_window = protocol.testharness.get_test_window(self.window_id, parent_window) | ||
|
||
protocol.base.execute_script("window.open('about:blank', '%s', 'noopener')" % self.window_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opening from an iframe apparently works in older versions of Safari:
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentWindow.open('about:blank', 'window_id');
document.body.removeChild(iframe);
Though Edge's behavior isn't what we want. From the child window:
> !!opener
true
> opener.document
X Permission denied
We can just null out the window's opener
property:
var win = open('about:blank');
win.opener = null;
This feels a little artificial. Is it important that the window be disowned specifically? If so, maybe we could inject an anchor with target="_blank" rel="noreferrer"
and click on the link. That's spec'd to disown the window, and it works in Edge.
9097743
to
538e362
Compare
} else if (document.readyState !== "loading") { | ||
callback(true); | ||
} else { | ||
document.addEventListener("DOMContentLoaded", () => callback(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this readyStateChange
being ready
to match WebDriver.
538e362
to
f109aa7
Compare
Traditionally testharness tests ran in a auxillary browsing context opened using window.open and with access to the opener. This works well because the long-lived nature of the opener helps to avoid some of the race conditions that would otherwise occur. But it doesn't work *that* well; the recent refactor to stop continually focusing the opener broke tests that alter document.domain or otherwise prevent the opener being same-domain with the test window. And future platform features may cause the opener to be nulled out entirely so even a postMessage based fix wouldn't work. To solve all of this, this patch refactors things so that the initial window doesn't contain any logic at all and is just used to keep the browser alive between tests. Most of the logic moves to testharnessreport.js which is loaded once per test. In order to get the right timeout when timeout_multiplier is set this requires an addition to the product API in wptrunner to expose a function for getting the timeout multiplier. This allows us to get the timeout_multiplier for testharness tests upfront and avoids the need to change the content of testharnessreport when we start running testharness tests, or to restart the server for each test type. The main issue with the single-window implementation is that we need to start injecting script once the test page has loaded testharnessreport.js. For most browsers we are able to use pageLoadStrategy=eager to control this; in that case we can start running tests once DOMContentLoaded is reached. Chrome doesn't support this pageLoadStrategy, however, so we have to fake support with custom script.
f109aa7
to
2ed77c9
Compare
This seems to fix |
@jgraham so what's the status of this now? |
Works on Firefox and Chrome on Linux and macOS. Status for Edge and Safari is unknown. |
Safari looks happy on Azure Pipelines. If you trigger Azure Pipelines again even more stuff will run. |
In Edge almost all (all?) the testharness.js tests now give
|
I couldn't later reproduce that, so I've no idea what's up with that; let's assume this works. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 27 of 27 files at r1, 3 of 3 files at r2, 2 of 2 files at r3.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @jgraham, @frivoal, @annevk, @zqzhang, @zcorpan, @dbaron, @jdm, @foolip, and @domenic)
tools/wptrunner/wptrunner/products.py, line 34 at r1 (raw file):
def __init__(self, config, product): module = product_module(config, product) data = module.__wptrunner__
What would it take to have a function (or just a variable) in that module that returned a Product?
tools/wptrunner/wptrunner/products.py, line 52 at r1 (raw file):
def load_product(config, product, load_cls=False):
What's the point of the load_cls
arg here? When does it make sense to call this with it being True
; why wouldn't you just construct the class yourself?
tools/wptrunner/wptrunner/browsers/firefox.py, line 103 at r1 (raw file):
capabilities = {} if test_type == "testharness": capabilities["pageLoadStrategy"] = "eager"
Can we not make this default to eager, somehow? The fact we have all of this is to deal with ChromeDriver not supporting it, right?
tools/wptrunner/wptrunner/executors/base.py, line 525 at r1 (raw file):
def process_complete(self, url, payload): rv = [strip_server(url)] + payload
Is this an earlier underlying bug? What caught this?
tools/wptrunner/wptrunner/executors/executormarionette.py, line 221 at r1 (raw file):
return test_window time.sleep(0.1)
This is addressing the fact that closing windows is async, right?
tools/wptserve/wptserve/stash.py, line 175 at r1 (raw file):
return value
Given you're adding loads of whitespace, can you enable whichever flake8 check checks for them, or does that still have lots of failures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @gsnedders, @frivoal, @annevk, @zqzhang, @zcorpan, @dbaron, @jdm, @foolip, and @domenic)
tools/wptrunner/wptrunner/products.py, line 34 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
What would it take to have a function (or just a variable) in that module that returned a Product?
A new PR to implement that.
tools/wptrunner/wptrunner/products.py, line 52 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
What's the point of the
load_cls
arg here? When does it make sense to call this with it beingTrue
; why wouldn't you just construct the class yourself?
Fair point. Should that block this PR?
tools/wptrunner/wptrunner/browsers/firefox.py, line 103 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
Can we not make this default to eager, somehow? The fact we have all of this is to deal with ChromeDriver not supporting it, right?
Chromedriver doesn't support it and it's not clear that it's right for other test types. We could set this in the executor, but you'd still need to set it once per executor.
tools/wptrunner/wptrunner/executors/base.py, line 525 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
Is this an earlier underlying bug? What caught this?
I think this is a change because we aren't returning the same URL as before.
tools/wptrunner/wptrunner/executors/executormarionette.py, line 221 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
This is addressing the fact that closing windows is async, right?
s/closing/opening/ and yes.
tools/wptserve/wptserve/stash.py, line 175 at r1 (raw file):
Previously, gsnedders (Geoffrey Sneddon) wrote…
Given you're adding loads of whitespace, can you enable whichever flake8 check checks for them, or does that still have lots of failures?
I didn't check but I would expect lots of failures. We should do that as a seperate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: complete! all files reviewed, all discussions resolved (waiting on @frivoal, @annevk, @zqzhang, @zcorpan, @dbaron, @jdm, @foolip, and @domenic)
tools/wptrunner/wptrunner/products.py, line 34 at r1 (raw file):
Previously, jgraham wrote…
A new PR to implement that.
Given you've done half the work here, it's probably worth actually prioritising this now…
tools/wptrunner/wptrunner/products.py, line 52 at r1 (raw file):
Previously, jgraham wrote…
Fair point. Should that block this PR?
Let's actually keep this as is on the assumption we'll refactor so the module itself gives the Product
and this provides an abstraction to make this easier, and remove this then.
tools/wptrunner/wptrunner/browsers/firefox.py, line 103 at r1 (raw file):
Previously, jgraham wrote…
Chromedriver doesn't support it and it's not clear that it's right for other test types. We could set this in the executor, but you'd still need to set it once per executor.
I guess both of these suck. Meh.
@jgraham @gsnedders I see that regressions were looked for in #13966 (comment), but that was a month before this was merged. It would have been great to do another trial right before landing. |
fixes #13418
This change is