Auto merge of #20837 - gterzian:tests_for_has_event_listener, r=cbrewster

Fix for document salvageable state

I noticed a bug where if the document was un-salavageable due to the presence of `beforeunload` listeners, this could be overwritten if there were no listeners for `unload`. This could also have happened if an iframe of the document had no listeners while the parent did.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20837)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-05-28 15:52:31 -04:00 committed by GitHub
commit 2439ab02b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 5 deletions

View file

@ -1665,7 +1665,9 @@ impl Document {
);
// TODO: Step 6, decrease the event loop's termination nesting level by 1.
// Step 7
self.salvageable.set(!has_listeners);
if has_listeners {
self.salvageable.set(false);
}
let mut can_unload = true;
// TODO: Step 8, also check sandboxing modals flag.
let default_prevented = event.DefaultPrevented();
@ -1681,9 +1683,11 @@ impl Document {
for iframe in self.iter_iframes() {
// TODO: handle the case of cross origin iframes.
let document = document_from_node(&*iframe);
if !document.prompt_to_unload(true) {
self.salvageable.set(document.salvageable());
can_unload = false;
can_unload = document.prompt_to_unload(true);
if !document.salvageable() {
self.salvageable.set(false);
}
if !can_unload {
break;
}
}
@ -1734,7 +1738,9 @@ impl Document {
);
self.fired_unload.set(true);
// Step 9
self.salvageable.set(!has_listeners);
if has_listeners {
self.salvageable.set(false);
}
}
// TODO: Step 8, decrease the event loop's termination nesting level by 1.

View file

@ -275100,6 +275100,16 @@
{}
]
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004-1.html": [
[
{}
]
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004-2.html": [
[
{}
]
],
"html/browsers/browsing-the-web/unloading-documents/prompt/manual-001.html": [
[
{}
@ -331319,6 +331329,12 @@
{}
]
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004.html": [
[
"/html/browsers/browsing-the-web/unloading-documents/prompt/004.html",
{}
]
],
"html/browsers/browsing-the-web/unloading-documents/unload/001.html": [
[
"/html/browsers/browsing-the-web/unloading-documents/unload/001.html",
@ -561520,6 +561536,18 @@
"c37ad1ea3a1c8e389f6066c95c7b2745648e9e7e",
"testharness"
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004-1.html": [
"3530a94754361d436b6c20496bea07eb0bec4893",
"support"
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004-2.html": [
"01dc2c7f9c673781291a5afbdb40ca0f0919e797",
"support"
],
"html/browsers/browsing-the-web/unloading-documents/prompt/004.html": [
"4c8485a929926005115dd0f8e2d2a2d8e1673c6f",
"testharness"
],
"html/browsers/browsing-the-web/unloading-documents/prompt/manual-001.html": [
"895580cf70904918397da755527c5dda3f227b8a",
"support"

View file

@ -0,0 +1,28 @@
<!doctype html>
004-1
<script>
var handleBeforeUnload = function() {
parent.beforeunload_fired = true;
removeListener();
setTimeout(function() {
parent.timeout_fired = true;
}, 1000);
}
var removeListener = function() {
assert_true(window.removeEventListener('beforeunload', handleBeforeUnload, false));
}
window.addEventListener('beforeunload', handleBeforeUnload, false);
onload = function() {
if (!parent.loaded) {
parent.loaded = true;
location="004-2.html?" + Math.random();
}
}
</script>
// child frame with no onbeforeunload listener. Should leave the parent as unsalvageable.
// Adding the iframe prevents potential implementation bugs where the the recursive steps of #prompt-to-unload-a-document
// would overwrite the salvageable state of the parent.
<iframe></iframe>

View file

@ -0,0 +1,5 @@
<!doctype html>
004-2
<script>
onload = function() {setTimeout(parent.t.step_func(function() {parent.start_test(); history.go(-1)}), 100)}
</script>

View file

@ -0,0 +1,29 @@
<!doctype html>
<title>salvagable state of document after setting beforeunload listener</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var t = async_test();
var loaded = false;
var beforeunload_fired = false;
var timeout_fired = false;
function start_test() {
step_timeout(
t.step_func(function() {
assert_true(beforeunload_fired);
assert_false(timeout_fired);
t.done()
}), 1000);
}
onload = function() {
var iframe = document.getElementsByTagName("iframe")[0]
onload = null;
iframe.src="004-1.html?" + Math.random();
};
</script>
<iframe></iframe>