-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
[wptrunner] Transmit test results via postMessage #13881
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,44 @@ | ||
document.title = '%(title)s'; | ||
|
||
window.addEventListener( | ||
"message", | ||
function(event) { | ||
window.message_queue.push(event); | ||
window.process_next_event(); | ||
}, | ||
false | ||
); | ||
|
||
|
||
window.process_next_event = function() { | ||
/* This function handles the next testdriver event. The presence of | ||
window.testdriver_callback is used as a switch; when that function | ||
is present we are able to handle the next event and when is is not | ||
present we must wait. Therefore to drive the event processing, this | ||
function must be called in two circumstances: | ||
* Every time there is a new event that we may be able to handle | ||
* Every time we set the callback function | ||
This function unsets the callback, so no further testdriver actions | ||
will be run until it is reset, which wptrunner does after it has | ||
completed handling the current action. | ||
*/ | ||
if (!window.testdriver_callback) { | ||
var message_queue = []; | ||
var source = null; | ||
|
||
/** | ||
* In preparation to execute a test, testdriver issues a number of messages | ||
* which should be queued until execution time. During execution, testdriver | ||
* consumes the queued messages by repeatedly "resuming" via `do_testharness`. | ||
* The sequence of these events is variable, so the handler must account for | ||
* cases where "resume" requests arrive before any messages are available (by | ||
* caching the request's source) and where messages arrive before "resume" | ||
* requests (by queuing the messages). | ||
*/ | ||
window.addEventListener("message", function(event) { | ||
if (!event.data) { | ||
return; | ||
} | ||
var event = window.message_queue.shift(); | ||
if (!event) { | ||
|
||
if (event.data.type === "testdriver-resume") { | ||
source = event.source; | ||
} else { | ||
message_queue.push(event.data); | ||
} | ||
|
||
if (!source || !message_queue.length) { | ||
return; | ||
} | ||
var data = event.data; | ||
|
||
reply(source, message_queue[0]); | ||
source = null; | ||
message_queue.shift(); | ||
}, false); | ||
|
||
function reply(source, data) { | ||
var payload = undefined; | ||
|
||
switch(data.type) { | ||
case "complete": | ||
var tests = event.data.tests; | ||
var status = event.data.status; | ||
var tests = data.tests; | ||
var status = data.status; | ||
|
||
var subtest_results = tests.map(function(x) { | ||
return [x.name, x.status, x.message, x.stack]; | ||
|
@@ -53,7 +55,11 @@ window.process_next_event = function() { | |
default: | ||
return; | ||
} | ||
var callback = window.testdriver_callback; | ||
window.testdriver_callback = null; | ||
callback([window.url, data.type, payload]); | ||
}; | ||
|
||
source.postMessage({ | ||
type: "testdriver-next message", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This type string doesn't match anything else. |
||
message: [window.url, data.type, payload] | ||
}, | ||
"*" | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,24 @@ | ||
var callback = arguments[arguments.length - 1]; | ||
window.opener.testdriver_callback = callback; | ||
window.opener.process_next_event(); | ||
|
||
window.addEventListener("message", function handle(event) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like the pattern where we keep adding and removing message listeners; we've had bags with such code before. Ideally we define the message handler once in |
||
if (!event.data || event.data.type !== "testdriver-next message") { | ||
return; | ||
} | ||
|
||
window.removeEventListener("message", handle); | ||
|
||
callback(event.data.message); | ||
}); | ||
|
||
/** | ||
* The current window and its opener belong to the same domain, making it | ||
* technically possible for data structures to be shared directly. Some | ||
* browser/WebDriver implementations [1] do not correctly serialize Arrays from | ||
* a foreign realm. Transmitting data structures via the `postMessage` API | ||
* avoids this issue because doing so involves de-serializing values in the | ||
* local realm. | ||
* | ||
* [1] This has been observed in Edge version 17 and/or the corresponding | ||
* release of Edgedriver | ||
*/ | ||
window.opener.postMessage({ type: "testdriver-resume" }, "*"); |
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 really understand the point of this; it seems like the identity of the test window is statically known here; it's
window.win
. Why do we need to keep updating it?