Update web-platform-tests to revision 34f9b93c2749043ba68485dea92d1fb554075e60

This commit is contained in:
WPT Sync Bot 2018-08-23 22:19:29 -04:00
parent fd64f11efe
commit ace02666c2
75 changed files with 1496 additions and 120 deletions

View file

@ -52,7 +52,7 @@ async_test(t => {
function acceptChLoaded() {
// Open a new window. Verify that the user agent does not attach the client
// hints.
var verify_win = window.open("do_not_expect_client_hints_headers.html");
var verify_win = window.open("resources/do_not_expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
}

View file

@ -1,2 +1,2 @@
<!DOCTYPE html>
<html><head><title>Dummy XHTML document</title></head><body /></html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Dummy XHTML document</title></head><body /></html>

View file

@ -40,6 +40,7 @@ test(function() {
assert_equals(ev.defaultPrevented, true, "defaultPrevented");
}, "preventDefault() should change defaultPrevented if cancelable is true.");
test(function() {
ev.initEvent("foo", true, true);
assert_equals(ev.cancelable, true, "cancelable (before)");
ev.returnValue = false;
assert_equals(ev.cancelable, true, "cancelable (after)");

View file

@ -0,0 +1,7 @@
<!doctype html>
<title>Reference for fieldset border gap</title>
<style>
div { position: relative; top: 25px; width: 100px; height: 50px; background: lime; }
</style>
<p>There should be no red.</p>
<div></div>

View file

@ -0,0 +1,10 @@
<!doctype html>
<title>fieldset border gap</title>
<link rel=match href=fieldset-border-gap-ref.html>
<style>
fieldset, legend { margin: 0; padding: 0; }
fieldset { border: none; border-top: 100px solid red; width: 100px; }
legend { width: 100px; height: 50px; background: lime; }
</style>
<p>There should be no red.</p>
<fieldset><legend></legend></fieldset>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<title>Reference for fieldset containing block</title>
<style>
p { margin: 0; height: 100px }
div { position: absolute; top: 108px; width: 100px; height: 100px; background: lime; }
</style>
<p>There should be no red.</p>
<div></div>

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<title>fieldset containing block</title>
<link rel=match href=fieldset-containing-block-ref.html>
<style>
p { margin: 0; height: 100px }
fieldset { position: relative; border: none; padding: 0; margin: 0; }
legend { padding: 0; width: 100px; height: 50px; background: lime; }
div { position: absolute; top: 0; width: 100px; height: 50px; background: lime; }
.behind { height:100px; top: 108px; background: red; }
</style>
<p>There should be no red.</p>
<div class="behind"></div>
<fieldset><legend></legend><div></div></fieldset>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<title>fieldset and div with display: contents</title>
<link rel=fieldset-foo-ref.html>
<style>
div { display: contents; }
</style>
<p>There should be a normal fieldset below with the legend "Foo".</p>
<fieldset>
<div>
<legend>Foo</legend>
</div>
</fieldset>

View file

@ -0,0 +1,6 @@
<!DOCTYPE html>
<title>Reference with a fieldset and legend "Foo"</title>
<p>There should be a normal fieldset below with the legend "Foo".</p>
<fieldset>
<legend>Foo</legend>
</fieldset>

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<title>fieldset and shadow DOM</title>
<link rel=fieldset-foo-ref.html>
<p>There should be a normal fieldset below with the legend "Foo".</p>
<template id="my-fieldset">
<fieldset><slot name="my-text"></slot></fieldset>
</template>
<my-fieldset>
<legend slot="my-text">Foo</legend>
</my-fieldset>
<script>
customElements.define('my-fieldset',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-fieldset');
const templateContent = template.content;
this.attachShadow({mode: 'open'}).appendChild(
templateContent.cloneNode(true)
);
}
}
);
</script>

View file

@ -0,0 +1,31 @@
<!doctype html>
<title>rendered legend and CSS display</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<fieldset><legend id="ref">x</legend></fieldset>
<fieldset><legend id="test">x</legend></fieldset>
<script>
const refElm = document.querySelector('#ref');
const refStyle = getComputedStyle(refElm);
const testElm = document.querySelector('#test');
const values = ['block', 'table', 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-cell',
'table-column-group', 'table-column', 'table-caption', 'list-item', 'flow', 'flow-root','run-in','inline',
'inline-block', 'inline-table', 'ruby', 'ruby-base', 'ruby-text', 'ruby-base-container', 'ruby-text-container',
'grid', 'inline-grid', 'flex', 'inline-flex'];
for (const val of values) {
test(() => {
testElm.style.removeProperty('display');
testElm.style.display = val;
const computed = getComputedStyle(testElm);
// Note that computed value is different from the used value.
// E.g., if ruby is not supported, the following assertion will
// fail as the computed value of display will be block.
// If ruby is supported, computed.display will return "ruby",
// but the used value is supposed to be "block".
assert_equals(computed.display, val, `display: ${val} is not supported`);
assert_equals(computed.width, refStyle.width, 'width');
assert_equals(testElm.offsetLeft, refElm.offsetLeft, 'offsetLeft');
}, `rendered legend with display: ${val}`);
}
</script>

View file

@ -0,0 +1,88 @@
<!doctype html>
<title>legend and float and position: absolute/fixed</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
body { margin: 0; }
fieldset { margin: 0; padding: 20px; border: 10px solid; width: 300px; }
legend { height: 10px; }
#legend1 { float: left; }
#legend2 { float: right; }
#legend3 { position: absolute; }
#legend4 { position: fixed; }
</style>
<fieldset id=fieldset>
<div>div</div>
<legend id=legend1>legend1</legend>
<legend id=legend2>legend2</legend>
<legend id=legend3>legend3</legend>
<legend id=legend4>legend4</legend>
<legend id=legend5>legend5</legend>
</fieldset>
<script>
const fieldset = document.getElementById('fieldset');
const legends = document.getElementsByTagName('legend');
const [legend1, legend2, legend3, legend4, legend5] = legends;
const expectedTop = 0;
const expectedLeft = 10 + 20;
function assert_rendered_legend(legend) {
assert_equals(legend.offsetTop, expectedTop, `${legend.id}.offsetTop`);
assert_equals(legend.offsetLeft, expectedLeft, `${legend.id}.offsetLeft`);
for (const other of legends) {
if (other === legend) {
continue;
}
if (other.offsetTop === expectedTop && other.offsetLeft === expectedLeft) {
assert_unreached(`${other.id} should not be the "rendered legend"`);
}
}
}
test(t => {
assert_rendered_legend(legend5);
}, 'no dynamic changes');
test(t => {
const legend = document.createElement('legend');
t.add_cleanup(() => {
legend.remove();
});
legend.id = 'script-inserted';
legend.textContent = 'script-inserted legend';
fieldset.insertBefore(legend, legend1);
assert_rendered_legend(legend);
legend.remove();
assert_rendered_legend(legend5);
}, 'inserting a new legend and removing it again');
test(t => {
t.add_cleanup(() => {
legend1.id = 'legend1';
legend2.id = 'legend2';
});
legend2.id = '';
assert_rendered_legend(legend2);
legend1.id = '';
assert_rendered_legend(legend1);
legend1.id = 'legend1';
assert_rendered_legend(legend2);
legend2.id = 'legend2';
assert_rendered_legend(legend5);
}, 'dynamic changes to float');
test(t => {
t.add_cleanup(() => {
legend3.id = 'legend3';
legend4.id = 'legend4';
});
legend4.id = '';
assert_rendered_legend(legend4);
legend3.id = '';
assert_rendered_legend(legend3);
legend3.id = 'legend3';
assert_rendered_legend(legend4);
legend4.id = 'legend4';
assert_rendered_legend(legend5);
}, 'dynamic changes to position');
</script>

View file

@ -0,0 +1,31 @@
<!doctype html>
<title>legend and flexbox, grid & multicol</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
legend { width: 200px; background: silver }
#flex { display: flex; }
#inline-flex { display: inline-flex; }
#grid { display: grid; }
#inline-grid { display: inline-grid; }
#grid, #inline-grid { grid-template-columns: auto auto }
#multicol { columns: 2; }
</style>
<fieldset><legend id=ref>12</legend></fieldset>
<fieldset><legend id=flex><div>1</div><div>2</div></legend></fieldset>
<fieldset><legend id=inline-flex><div>1</div><div>2</div></legend></fieldset>
<fieldset><legend id=grid><div>1</div><div>2</div></legend></fieldset>
<fieldset><legend id=inline-grid><div>1</div><div>2</div></legend></fieldset>
<fieldset><legend id=multicol><div>1</div><div>2</div></legend></fieldset>
<script>
const ref = document.getElementById('ref');
for (const id of ["flex", "inline-flex", "grid", "inline-grid", "multicol"]) {
test(() => {
const elm = document.getElementById(id);
assert_equals(elm.offsetHeight, ref.offsetHeight, 'offsetHeight');
if (id !== "multicol") {
assert_equals(getComputedStyle(elm).display, id, 'display');
}
}, id);
}
</script>

View file

@ -0,0 +1,97 @@
document.domain = "{{host}}";
// In many cases in this test, we want to delay execution of a piece of code so
// that the entry settings object would be the top-level page. A microtask is
// perfect for this purpose as it is executed in the "clean up after running
// script" algorithm, which is generally called right after the callback.
function setEntryToTopLevel(cb) {
Promise.resolve().then(cb);
}
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
iframe.onload = t.step_func_done(() => {
// Since this is called as an event handler on an element of this window,
// the entry settings object is that of this browsing context.
assert_throws("InvalidStateError", () => {
iframe.contentDocument.open();
}, "opening an XML document should throw an InvalidStateError");
});
const frameURL = new URL("resources/bailout-order-xml-with-domain-frame.sub.xhtml", document.URL);
frameURL.port = "{{ports[http][1]}}";
iframe.src = frameURL.href;
}, "document.open should throw an InvalidStateError with XML document even if it is cross-origin");
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
window.onCustomElementReady = t.step_func(() => {
window.onCustomElementReady = t.unreached_func("onCustomElementReady called again");
// Here, the entry settings object is still the iframe's, as the function
// is called from a custom element constructor in the iframe document.
// Delay execution in such a way that makes the entry settings object the
// top-level page's, but without delaying too much that the
// throw-on-dynamic-markup-insertion counter gets decremented (which is
// what this test tries to pit against the cross-origin document check).
//
// "Clean up after running script" is executed through the "construct" Web
// IDL algorithm in "create an element", called by "create an element for a
// token" in the parser.
setEntryToTopLevel(t.step_func_done(() => {
assert_throws("InvalidStateError", () => {
iframe.contentDocument.open();
}, "opening a document when the throw-on-dynamic-markup-insertion counter is incremented should throw an InvalidStateError");
}));
});
const frameURL = new URL("resources/bailout-order-custom-element-with-domain-frame.sub.html", document.URL);
frameURL.port = "{{ports[http][1]}}";
iframe.src = frameURL.href;
}, "document.open should throw an InvalidStateError when the throw-on-dynamic-markup-insertion counter is incremented even if the document is cross-origin");
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
self.testSynchronousScript = t.step_func(() => {
// Here, the entry settings object is still the iframe's, as the function
// is synchronously called from a <script> element in the iframe's
// document.
//
// "Clean up after running script" is executed when the </script> tag is
// seen by the HTML parser.
setEntryToTopLevel(t.step_func_done(() => {
assert_throws("SecurityError", () => {
iframe.contentDocument.open();
}, "opening a same origin-domain (but not same origin) document should throw a SecurityError");
}));
});
const frameURL = new URL("resources/bailout-order-synchronous-script-with-domain-frame.sub.html", document.URL);
frameURL.port = "{{ports[http][1]}}";
iframe.src = frameURL.href;
}, "document.open should throw a SecurityError with cross-origin document even when there is an active parser executing script");
for (const ev of ["beforeunload", "pagehide", "unload"]) {
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
iframe.addEventListener("load", t.step_func(() => {
iframe.contentWindow.addEventListener(ev, t.step_func(() => {
// Here, the entry settings object should be the top-level page's, as
// the callback context of this event listener is the incumbent
// settings object, which is the this page. However, due to a Chrome
// bug (https://crbug.com/606900), the entry settings object may be
// mis-set to the iframe's.
//
// "Clean up after running script" is called in the task that
// navigates.
setEntryToTopLevel(t.step_func_done(() => {
assert_throws("SecurityError", () => {
iframe.contentDocument.open();
}, "opening a same origin-domain (but not same origin) document should throw a SecurityError");
}));
}));
iframe.src = "about:blank";
}), { once: true });
iframe.src = "http://{{host}}:{{ports[http][1]}}/common/domain-setter.sub.html";
}, `document.open should throw a SecurityError with cross-origin document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`);
}

View file

@ -0,0 +1,26 @@
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
self.testSynchronousScript = t.step_func_done(() => {
assert_throws("InvalidStateError", () => {
iframe.contentDocument.open();
}, "opening an XML document should throw");
});
iframe.src = "resources/bailout-order-xml-with-synchronous-script-frame.xhtml";
}, "document.open should throw an InvalidStateError with XML document even when there is an active parser executing script");
for (const ev of ["beforeunload", "pagehide", "unload"]) {
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => { iframe.remove(); });
iframe.addEventListener("load", t.step_func(() => {
iframe.contentWindow.addEventListener(ev, t.step_func_done(() => {
assert_throws("InvalidStateError", () => {
iframe.contentDocument.open();
}, "opening an XML document should throw");
}));
iframe.src = "about:blank";
}), { once: true });
iframe.src = "/common/dummy.xhtml";
}, `document.open should throw an InvalidStateError with XML document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`);
}

View file

@ -6,11 +6,19 @@ for (const ev of ["unload", "beforeunload", "pagehide"]) {
t.add_cleanup(() => iframe.remove());
iframe.src = "/common/blank.html";
iframe.onload = t.step_func(() => {
iframe.contentWindow.addEventListener(ev, t.step_func_done(() => {
const origURL = iframe.contentDocument.URL;
assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
assertOpenHasNoSideEffects(iframe.contentDocument, origURL, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
iframe.contentWindow.addEventListener(ev, t.step_func(() => {
// Here, the entry settings object could still be the iframe's. Delay
// it in such a way that ensures the entry settings object is the
// top-level page's, but without delaying too much that the
// ignore-opens-during-unload counter becomes decremented. A microtask
// is perfect as it's executed immediately in "clean up after running
// script".
Promise.resolve().then(t.step_func_done(() => {
const origURL = iframe.contentDocument.URL;
assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
assertOpenHasNoSideEffects(iframe.contentDocument, origURL, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
}));
}));
iframe.src = "about:blank";
});

View file

@ -3,11 +3,17 @@
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => iframe.remove());
self.testSynchronousScript = t.step_func_done(() => {
const origURL = iframe.contentDocument.URL;
assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "active parser whose script nesting level is greater than 0");
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "active parser whose script nesting level is greater than 0");
self.testSynchronousScript = t.step_func(() => {
// Here, the entry settings object is still the iframe's. Delay it in such
// a way that makes the entry settings object the top-level page's, but
// without delaying too much that the parser becomes inactive. A microtask
// is perfect as it's executed in "clean up after running script".
Promise.resolve().then(t.step_func_done(() => {
const origURL = iframe.contentDocument.URL;
assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "active parser whose script nesting level is greater than 0");
assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "active parser whose script nesting level is greater than 0");
}));
});
iframe.src = "resources/bailout-order-synchronous-script-frame.html";
}, "document.open bailout should not have any side effects (active parser whose script nesting level is greater than 0)");

View file

@ -0,0 +1,29 @@
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => iframe.remove());
iframe.src = "/common/blank.html";
iframe.onload = t.step_func_done(() => {
const win = iframe.contentWindow;
const doc = iframe.contentDocument;
assert_equals(win.history.state, null);
win.history.replaceState("state", "");
assert_equals(win.history.state, "state");
assert_equals(doc.open(), doc);
assert_equals(win.history.state, "state");
});
}, "history.state is kept by document.open()");
async_test(t => {
const iframe = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => iframe.remove());
iframe.src = "/common/blank.html";
iframe.onload = t.step_func_done(() => {
const win = iframe.contentWindow;
const doc = iframe.contentDocument;
assert_equals(win.history.state, null);
win.history.replaceState("state", "");
assert_equals(win.history.state, "state");
assert_equals(doc.open("", "replace"), doc);
assert_equals(win.history.state, "state");
});
}, "history.state is kept by document.open() (with historical replace parameter set)");

View file

@ -0,0 +1,71 @@
// This test tests for the nonexistence of a reload override buffer, which is
// used in a previous version of the HTML Standard to make reloads of a
// document.open()'d document load the written-to document rather than doing an
// actual reload of the document's URL.
//
// This test has a somewhat interesting structure compared to the other tests
// in this directory. It eschews the <iframe> structure used by other tests,
// since when the child frame is reloaded it would adopt the URL of the test
// page (the responsible document of the entry settings object), and the spec
// forbids navigation in nested browsing contexts to the same URL as their
// parent. To work around that, we use window.open() which does not suffer from
// that restriction.
//
// In any case, this test as the caller of `document.open()` would be used both
// as the test file and as part of the test file. The `if (!opener)` condition
// controls what role this file plays.
if (!opener) {
async_test(t => {
const testURL = document.URL;
const dummyURL = new URL("resources/dummy.html", document.URL).href;
// 1. Open an auxiliary window.
const win = window.open("resources/dummy.html");
t.add_cleanup(() => { win.close(); });
win.addEventListener("load", t.step_func(() => {
// The timeout seems to be necessary for Firefox, which when `load` is
// called may still have an active parser.
t.step_timeout(() => {
const doc = win.document;
assert_true(doc.body.textContent.includes("Dummy"), "precondition");
assert_equals(doc.URL, dummyURL, "precondition");
window.onChildLoad = t.step_func(message => {
// 3. The dynamically overwritten content will trigger this function,
// which puts in place the actual test.
assert_equals(message, "Written", "script on written page is executed");
assert_true(win.document.body.textContent.includes("Content"), "page is written to");
assert_equals(win.document.URL, testURL, "postcondition: after document.write()");
assert_equals(win.document, doc, "document.open should not change the document object");
window.onChildLoad = t.step_func_done(message => {
// 6. This function should be called from the if (opener) branch of
// this file. It would throw an assertion error if the overwritten
// content was executed instead.
assert_equals(message, "Done!", "actual test");
assert_true(win.document.body.textContent.includes("Back to the test"), "test is reloaded");
assert_equals(win.document.URL, testURL, "postcondition: after reload");
assert_not_equals(win.document, doc, "reload should change the document object");
});
// 4. Reload the pop-up window. Because of the doc.open() call, this
// pop-up window will reload to the same URL as this test itself.
win.location.reload();
});
// 2. When it is loaded, dynamically overwrite its content.
assert_equals(doc.open(), doc);
assert_equals(doc.URL, testURL, "postcondition: after document.open()");
doc.write("<p>Content</p><script>opener.onChildLoad('Written');</script>");
doc.close();
}, 100);
}), { once: true });
}, "Reloading a document.open()'d page should reload the URL of the entry realm's responsible document");
} else {
document.write("<p>Back to the test</p>");
// 5. Since this window is window.open()'d, opener refers to the test window.
// Inform the opener that reload succeeded.
opener.onChildLoad("Done!");
}

View file

@ -0,0 +1,13 @@
<p>Text</p>
<script>
document.domain = "{{host}}";
class CustomElement extends HTMLElement {
constructor() {
super();
parent.onCustomElementReady();
}
}
customElements.define("custom-element", CustomElement);
</script>
<custom-element></custom-element>

View file

@ -0,0 +1,5 @@
<p>Text</p>
<script>
document.domain = "{{host}}";
parent.testSynchronousScript();
</script>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>XHTML document with domain set</title></head>
<body>
<p>Text</p>
<script>
document.domain = "{{host}}";
</script>
</body>
</html>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>XHTML document with hook to run script from a script tag</title></head>
<body>
<p>Text</p>
<script>
parent.testSynchronousScript();
</script>
</body>
</html>

View file

@ -0,0 +1,2 @@
<!-- Like /common/blank.html, but with some content in it. -->
<p>Dummy</p>

View file

@ -21,7 +21,7 @@ function taskTest(description, testBody) {
// The empty HTML seems to be necessary to cajole Chrome and Safari into
// firing a load event asynchronously, which is necessary to make sure the
// frame's document doesn't have a parser associated with it.
// See: https://crbug.com/875354
// See: https://crbug.com/569511
frame.src = "/common/blank.html";
t.add_cleanup(() => frame.remove());
frame.onload = t.step_func(() => {
@ -39,7 +39,7 @@ function taskTest(description, testBody) {
// The empty HTML seems to be necessary to cajole Chrome into firing a load
// event, which is necessary to make sure the frame's document doesn't have
// a parser associated with it.
// See: https://crbug.com/875354
// See: https://crbug.com/569511
frame.src = "/common/blank.html";
t.add_cleanup(() => frame.remove());
frame.onload = t.step_func(() => {

View file

@ -0,0 +1,87 @@
test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
assert_equals(frame.contentDocument.URL, "about:blank");
assert_equals(frame.contentWindow.location.href, "about:blank");
frame.contentDocument.open();
assert_equals(frame.contentDocument.URL, document.URL);
assert_equals(frame.contentWindow.location.href, document.URL);
}, "document.open() changes document's URL (fully active document)");
async_test(t => {
const blankURL = new URL("/common/blank.html", document.URL).href;
const frameURL = new URL("resources/page-with-frame.html", document.URL).href;
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
frame.onload = t.step_func(() => {
assert_equals(frame.contentDocument.URL, frameURL);
assert_equals(frame.contentWindow.location.href, frameURL);
const childFrame = frame.contentDocument.querySelector("iframe");
const childDoc = childFrame.contentDocument;
const childWin = childFrame.contentWindow;
assert_equals(childDoc.URL, blankURL);
assert_equals(childWin.location.href, blankURL);
// Right now childDoc is still fully active.
frame.onload = t.step_func_done(() => {
// Now childDoc is still active but no longer fully active.
childDoc.open();
assert_equals(childDoc.URL, blankURL);
assert_equals(childWin.location.href, blankURL);
});
frame.src = "/common/blank.html";
});
frame.src = frameURL;
}, "document.open() does not change document's URL (active but not fully active document)");
test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
const doc = frame.contentDocument;
// Right now the frame is connected and it has an active document.
assert_equals(doc.URL, "about:blank");
frame.remove();
// Now the frame is no longer connected. Its document is no longer active.
assert_equals(doc.URL, "about:blank");
assert_equals(doc.open(), doc);
assert_equals(doc.URL, "about:blank");
}, "document.open() does not change document's URL (non-active document with an associated Window object; frame is removed)");
async_test(t => {
const frame = document.createElement("iframe");
t.add_cleanup(() => frame.remove());
frame.onload = t.step_func(() => {
const doc = frame.contentDocument;
// Right now the frame is connected and it has an active document.
assert_equals(doc.URL, "about:blank");
frame.onload = t.step_func_done(() => {
// Now even though the frame is still connected, its document is no
// longer active.
assert_not_equals(frame.contentDocument, doc);
assert_equals(doc.URL, "about:blank");
assert_equals(doc.open(), doc);
assert_equals(doc.URL, "about:blank");
});
frame.src = "/common/blank.html";
});
// We need to connect the frame after the load event is set up to mitigate
// against https://crbug.com/569511.
document.body.appendChild(frame);
}, "document.open() does not change document's URL (non-active document with an associated Window object; navigated away)");
test(t => {
const frame = document.body.appendChild(document.createElement("iframe"));
t.add_cleanup(() => frame.remove());
const doc = frame.contentDocument.implementation.createHTMLDocument();
assert_equals(doc.URL, "about:blank");
assert_equals(doc.open(), doc);
assert_equals(doc.URL, "about:blank");
}, "document.open() does not change document's URL (non-active document without an associated Window object)");

View file

@ -57,6 +57,7 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.ani
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.cur
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.ico
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wasm
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.bmp
## Documentation ##

View file

@ -0,0 +1,13 @@
<title>text decoration doesn't propagate into tables quirks mode ref</title>
<style>
.inline-table { display: inline-table }
.inline, .inline * { display: inline }
.table { display: table }
.tbody { display: table-row-group }
.tr { display: table-row }
.td { display: table-cell }
</style>
<div><table><tr><td>this should not be underlined</table></div>
<div><table class=inline-table><tr><td>this should not be underlined</table></div>
<div><table class=inline><tr><td>this should not be underlined</table></div>
<div><span class=table><span class=tbody><span class=tr><span class=td><u>this should be underlined</u></span></span></span></span></div>

View file

@ -0,0 +1,14 @@
<title>text decoration doesn't propagate into tables quirk</title>
<link rel=match href=quirks-ref.html>
<style>
.inline-table { display: inline-table }
.inline, .inline * { display: inline }
.table { display: table }
.tbody { display: table-row-group }
.tr { display: table-row }
.td { display: table-cell }
</style>
<div><u><table><tr><td>this should not be underlined</table></u></div>
<div><u><table class=inline-table><tr><td>this should not be underlined</table></u></div>
<div><u><table class=inline><tr><td>this should not be underlined</table></u></div>
<div><u><span class=table><span class=tbody><span class=tr><span class=td>this should be underlined</span></span></span></span></u></div>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>text decoration doesn't propagate into tables standards mode ref</title>
<style>
.inline-table { display: inline-table }
.inline, .inline * { display: inline }
.table { display: table }
.tbody { display: table-row-group }
.tr { display: table-row }
.td { display: table-cell }
</style>
<div><table><tr><td><u>this should be underlined</u></table></div>
<div><table class=inline-table><tr><td>this should not be underlined</table></div>
<div><table class=inline><tr><td><u>this should be underlined</u></table></div>
<div><span class=table><span class=tbody><span class=tr><span class=td><u>this should be underlined</u></span></span></span></span></div>

View file

@ -0,0 +1,15 @@
<!doctype html>
<title>text decoration doesn't propagate into tables standards mode</title>
<link rel=match href=standards-ref.html>
<style>
.inline-table { display: inline-table }
.inline, .inline * { display: inline }
.table { display: table }
.tbody { display: table-row-group }
.tr { display: table-row }
.td { display: table-cell }
</style>
<div><u><table><tr><td>this should be underlined</table></u></div>
<div><u><table class=inline-table><tr><td>this should not be underlined</table></u></div>
<div><u><table class=inline><tr><td>this should be underlined</table></u></div>
<div><u><span class=table><span class=tbody><span class=tr><span class=td>this should be underlined</span></span></span></span></u></div>

View file

@ -352,12 +352,13 @@ class MockRuntime {
let dataProviderBinding = new mojo.Binding(
device.mojom.XRFrameDataProvider, this, dataProviderRequest);
let enviromentProviderPtr =
new device.mojom.XREnviromentIntegrationProviderPtr();
let enviromentProviderRequest = mojo.makeRequest(enviromentProviderPtr);
let enviromentProviderBinding = new mojo.Binding(
device.mojom.XREnviromentIntegrationProvider, this,
enviromentProviderRequest);
let environmentProviderPtr =
new device.mojom.XREnvironmentIntegrationProviderPtr();
let environmentProviderRequest =
mojo.makeRequest(environmentProviderPtr);
let environmentProviderBinding = new mojo.Binding(
device.mojom.XREnvironmentIntegrationProvider, this,
environmentProviderRequest);
let clientRequest = mojo.makeRequest(this.sessionClient_);
@ -365,7 +366,7 @@ class MockRuntime {
session: {
submitFrameSink: submit_frame_sink,
dataProvider: dataProviderPtr,
enviromentProvider: enviromentProviderPtr,
environmentProvider: environmentProviderPtr,
clientRequest: clientRequest,
displayInfo: this.displayInfo_
}

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Service Worker: isSecureContext</title>
</head>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helpers.sub.js"></script>
<script>
'use strict';
promise_test(async (t) => {
var url = 'isSecureContext.serviceworker.js';
var scope = 'empty.html';
var frame_sw, sw_registration;
await service_worker_unregister(t, scope);
var f = await with_iframe(scope);
t.add_cleanup(function() {
f.remove();
});
frame_sw = f.contentWindow.navigator.serviceWorker;
var registration = await navigator.serviceWorker.register(url, {scope: scope});
sw_registration = registration;
await wait_for_state(t, registration.installing, 'activated');
fetch_tests_from_worker(sw_registration.active);
}, 'Setting up tests');
</script>
</body>
</html>

View file

@ -0,0 +1,5 @@
importScripts("/resources/testharness.js");
test(() => {
assert_true(self.isSecureContext, true);
}, "isSecureContext");

View file

@ -36,6 +36,15 @@ function registration_tests_script_url(register_method, check_error_types) {
'URL-encoded backslash in the script URL should be rejected.');
}, 'Script URL including uppercase URL-encoded backslash');
promise_test(function(t) {
var script = 'data:application/javascript,';
var scope = 'resources/scope/data-url-in-script-url';
return promise_rejects(t,
check_error_types ? new TypeError : null,
register_method(script, {scope: scope}),
'Data URLs should not be registered as service workers.');
}, 'Script URL is a data URL');
promise_test(function(t) {
var script = 'resources/././empty-worker.js';
var scope = 'resources/scope/parent-reference-in-script-url';

View file

@ -0,0 +1,18 @@
import time
def main(request, response):
# no-cache itself to ensure the user agent finds a new version for each update.
headers = [('Cache-Control', 'no-cache, must-revalidate'),
('Pragma', 'no-cache')]
content_type = 'application/javascript'
headers.append(('Content-Type', content_type))
body = '''
let promise = self.registration.update()
onmessage = (evt) => {
promise.then(r => {
evt.source.postMessage(self.registration === r ? 'PASS' : 'FAIL');
});
};'''
return headers, '/* %s %s */ %s' % (time.time(), time.clock(), body)

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>Service Worker: Registration update()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
'use strict';
function wait_for_message() {
return new Promise(resolve => {
navigator.serviceWorker.addEventListener("message",
e => {
resolve(e.data);
}, { once: true });
});
}
promise_test(async t => {
const script = './resources/update-top-level-worker.py';
const scope = './resources/empty.html?update-result';
let reg = await navigator.serviceWorker.register(script, { scope });
t.add_cleanup(async _ => await reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
reg.addEventListener("updatefound",
() => assert_unreached("shouldn't find an update"));
reg.active.postMessage("ping");
assert_equals(await wait_for_message(), 'PASS', 'did not hang');
}, 'A serviceworker with a top-level update should not hang');
</script>

View file

@ -492,9 +492,10 @@ def start_servers(host, ports, paths, routes, bind_address, config, **kwargs):
for scheme, ports in ports.items():
assert len(ports) == {"http":2}.get(scheme, 1)
# TODO Not very ideal, look into removing it in the future
# Check that python 2.7.15 is being used for HTTP/2.0
# If trying to start HTTP/2.0 server, check compatibility
if scheme == 'http2' and not http2_compatible():
logger.error('Cannot start HTTP/2.0 server as the environment is not compatible. ' +
'Requires Python 2.7.10+ (< 3.0) and OpenSSL 1.0.2+')
continue
for port in ports:

View file

@ -4,7 +4,7 @@ import pytest
from six.moves.urllib.error import HTTPError
wptserve = pytest.importorskip("wptserve")
from .base import TestUsingServer
from .base import TestUsingServer, TestUsingH2Server
class TestFileHandler(TestUsingServer):
@ -40,5 +40,51 @@ class TestRequestHandler(TestUsingServer):
self.assertEqual(cm.exception.code, 500)
class TestFileHandlerH2(TestUsingH2Server):
def test_not_handled(self):
self.conn.request("GET", "/not_existing")
resp = self.conn.get_response()
assert resp.status == 404
class TestRewriterH2(TestUsingH2Server):
def test_rewrite(self):
@wptserve.handlers.handler
def handler(request, response):
return request.request_path
route = ("GET", "/test/rewritten", handler)
self.server.rewriter.register("GET", "/test/original", route[1])
self.server.router.register(*route)
self.conn.request("GET", "/test/original")
resp = self.conn.get_response()
assert resp.status == 200
assert resp.read() == b"/test/rewritten"
class TestRequestHandlerH2(TestUsingH2Server):
def test_exception(self):
@wptserve.handlers.handler
def handler(request, response):
raise Exception
route = ("GET", "/test/raises", handler)
self.server.router.register(*route)
self.conn.request("GET", "/test/raises")
resp = self.conn.get_response()
assert resp.status == 500
def test_frame_handler_exception(self):
class handler_cls:
def frame_handler(self, request):
raise Exception
route = ("GET", "/test/raises", handler_cls())
self.server.router.register(*route)
self.conn.request("GET", "/test/raises")
resp = self.conn.get_response()
assert resp.status == 500
if __name__ == "__main__":
unittest.main()

View file

@ -354,6 +354,10 @@ class Http2WebTestRequestHandler(BaseWebTestRequestHandler):
try:
while not self.close_connection:
data = self.request.recv(window_size)
if data == '':
self.logger.debug('(%s) Socket Closed' % self.uid)
self.close_connection = True
continue
with self.conn as connection:
frames = connection.receive_data(data)

View file

@ -57,6 +57,18 @@
order: undefined,
found: false
},
{
name: "measure_no_start_end",
startMark: undefined,
endMark: "mark_end",
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
},
// intentional duplicate of the first measure, used to confirm names can be re-used
{
name: "measure_no_start_no_end",
startMark: undefined,
@ -69,6 +81,8 @@
found: false
}
];
// the index of the duplicate "measure_no_start_no_end"
const duplicate_index = TEST_MEASURES.map(m=>m.name).lastIndexOf('measure_no_start_no_end');
setup({explicit_done: true});
@ -150,9 +164,26 @@
scenario.startTime = startMarkValue;
// when endMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the startMark
// provided is used for the endMark
scenario.duration = endMarkValue - startMarkValue;
}
else if (scenario.startMark == undefined && scenario.endMark != undefined)
{
// endMark is defined but startMark is undefined, provide both parameters
window.performance.measure(scenario.name, scenario.startMark, scenario.endMark);
// when startMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding
// to the navigationStart attribute with a timebase of the same attribute is used; this is
// equivalent to 0
scenario.startTime = 0;
// when endMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the endMark
scenario.duration = endMarkValue;
} else
{
test_true(false, 'Test measure scenario unhandled');
}
}
// test that expected measures are returned by getEntriesByName
@ -162,13 +193,13 @@
// for all test measures, the test will be validate the test measure against the first entry returned
// by getEntriesByName(), except for the last measure, where since it is a duplicate measure, the test
// will validate it against the second entry returned by getEntriesByName()
test_measure(entries[(i == 3 ? 1 : 0)],
test_measure(entries[(i == duplicate_index ? 1 : 0)],
"window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\")[" +
(i == 3 ? 1 : 0) + "]",
(i == duplicate_index ? 1 : 0) + "]",
TEST_MEASURES[i].name,
TEST_MEASURES[i].startTime,
TEST_MEASURES[i].duration);
TEST_MEASURES[i].entryMatch = entries[(i == 3 ? 1 : 0)];
TEST_MEASURES[i].entryMatch = entries[(i == duplicate_index ? 1 : 0)];
}
// test that expected measures are returned by getEntriesByName with the entryType parameter provided
@ -176,9 +207,9 @@
{
entries = window.performance.getEntriesByName(TEST_MEASURES[i].name, "measure");
test_true(match_entries(entries[(i == 3 ? 1 : 0)], TEST_MEASURES[i].entryMatch),
test_true(match_entries(entries[(i == duplicate_index ? 1 : 0)], TEST_MEASURES[i].entryMatch),
"window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\", \"measure\")[" +
(i == 3 ? 1 : 0) + "] returns an object containing the \"" + TEST_MEASURES[i].name +
(i == duplicate_index ? 1 : 0) + "] returns an object containing the \"" + TEST_MEASURES[i].name +
"\" measure in the correct order, and its value matches the \"" + TEST_MEASURES[i].name +
"\" measure returned by window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name +
"\")");
@ -260,7 +291,7 @@
measureEntryListCommand + " returns an object containing the \"" +
measureScenarios[i].name + "\" measure, and it's value matches the measure " +
"returned by window.performance.getEntriesByName(\"" + measureScenarios[i].name +
"\")[" + (i == 3 ? 1 : 0) + "].");
"\")[" + (i == duplicate_index ? 1 : 0) + "].");
measureEntryList[j].found = true;
measureScenarios[i].found = true;
@ -318,6 +349,7 @@
provided</li>
<li>"measure_start_no_end": created using a measure() call with only the startMark provided</li>
<li>"measure_start_end": created using a measure() call with both a startMark or endMark provided</li>
<li>"measure_no_start_end": created using a measure() call with only the endMark provided</li>
<li>"measure_no_start_no_end": duplicate of the first measure, used to confirm names can be re-used</li>
</ul>
After creating each measure, the existence of these measures is validated by calling

View file

@ -9,6 +9,12 @@
// These tests are based on the following extension specification:
// https://w3c.github.io/webrtc-ice/
function makeIceTransport(t) {
const iceTransport = new RTCIceTransport();
t.add_cleanup(() => iceTransport.stop());
return iceTransport;
}
test(() => {
const iceTransport = new RTCIceTransport();
}, 'RTCIceTransport constructor does not throw.');
@ -25,10 +31,98 @@ test(() => {
'Expect no remote candidates');
assert_equals(iceTransport.getSelectedCandidatePair(), null,
'Expect no selected candidate pair');
assert_equals(iceTransport.getLocalParameters(), null,
'Expect no local parameters');
assert_not_equals(iceTransport.getLocalParameters(), null,
'Expect local parameters generated');
assert_equals(iceTransport.getRemoteParameters(), null,
'Expect no remote parameters');
}, 'RTCIceTransport initial properties are set.');
test(t => {
const iceTransport = makeIceTransport(t);
assert_throws(new TypeError(), () =>
iceTransport.gather({ iceServers: null }));
}, 'gather() with { iceServers: null } should throw TypeError');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: undefined });
}, 'gather() with { iceServers: undefined } should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: [{
urls: ['turns:turn.example.org', 'turn:turn.example.net'],
username: 'user',
credential: 'cred',
}] });
}, 'gather() with one turns server, one turn server, username, credential' +
' should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: [{
urls: ['stun:stun1.example.net', 'stun:stun2.example.net'],
}] });
}, 'gather() with 2 stun servers should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.stop();
assert_throws('InvalidStateError', () => iceTransport.gather({}));
}, 'gather() throws if closed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({});
assert_equals(iceTransport.gatheringState, 'gathering');
}, `gather() transitions gatheringState to 'gathering'`);
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({});
assert_throws('InvalidStateError', () => iceTransport.gather({}));
}, 'gather() throws if called twice');
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'gatheringstatechange');
iceTransport.gather({});
await watcher.wait_for('gatheringstatechange');
assert_equals(iceTransport.gatheringState, 'complete');
}, `eventually transition gatheringState to 'complete'`);
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport,
[ 'icecandidate', 'gatheringstatechange' ]);
iceTransport.gather({});
let candidate;
do {
({ candidate } = await watcher.wait_for('icecandidate'));
} while (candidate !== null);
assert_equals(iceTransport.gatheringState, 'gathering');
await watcher.wait_for('gatheringstatechange');
assert_equals(iceTransport.gatheringState, 'complete');
}, 'onicecandidate fires with null candidate before gatheringState' +
` transitions to 'complete'`);
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'icecandidate');
iceTransport.gather({});
const { candidate } = await watcher.wait_for('icecandidate');
assert_not_equals(candidate.candidate, '');
assert_array_equals(iceTransport.getLocalCandidates(), [candidate]);
}, 'gather() returns at least one host candidate');
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'icecandidate');
iceTransport.gather({ gatherPolicy: 'relay' });
const { candidate } = await watcher.wait_for('icecandidate');
assert_equals(candidate, null);
assert_array_equals(iceTransport.getLocalCandidates(), []);
}, `gather() returns no candidates with { gatherPolicy: 'relay'} and no turn` +
' servers');
</script>