Update web-platform-tests to revision 6340a70e8df5e850ea44436b54105f59dd5aa22e

This commit is contained in:
WPT Sync Bot 2019-07-19 10:25:00 +00:00
parent 5788e8c050
commit 7be3e2f06b
131 changed files with 3893 additions and 1852 deletions

View file

@ -89,7 +89,7 @@
effect.localTime = this.test_local_time++;
}
state() {
return new Error('foo');
return new Symbol('foo');
}
});
</script>

View file

@ -0,0 +1,106 @@
<!doctype html>
<meta name="timeout" content="long">
<title>Accept-CH-Lifetime test</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/accept-ch-lifetime-test.js"></script>
<script>
setup({ explicit_done: true });
// Cross-origin header tests
run_test({ name: "cross origin iframe not setting other origins",
initial_url: echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept,
expect_url: do_not_expect,
type: "iframe" });
run_test({ name: "cross origin iframe not setting own origin",
initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect,
type: "iframe" });
run_test({ name: "cross origin navigation",
initial_url: echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + expect,
type: "navigation" });
run_test({ name: "cross origin subresource",
initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect,
type: "subresource" });
// Same origin header tests
run_test({ name: "same origin iframe",
initial_url: echo,
accept_url: accept,
expect_url: expect,
type: "iframe" });
run_test({ name: "same origin navigation",
initial_url: echo,
accept_url: accept,
expect_url: expect,
type: "navigation" });
run_test({ name: "same origin subresource",
initial_url: echo,
accept_url: accept,
expect_url: do_not_expect,
type: "subresource" });
// Cross-origin http-equiv tests
run_test({ name: "http-equiv cross origin iframe not setting other origins",
initial_url: echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept,
expect_url: do_not_expect,
type: "iframe" });
run_test({ name: "http-equiv cross origin iframe not setting own origin",
initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect,
type: "iframe" });
run_test({ name: "http-equiv cross origin navigation",
initial_url: echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + expect,
type: "navigation" });
run_test({ name: "http-equiv cross origin subresource",
initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo,
accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept,
expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect,
type: "subresource" });
// same-origin http-equiv tests
run_test({ name: "http-equiv same origin iframe",
initial_url: echo,
accept_url: httpequiv_accept,
expect_url: expect,
type: "iframe" });
run_test({ name: "http-equiv same origin navigation",
initial_url: echo,
accept_url: httpequiv_accept,
expect_url: expect,
type: "navigation" });
run_test({ name: "http-equiv same origin subresource",
initial_url: echo,
accept_url: httpequiv_accept,
expect_url: do_not_expect,
type: "subresource" });
done();
</script>
</body>
</html>

View file

@ -1,67 +0,0 @@
<html>
<title>Accept-CH-Lifetime test</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens two more html web page. One test is run
in this web page, and two in the other web pages.
-->
<script>
// This test fetches resources/accept_ch_lifetime.html. The response headers to
// that webpage contain Accept-CH and Accept-CH-Lifetime headers.
// Fetching that webpage should cause the user-agent to persist origin
// preferences for the client hints specified in Accept-CH header for a
// duration specified in the Accept-CH-Lifetime header.
// Next, to verify if the origin preferences were persisted by the user
// agent, this test fetches resources/expect_client_hints_headers.html
// in a new window. Fetching of resources/expect_client_hints_headers.html
// verifies that the user agent actually sends the client hints in the request
// headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/expect_client_hints_headers.html did not finish.");
function acceptChLifetimeLoaded() {
// Open a new window. Verify that the user agent attaches the client hints.
var verify_win = window.open("expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
}
// Fetching this webpage should cause user-agent to persist client hint
// preferences for the origin.
var win = window.open("resources/accept_ch_lifetime.html");
assert_not_equals(win, null, "Popup windows not allowed?");
win.addEventListener('load', acceptChLifetimeLoaded, false);
</script>
</body>
</html>

View file

@ -1,68 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with cross-origin iframe</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/accept_ch_lifetime.html in a cross origin iframe.
// The response headers to that webpage contain Accept-CH and Accept-CH-Lifetime
// headers.
// Fetching that webpage should NOT cause the user-agent to persist origin
// preferences for the client hints specified.
// Next, to verify if the origin preferences were NOT persisted by the user
// agent, this test fetches resources/do_not_expect_client_hints_headers.html
// in a new window. Fetching of
// resources/do_not_expect_client_hints_headers.html
// verifies that the user agent did not actually sent the client hints in the
// request headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("do_not_expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/do_not_expect_client_hints_headers.html did not finish.");
function acceptChLifetimeLoaded() {
// Open a new window. Verify that the user agent does not attach the client
// hints.
var verify_win = window.open("resources/do_not_expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
}
</script>
<!-- Fetching this webpage should NOT cause user-agent to persist client hint
preferences for the origin.-->
<iframe onload="acceptChLifetimeLoaded()" src="https://{{hosts[][www]}}:{{ports[https][0]}}/client-hints/resources/accept_ch_lifetime.html"></iframe>
</body>
</html>

View file

@ -1,69 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with same-origin iframe</title>
<meta name="timeout" content="long">
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/accept_ch_lifetime.html in a same origin iframe.
// The response headers to that webpage contain Accept-CH and Accept-CH-Lifetime
// headers.
// Fetching that webpage should cause the user-agent to persist origin
// preferences for the client hints specified in Accept-CH header for a
// duration specified in the Accept-CH-Lifetime header.
// Next, to verify if the origin preferences were persisted by the user
// agent, this test fetches resources/expect_client_hints_headers.html
// in a new window. Fetching of resources/expect_client_hints_headers.html
// verifies that the user agent actually sends the client hints in the request
// headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
var acceptChLifetimeLoaded;
async_test(t => {
acceptChLifetimeLoaded = t.step_func(() => {
// Open a new window. Verify that the user agent attaches the client hints.
var verify_win = window.open("resources/expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
});
window.addEventListener('message', t.step_func((e) => {
if(!e.source.location.pathname.includes("expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/expect_client_hints_headers.html did not finish.");
</script>
<!-- Fetching this webpage should cause user-agent to persist client hint
preferences for the origin.-->
<iframe onload="acceptChLifetimeLoaded()" src="resources/accept_ch_lifetime.html"></iframe>
</body>
</html>

View file

@ -1,72 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with subresource</title>
<meta name="timeout" content="long">
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/accept_ch_lifetime.html as a subresource. The
// response headers to that webpage contain Accept-CH and Accept-CH-Lifetime
// headers.
// Fetching that webpage as a subresource should NOT cause the user-agent to
// persist origin preferences for the client hints specified in Accept-CH
// header.
// Next, to verify if the origin preferences were not persisted by the user
// agent, this test fetches resources/do_not_expect_client_hints_headers.html
// in a new window. Fetching of
// resources/do_not_expect_client_hints_headers.html verifies that the user
// agent does not send the client hints in the request headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
promise_test(t => {
// Fetching this web page as a subresource should NOT cause user-agent to
// persist client hint preferences for the origin.
return fetch("resources/accept_ch_lifetime.html").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
// Open a new window. Verify that the user agent does not attach the client
// hints.
var win = window.open("resources/do_not_expect_client_hints_headers.html");
assert_not_equals(win, null, "Popup windows not allowed?");
});
}, "Test receiving Accept-CH-Lifetime header");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("do_not_expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/do_not_expect_client_hints_headers.html did not finish.");
</script>
</body>
</html>

View file

@ -1,66 +0,0 @@
<html>
<title>Accept-CH-Lifetime test</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens two more html web page. One test is run
in this web page, and two in the other web pages.
-->
<script>
// This test fetches resources/http_equiv_accept_ch_lifetime.html. The response
// to that webpage contains Accept-CH and Accept-CH-Lifetime http-equiv headers.
// Fetching that webpage should cause the user-agent to persist origin
// preferences for the client hints specified in Accept-CH header for a
// duration specified in the Accept-CH-Lifetime header.
// Next, to verify if the origin preferences were persisted by the user
// agent, this test fetches resources/expect_client_hints_headers.html
// in a new window. Fetching of resources/expect_client_hints_headers.html
// verifies that the user agent actually sends the client hints in the request
// headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/expect_client_hints_headers.html did not finish.");
function acceptChLifetimeLoaded() {
// Open a new window. Verify that the user agent attaches the client hints.
var verify_win = window.open("expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
}
// Fetching this webpage should cause user-agent to persist client hint
// preferences for the origin.
var win = window.open("resources/http_equiv_accept_ch_lifetime.html");
assert_not_equals(win, null, "Popup windows not allowed?");
win.addEventListener('load', acceptChLifetimeLoaded, false);
</script>
</body>
</html>

View file

@ -1,66 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with cross-origin iframe</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/http_equiv_accept_ch_lifetime.html in a cross
// origin iframe. The response to that webpage contains Accept-CH and
// Accept-CH-Lifetime http-equiv headers.
// Fetching that webpage should NOT cause the user-agent to persist origin
// preferences for the client hints specified.
// Next, to verify if the origin preferences were NOT persisted by the user
// agent, this test fetches resources/do_not_expect_client_hints_headers.html
// in a new window. Fetching of
// resources/do_not_expect_client_hints_headers.html
// verifies that the user agent did not actually sent the client hints in the
// request headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("do_not_expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/do_not_expect_client_hints_headers.html did not finish.");
function acceptChLifetimeLoaded() {
var verify_win = window.open("resources/do_not_expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
}
</script>
<!-- Fetching this webpage should NOT cause user-agent to persist client hint
preferences for the origin.-->
<iframe onload="acceptChLifetimeLoaded()" src="https://{{hosts[][www]}}:{{ports[https][0]}}/client-hints/resources/http_equiv_accept_ch_lifetime.html"></iframe>
</body>
</html>

View file

@ -1,70 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with same-origin iframe</title>
<meta name="timeout" content="long">
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/http_equiv_accept_ch_lifetime.html in a same
// origin iframe. The response to that webpage contains Accept-CH and
// Accept-CH-Lifetime http-equiv headers.
// Fetching that webpage should cause the user-agent to persist origin
// preferences for the client hints specified in Accept-CH header for a
// duration specified in the Accept-CH-Lifetime header.
// Next, to verify if the origin preferences were persisted by the user
// agent, this test fetches resources/expect_client_hints_headers.html
// in a new window. Fetching of resources/expect_client_hints_headers.html
// verifies that the user agent actually sends the client hints in the request
// headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
var acceptChLifetimeLoaded;
async_test(t => {
acceptChLifetimeLoaded = t.step_func(() => {
// Open a new window. Verify that the user agent attaches the client hints.
var verify_win = window.open("resources/expect_client_hints_headers.html");
assert_not_equals(verify_win, null, "Popup windows not allowed?");
});
window.addEventListener('message', t.step_func((e) => {
if(!e.source.location.pathname.includes("expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/expect_client_hints_headers.html did not finish.");
</script>
<!-- Fetching this webpage should cause user-agent to persist client hint
preferences for the origin.-->
<iframe onload="acceptChLifetimeLoaded()" src="resources/http_equiv_accept_ch_lifetime.html"></iframe>
</body>
</html>

View file

@ -1,75 +0,0 @@
<html>
<title>Accept-CH-Lifetime test with subresource</title>
<meta name="timeout" content="long">
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!--
Apart from this webpage, the test opens another html web page. One test is run
in this web page, and another in the second web page.
-->
<script>
// This test fetches resources/http_equiv_accept_ch_lifetime.html as a
// subresource. The response to that webpage contains Accept-CH and
// Accept-CH-Lifetime http-equiv headers.
// Fetching that webpage as a subresource should NOT cause the user-agent to
// persist origin preferences for the client hints specified in Accept-CH
// header.
// Next, to verify if the origin preferences were not persisted by the user
// agent, this test fetches resources/do_not_expect_client_hints_headers.html
// in a new window. Fetching of
// resources/do_not_expect_client_hints_headers.html verifies that the user
// agent does not send the client hints in the request headers.
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch("echo_client_hints_received.py").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
});
}, "Precondition: Test that the browser does not have client hints preferences cached");
promise_test(t => {
// Fetching this web page as a subresource should NOT cause user-agent to
// persist client hint preferences for the origin.
return fetch("resources/http_equiv_accept_ch_lifetime.html").then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers.
assert_false(r.headers.has("device-memory-received"), "device-memory-received");
// Open a new window. Verify that the user agent does not attach the client
// hints.
var win = window.open("resources/do_not_expect_client_hints_headers.html");
assert_not_equals(win, null, "Popup windows not allowed?");
});
}, "Test receiving Accept-CH-Lifetime header");
async_test(t => {
window.addEventListener('message', t.step_func(function(e) {
if(!e.source.location.pathname.includes("do_not_expect_client_hints_headers.html")) {
return;
}
if(typeof e.data != "string")
return;
assert_equals(e.data, "PASS");
t.done();
}));
}, "Loading of resources/do_not_expect_client_hints_headers.html did not finish.");
</script>
</body>
</html>

View file

@ -0,0 +1,73 @@
const echo = "/client-hints/echo_client_hints_received.py";
const accept = "/client-hints/resources/accept_ch_lifetime.html";
const httpequiv_accept = "/client-hints/resources/http_equiv_accept_ch_lifetime.html";
const expect = "/client-hints/resources/expect_client_hints_headers.html"
const do_not_expect = "/client-hints/resources/do_not_expect_client_hints_headers.html"
const host_info = get_host_info();
const run_test = test => {
// Test is marked as tentative until https://github.com/whatwg/fetch/issues/726
// is resolved.
// First, verify the initial state to make sure that the browser does not have
// client hints preferences cached from a previous run of the test.
promise_test(t => {
return fetch(test.initial_url).then(r => {
assert_equals(r.status, 200)
// Verify that the browser did not include client hints in the request
// headers when fetching echo_client_hints_received.py.
assert_false(r.headers.has("device-memory-received"),
"device-memory-received");
});
}, test.name + " precondition: Test that the browser does not have client " +
"hints preferences cached");
// Then, attempt to set Accept-CH-Lifetime for 1 second
promise_test(t => {
return new Promise(resolve => {
if (test.type == "navigation") {
const win = window.open(test.accept_url);
assert_not_equals(win, null, "Popup windows not allowed?");
addEventListener('message', t.step_func(() => {
win.close();
resolve();
}), false);
} else if (test.type == "iframe") {
const iframe = document.createElement("iframe");
iframe.addEventListener('load', t.step_func(() => {
resolve();
}), false);
iframe.src = test.accept_url;
document.body.appendChild(iframe);
} else if (test.type == "subresource") {
fetch(test.accept_url).then(r => {
assert_equals(r.status, 200, "subresource response status")
// Verify that the browser did not include client hints in the request
// headers, just because we can..
assert_false(r.headers.has("device-memory-received"),
"device-memory-received",
"subresource request had no client hints");
resolve();
});
} else {
assert_unreached("unknown test type");
}
});
}, test.name + " set Accept-CH-Lifetime");
// Finally, verify that CH are actually sent (or not) on requests
promise_test(t => {
return new Promise(resolve => {
let win;
window.addEventListener('message', t.step_func(function(e) {
win.close();
assert_equals(e.data, "PASS", "message from opened page");
fetch("/client-hints/resources/clear-site-data.html").then(resolve);
}));
// Open a new window. Verify that the user agent attaches client hints.
win = window.open(test.expect_url);
assert_not_equals(win, null, "Popup windows not allowed?");
});
}, test.name + " got client hints according to expectations.");
};

View file

@ -6,6 +6,10 @@ and Accept-CH-Lifetime header. Fetching this webpage should cause
user-agent to persist origin preferences for the client hints
specified in the Accept-CH header for a duration specified in
the Accept-CH-Lifetime header.-->
<script>
window.top.opener.postMessage('Loaded', '*');
</script>
</body>
</html>

View file

@ -1,2 +1,3 @@
Accept-CH: device-memory
Accept-CH-Lifetime: 5
Accept-CH-Lifetime: 1
Access-Control-Allow-Origin: *

View file

@ -0,0 +1 @@
Clear-Site-Data: "*"

View file

@ -2,5 +2,8 @@
<meta http-equiv="Accept-CH" content="device-memory">
<meta http-equiv="Accept-CH-Lifetime" content="5">
<body>
<script>
window.top.opener.postMessage('Loaded', '*');
</script>
</body>
</html>

View file

@ -0,0 +1,2 @@
Access-Control-Allow-Origin: *

View file

@ -12,7 +12,7 @@ function get_host_info() {
var ORIGINAL_HOST = '{{host}}';
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST);
var OTHER_HOST = '{{domains[www2]}}';
var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('not-' + ORIGINAL_HOST);
var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('{{hosts[alt][]}}');
return {
HTTP_PORT: HTTP_PORT,

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<iframe id="if" src="about:blank"></iframe>
<script>
var t = async_test("document.cookie behavior on documents without browser context");
t.add_cleanup(function() {
document.cookie = "nav_away_test=yes;max-age=0";
});
function step2() {
t.step(function() {
// Get from saved doc should fail.
assert_equals(window.iframeDoc.cookie, "");
// Try set from saved doc, should do nothing.
window.iframeDoc.cookie = "nav_away_test=second";
assert_equals(window.iframeDoc.cookie, "");
assert_not_equals(document.cookie.indexOf("nav_away_test=yes"), -1);
});
t.done();
}
t.step(function() {
document.cookie = "nav_away_test=yes";
var iframe = document.getElementById("if");
// Save original document.
window.iframeDoc = iframe.contentDocument;
assert_not_equals(window.iframeDoc.cookie.indexOf("nav_away_test=yes"), -1);
// Navigate away.
iframe.onload = step2;
iframe.contentWindow.location = "/common/blank.html";
})
</script>
</body>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>CSS Floats — reference</title>
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
p { width: 10em; border: solid aqua; }
span { float: left; width: 5em; height: 5em; border: solid blue; }
</style>
<div>Test passes if all three examples render the same:</div>
<p><span></span><br>Supercalifragilisticexpialidocious</p>
<br style="clear:both">
<p><span></span><br>Supercalifragilisticexpialidocious</p>
<br style="clear:both">
<p><span></span><br>Supercalifragilisticexpialidocious</p>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>CSS Floats — narrow containing block</title>
<meta name=assert content="If a shortened line box is too small to contain any content, then the line box is shifted downward">
<link rel=help href="https://www.w3.org/TR/CSS2/visuren.html#floats">
<link rel=match href="float-no-content-beside-001-ref.html">
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
p { width: 10em; border: solid aqua; }
span { float: left; width: 5em; height: 5em; border: solid blue; }
</style>
<div>Test passes if all three examples render the same:</div>
<p><span></span>Supercalifragilisticexpialidocious</p>
<br style="clear:both">
<p><span></span> Supercalifragilisticexpialidocious</p>
<br style="clear:both">
<p><span></span><br>Supercalifragilisticexpialidocious</p>

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Box Alignment Level 3: getComputedStyle().placeContent</title>
<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-place-content">
<meta name="assert" content="place-content computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("place-content", "normal normal", "normal");
test_computed_value("place-content", "first baseline", "baseline start");
test_computed_value("place-content", "baseline", "baseline start");
test_computed_value("place-content", "first baseline start", "baseline start");
test_computed_value("place-content", "last baseline", "last baseline start");
test_computed_value("place-content", "first baseline stretch", "baseline stretch");
test_computed_value("place-content", "last baseline flex-start");
test_computed_value("place-content", "baseline stretch");
test_computed_value("place-content", "space-between");
test_computed_value("place-content", "space-around");
test_computed_value("place-content", "space-evenly");
test_computed_value("place-content", "stretch");
test_computed_value("place-content", "center");
test_computed_value("place-content", "end");
test_computed_value("place-content", "flex-start flex-start", "flex-start");
test_computed_value("place-content", "unsafe end unsafe end", "unsafe end");
test_computed_value("place-content", "safe flex-start");
test_computed_value("place-content", "normal stretch");
test_computed_value("place-content", "baseline space-around");
test_computed_value("place-content", "space-evenly unsafe end");
test_computed_value("place-content", "center normal");
test_computed_value("place-content", "normal right");
test_computed_value("place-content", "baseline unsafe left");
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Box Alignment Level 3: getComputedStyle().placeItems</title>
<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-place-items">
<meta name="assert" content="place-items computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
<style>
#grandparent {
justify-items: legacy center;
}
#parent {
justify-items: legacy;
}
</style>
</head>
<body>
<div id="grandparent">
<div id="parent">
<div id="target"></div>
</div>
<script>
test_computed_value("place-items", "normal");
test_computed_value("place-items", "stretch stretch", "stretch");
test_computed_value("place-items", "first baseline", "baseline");
test_computed_value("place-items", "last baseline last baseline", "last baseline");
test_computed_value("place-items", "center");
test_computed_value("place-items", "end end", "end");
test_computed_value("place-items", "self-start");
test_computed_value("place-items", "flex-end");
test_computed_value("place-items", "unsafe center unsafe center", "unsafe center");
test_computed_value("place-items", "safe self-end");
test_computed_value("place-items", "stretch baseline");
test_computed_value("place-items", "last baseline center");
test_computed_value("place-items", "safe self-end normal");
test_computed_value("place-items", "normal right");
test_computed_value("place-items", "baseline unsafe left");
// When specified justify-items is legacy, computed value depends on inherited value.
test_computed_value("place-items", "flex-end legacy", "flex-end legacy center");
test_computed_value("place-items", "stretch legacy left");
test_computed_value("place-items", "first baseline right legacy", "baseline legacy right");
</script>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Box Alignment Level 3: getComputedStyle().placeSelf</title>
<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-place-self">
<meta name="assert" content="place-self computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("place-self", "auto auto", "auto");
test_computed_value("place-self", "normal");
test_computed_value("place-self", "stretch");
test_computed_value("place-self", "first baseline", "baseline");
test_computed_value("place-self", "last baseline last baseline", "last baseline");
test_computed_value("place-self", "center center", "center");
test_computed_value("place-self", "start");
test_computed_value("place-self", "self-start");
test_computed_value("place-self", "flex-end");
test_computed_value("place-self", "unsafe center");
test_computed_value("place-self", "safe self-end safe self-end", "safe self-end");
test_computed_value("place-self", "auto last baseline");
test_computed_value("place-self", "baseline flex-end");
test_computed_value("place-self", "unsafe center stretch");
test_computed_value("place-self", "normal right");
test_computed_value("place-self", "baseline unsafe left");
</script>
</body>
</html>

View file

@ -36,6 +36,8 @@ function checkPlaceShorhand(shorthand, shorthandValue, alignValue, justifyValue)
var resolvedValue = getComputedStyle(div).getPropertyValue(shorthand);
var expectedResolvedValue = (alignValue + " " + justifyValue).trim();
if (alignValue === justifyValue)
expectedResolvedValue = alignValue;
assert_equals(div.style[shorthand], specifiedValue, shorthandValue + " specified value");
// FIXME: We need https://github.com/w3c/csswg-drafts/issues/1041 to clarify which

View file

@ -0,0 +1,16 @@
<!doctype html>
<title>CSS test reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.test {
display: flex;
}
.test::before {
content: "";
display: block;
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div class="test"></div>

View file

@ -0,0 +1,37 @@
<!doctype html>
<meta charset=utf-8>
<title>Animation of pseudo-element is stopped properly in presence of dynamic DOM change that reconstructs the layout tree</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-animations/">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1564366">
<link rel="match" href="animation-pseudo-dynamic-001-ref.html">
<style>
@keyframes anim {
from { background-color: red }
to { background-color: red }
}
.test {
display: flex;
}
.test::before {
content: "";
display: block;
width: 100px;
height: 100px;
background-color: green;
}
.tweak::before {
animation: anim 2s linear infinite;
}
</style>
<div class="test tweak">foo</div>
<script>
onload = function() {
const div = document.querySelector(".test");
const pseudoStyle = getComputedStyle(div, "::before");
div.getBoundingClientRect(); // update layout
div.classList.remove("tweak");
div.innerHTML = ""; // This is necessary to trigger the bug.
}
</script>

View file

@ -0,0 +1,98 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Display: getComputedStyle().display</title>
<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#display-prop">
<link rel="help" href="https://drafts.csswg.org/css-display/#the-display-properties">
<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-containers">
<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo">
<meta name="assert" content="position and float can change display computed value.">
<meta name="assert" content="display computed value is otherwise as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
'use strict';
// https://drafts.csswg.org/css-grid-1/#grid-containers
test_computed_value("display", "grid");
test_computed_value("display", "inline-grid");
// https://drafts.csswg.org/css2/visuren.html#display-prop
test_computed_value("display", "inline");
test_computed_value("display", "block");
test_computed_value("display", "list-item");
test_computed_value("display", "inline-block");
test_computed_value("display", "table");
test_computed_value("display", "inline-table");
test_computed_value("display", "table-row-group");
test_computed_value("display", "table-header-group");
test_computed_value("display", "table-footer-group");
test_computed_value("display", "table-row");
test_computed_value("display", "table-column-group");
test_computed_value("display", "table-column");
test_computed_value("display", "table-cell");
test_computed_value("display", "table-caption");
test_computed_value("display", "none");
// https://drafts.csswg.org/css-flexbox-1/#flex-containers
test_computed_value("display", "flex");
test_computed_value("display", "inline-flex");
test_computed_value("display", "contents");
// https://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo
function test_display_affected(property, value) {
const target = document.getElementById('target');
test(() => {
target.style[property] = value;
target.style.display = 'inline-table';
assert_equals(getComputedStyle(target).display, 'table', 'inline-table -> block');
const displayValues = [
'inline',
'table-row-group',
'table-column',
'table-column-group',
'table-header-group',
'table-footer-group',
'table-row',
'table-cell',
'table-caption',
'inline-block'
];
for (let displayValue of displayValues) {
target.style.display = displayValue;
assert_equals(getComputedStyle(target).display, 'block', displayValue + ' -> block');
}
target.style.display = 'inline-flex';
assert_equals(getComputedStyle(target).display, 'flex', 'inline-flex -> flex');
target.style.display = 'inline-grid';
assert_equals(getComputedStyle(target).display, 'grid', 'inline-grid -> grid');
// Other values are not affected.
target.style.display = 'list-item';
assert_equals(getComputedStyle(target).display, 'list-item', 'list-item -> list-item');
target.style.display = 'contents';
assert_equals(getComputedStyle(target).display, 'contents', 'contents -> contents');
target.style[property] = '';
target.style.display = '';
}, property + ' ' + value + ' affects computed display');
}
test_display_affected("position", "absolute");
test_display_affected("position", "fixed");
test_display_affected("float", "left");
test_display_affected("float", "right");
</script>
</body>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<title>CSS Flexbox: min-height: auto with flex items containing percentage-sized children</title>
<link rel="author" title="Google LLC" href="https://www.google.com/" />
<link rel="help" href="https://drafts.csswg.org/css-flexbox/#min-size-auto" />
<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=981481" />
<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=984606" />
<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
<style>
.flexbox {
display: flex;
width: 100px;
flex-direction: column;
}
.item {
flex-basis: 0;
background: green;
}
.percentage {
height: 100%;
}
.fixed {
height: 100px;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div class="flexbox">
<div class="item">
<div class="percentage"></div>
<div class="fixed"></div>
</div>
</div>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: getComputedStyle().clip</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#clip-property">
<meta name="assert" content="clip computed value is as specified, with lengths made absolute.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
<style>
#target {
font-size: 40px;
}
</style>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("clip", "auto");
test_computed_value("clip", "rect(10px, 20px, -30px, 40px)");
test_computed_value("clip", "rect(10px, 20px, calc(-1em + 10px), 1em)", "rect(10px, 20px, -30px, 40px)");
test_computed_value("clip", "rect(10px, -20px, auto, auto)");
</script>
</body>
</html>

View file

@ -3,7 +3,6 @@
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: parsing clip with invalid values</title>
<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#clip-property">
<meta name="assert" content="clip supports only the grammar 'rect() | auto'.">
<script src="/resources/testharness.js"></script>
@ -15,6 +14,7 @@
test_invalid_value("clip", "none");
test_invalid_value("clip", "rect(10px, 20px, 30px)");
test_invalid_value("clip", "rect(10%, -20%, auto, auto)");
test_invalid_value("clip", "rect(10px 20px, 30px 40px)");
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: getComputedStyle().clipRule</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-rule">
<meta name="assert" content="clip-rule computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("clip-rule", "nonzero");
test_computed_value("clip-rule", "evenodd");
</script>
</body>
</html>

View file

@ -13,8 +13,8 @@
<body>
<script>
test_valid_value("clip", "auto");
test_valid_value("clip", "rect(10px, 20px, -30px, 40px)", ["rect(10px, 20px, -30px, 40px)", "rect(10px 20px -30px 40px)"]);
test_valid_value("clip", "rect(10px, -20px, auto, auto)", ["rect(10px, -20px, auto, auto)", "rect(10px -20px auto auto)"]);
test_valid_value("clip", "rect(10px, 20px, -30px, 40px)");
test_valid_value("clip", "rect(10px, -20px, auto, auto)");
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: getComputedStyle().maskType</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-mask-type">
<meta name="assert" content="mask-type computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("mask-type", "luminance");
test_computed_value("mask-type", "alpha");
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: parsing mask-type with invalid values</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-mask-type">
<meta name="assert" content="mask-type supports only the grammar 'luminance | alpha'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("mask-type", "auto");
test_invalid_value("mask-type", "luminance alpha");
test_invalid_value("mask-type", "alpha, luminance");
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking Module Level 1: parsing mask-type with valid values</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-mask-type">
<meta name="assert" content="mask-type supports the full grammar 'luminance | alpha'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("mask-type", "luminance");
test_valid_value("mask-type", "alpha");
</script>
</body>
</html>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
<meta name="assert" content="CSSUnitValue of different angle units can be added correctly.">
<style>
.ref {
width: 200px;
height: 100px;
position: absolute;
top: 100px;
left: 100px;
transform: rotate(90deg);
background-color: green;
}
</style>
<p>Test passes if there is a filled green rectangle with <strong>no red</strong>.</p>
<div class="ref"></div>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
<link rel="match" href="rotate-by-added-angle-ref.html">
<meta name="assert" content="CSSUnitValue of different angle units can be added correctly.">
<style>
.common {
width: 200px;
height: 100px;
position: absolute;
top: 100px;
left: 100px;
}
.ref {
transform: rotate(90deg);
background-color: red;
}
.test {
background-color: green;
z-index: 1;
}
</style>
<p>Test passes if there is a filled green rectangle with <strong>no red</strong>.</p>
<div class="common ref"></div>
<div class="common test"></div>
<script>
const angle = new CSSMathSum(CSS.deg(45), CSS.turn(0.125)); // 90 degrees
const transform = new CSSTransformValue([new CSSRotate(angle)]);
const target = document.querySelector('.test');
target.attributeStyleMap.set('transform', transform);
</script>

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>backdrop-filter: Correctly apply masks/clips to backdrop-filter content</title>
<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
<p>Expected: A black circle.</p>
<div></div>
<style>
div {
position: absolute;
top: 100px;
left: 50px;
width: 200px;
height: 200px;
background: black;
border-radius: 100px;
}
</style>

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>backdrop-filter: Correctly apply masks/clips to backdrop-filter content</title>
<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty">
<link rel="match" href="backdrop-filter-plus-mask-ref.html">
<p>Expected: A black circle.</p>
<div></div>
<style>
div {
position: absolute;
top: 100px;
left: 50px;
width: 200px;
height: 200px;
backdrop-filter: invert(1);
clip-path: circle(100px at center);
}
</style>

View file

@ -39,6 +39,8 @@ function drawRectWithAddPathTransform(ctx, transform) {
return window.canvas.toDataURL();
}
var emptyCanvasURL = window.canvas.toDataURL();
[
{a: 1, m11: 2},
{b: 0, m12: -1},
@ -95,10 +97,10 @@ test(() => {
[{c: 0, m21: -0}, matrix2D({m21: -0})],
[{c: -0, m21: 0}, matrix2D({m21: 0})],
[{c: -0, m21: -0}, matrix2D({m21: -0})],
[{d: Infinity, m22: Infinity}, matrix2D({})], // should be silently ignored
[{e: -Infinity, m41: -Infinity}, matrix2D({})], // should be silently ignored
[{f: NaN, m42: NaN}, matrix2D({})], // should be silently ignored
[{f: NaN, m42: NaN, is2D: true}, matrix2D({})], // should be silently ignored
[{d: Infinity, m22: Infinity}, null], // setTransform: silently ignore / addPath: silently halt
[{e: -Infinity, m41: -Infinity}, null], // setTransform: silently ignore / addPath: silently halt
[{f: NaN, m42: NaN}, null], // setTransform: silently ignore / addPath: silently halt
[{f: NaN, m42: NaN, is2D: true}, null], // setTransform: silently ignore / addPath: silently halt
[{f: 0, m42: null}, matrix2D({m42: 0})], // null is converted to 0
[{f: -0, m42: null}, matrix2D({m42: 0})], // null is converted to 0
[{a: 2}, matrix2D({m11: 2})],
@ -171,12 +173,14 @@ test(() => {
ctx.resetTransform();
ctx.setTransform(dict);
const matrix = ctx.getTransform();
checkMatrix(matrix, expected);
checkMatrix(matrix, expected || matrix2D({}));
}, `setTransform(${format_dict(dict)})`);
test(() => {
var expectedResultURL = drawRectWithSetTransform(ctx, expected);
var actualResultURL = drawRectWithAddPathTransform(ctx, expected);
var expectedResultURL = expected ?
drawRectWithSetTransform(ctx, expected) :
emptyCanvasURL;
var actualResultURL = drawRectWithAddPathTransform(ctx, dict);
assert_equals(actualResultURL, expectedResultURL);
}, `addPath(${format_dict(dict)})`);
});

View file

@ -120,7 +120,7 @@
p2: { x: 2, y: 0, z: 0, w: 1 },
p3: { x: 2, y: 0, z: 0, w: 1 },
p4: { x: 2, y: 0, z: 0, w: 1 },
bounds: { x: 0, y: 0, width: 0, height: 0 } },
bounds: { x: 2, y: 0, width: 0, height: 0 } },
'p1Top4Attributes1');
function checkDOMQuad(createQuad, exp, name) {

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<style>
div {
margin: 1px;
background: lime;
float: left;
}
.square {
width: 24px;
height: 24px;
}
.bigWide {
width: 48px;
height: 32px;
}
.bigTall {
width: 32px;
height: 48px;
}
.small {
width: 8px;
height: 8px;
}
br { clear: both; }
</style>
</head>
<body>
<!-- Note: the specified heights here are just 1/2 the widths. -->
<div class="square"></div>
<div class="square" style="height: 12px"></div>
<br>
<div class="bigWide"></div>
<div class="bigWide" style="height: 24px"></div>
<br>
<div class="bigTall"></div>
<div class="bigTall" style="height: 16px"></div>
<br>
<div class="small"></div>
<div class="small" style="height: 4px"></div>
<br>
</body>
</html>

View file

@ -0,0 +1,71 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>CSS Test: 'object-fit: contain' and 'cover' on object element whose aspect ratio dynamically changes</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="http://www.w3.org/TR/css3-images/#sizing">
<link rel="help" href="http://www.w3.org/TR/css3-images/#the-object-fit">
<link rel="match" href="object-fit-dyn-aspect-ratio-001-ref.html">
<style>
object {
margin: 1px;
float: left;
/* I'm just using 'object-position' for cosmetic reasons, so that the
painted areas are all snapped to top-left which makes reference case
more trivial. */
object-position: top left;
}
.cov { object-fit: cover; }
.con { object-fit: contain; }
.square {
width: 24px;
height: 24px;
}
.bigWide {
width: 48px;
height: 32px;
}
.bigTall {
width: 32px;
height: 48px;
}
.small {
width: 8px;
height: 8px;
}
br { clear: both; }
</style>
<script>
function go() {
for (let elem of document.getElementsByTagName("object")) {
var doc = elem.contentDocument;
/* These should all should select out a piece of the
bottom-right quadrant (the lime chunk): */
doc.documentElement.setAttribute("viewBox", "8 4 8 4");
}
}
</script>
</head>
<body onload="go()">
<object data="support/colors-16x8-parDefault.svg" class="square cov"></object>
<object data="support/colors-16x8-parDefault.svg" class="square con"></object>
<br>
<object data="support/colors-16x8-parDefault.svg" class="bigWide cov"></object>
<object data="support/colors-16x8-parDefault.svg" class="bigWide con"></object>
<br>
<object data="support/colors-16x8-parDefault.svg" class="bigTall cov"></object>
<object data="support/colors-16x8-parDefault.svg" class="bigTall con"></object>
<br>
<object data="support/colors-16x8-parDefault.svg" class="small cov"></object>
<object data="support/colors-16x8-parDefault.svg" class="small con"></object>
<br>
</body>
</html>

View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<style>
div {
margin: 1px;
background: lime;
float: left;
}
.square {
width: 24px;
height: 24px;
}
.bigWide {
width: 48px;
height: 32px;
}
.bigTall {
width: 32px;
height: 48px;
}
.small {
width: 8px;
height: 8px;
}
br { clear: both; }
</style>
</head>
<body>
<!-- Note: each inline-style specified width here is just using the final
viewBox aspect-ratio (1/2) times the element's specified height. This
is how wide the concrete object size[1] should end up, for the
testcase's "object-fit:contain" elements.
[1] https://drafts.csswg.org/css-images-3/#concrete-object-size -->
<div class="square"></div>
<div class="square" style="width: 12px"></div>
<br>
<div class="bigWide"></div>
<div class="bigWide" style="width: 16px"></div>
<br>
<div class="bigTall"></div>
<div class="bigTall" style="width: 24px"></div>
<br>
<div class="small"></div>
<div class="small" style="width: 4px"></div>
<br>
</body>
</html>

View file

@ -0,0 +1,71 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>CSS Test: 'object-fit: contain' and 'cover' on object element whose aspect ratio dynamically changes</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="http://www.w3.org/TR/css3-images/#sizing">
<link rel="help" href="http://www.w3.org/TR/css3-images/#the-object-fit">
<link rel="match" href="object-fit-dyn-aspect-ratio-002-ref.html">
<style>
object {
margin: 1px;
float: left;
/* I'm just using 'object-position' for cosmetic reasons, so that the
painted areas are all snapped to top-left which makes reference case
more trivial. */
object-position: top left;
}
.cov { object-fit: cover; }
.con { object-fit: contain; }
.square {
width: 24px;
height: 24px;
}
.bigWide {
width: 48px;
height: 32px;
}
.bigTall {
width: 32px;
height: 48px;
}
.small {
width: 8px;
height: 8px;
}
br { clear: both; }
</style>
<script>
function go() {
for (let elem of document.getElementsByTagName("object")) {
var doc = elem.contentDocument;
/* These should all should select out a piece of the
bottom-right quadrant (the lime chunk): */
doc.documentElement.setAttribute("viewBox", "4 8 4 8");
}
}
</script>
</head>
<body onload="go()">
<object data="support/colors-8x16-parDefault.svg" class="square cov"></object>
<object data="support/colors-8x16-parDefault.svg" class="square con"></object>
<br>
<object data="support/colors-8x16-parDefault.svg" class="bigWide cov"></object>
<object data="support/colors-8x16-parDefault.svg" class="bigWide con"></object>
<br>
<object data="support/colors-8x16-parDefault.svg" class="bigTall cov"></object>
<object data="support/colors-8x16-parDefault.svg" class="bigTall con"></object>
<br>
<object data="support/colors-8x16-parDefault.svg" class="small cov"></object>
<object data="support/colors-8x16-parDefault.svg" class="small con"></object>
<br>
</body>
</html>

View file

@ -1,3 +1,7 @@
# Tests for dynamic change to aspect ratio on element with 'object-fit' set
== object-fit-dyn-aspect-ratio-001.html object-fit-dyn-aspect-ratio-001-ref.html
== object-fit-dyn-aspect-ratio-002.html object-fit-dyn-aspect-ratio-002-ref.html
# Tests for 'object-fit' / 'object-position' with a PNG image
== object-fit-fill-png-001c.html object-fit-fill-png-001-ref.html
== object-fit-fill-png-001e.html object-fit-fill-png-001-ref.html

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/fetch/sec-metadata/resources/helper.js></script>
<script>
// Site
promise_test(t => {
return fetch("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py",
{
mode: "cors",
headers: { 'x-test': 'testing' }
})
.then(r => r.json())
.then(j => {
assert_header_equals(j, {
"dest": "empty",
"site": "same-site",
"user": "",
"mode": "cors",
});
});
}, "Same-site fetch with preflight");
promise_test(t => {
return fetch("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py",
{
mode: "cors",
headers: { 'x-test': 'testing' }
})
.then(r => r.json())
.then(j => {
assert_header_equals(j, {
"dest": "empty",
"site": "cross-site",
"user": "",
"mode": "cors",
});
});
}, "Cross-site fetch with preflight");
</script>

View file

@ -7,11 +7,21 @@ def main(request, response):
if "origin" in request.headers:
headers.append(("Access-Control-Allow-Origin", request.headers["origin"]))
body = ""
# If we're in a preflight, verify that `Sec-Fetch-Mode` is `cors`.
if request.method == 'OPTIONS':
if request.headers.get("sec-fetch-mode") != "cors":
return (403, "Failed"), [], body
headers.append(("Access-Control-Allow-Methods", "*"))
headers.append(("Access-Control-Allow-Headers", "*"))
else:
body = json.dumps({
"dest": request.headers.get("sec-fetch-dest", ""),
"mode": request.headers.get("sec-fetch-mode", ""),
"site": request.headers.get("sec-fetch-site", ""),
"user": request.headers.get("sec-fetch-user", ""),
})
body = json.dumps({
"dest": request.headers.get("sec-fetch-dest", ""),
"mode": request.headers.get("sec-fetch-mode", ""),
"site": request.headers.get("sec-fetch-site", ""),
"user": request.headers.get("sec-fetch-user", ""),
})
return headers, body

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-same-origin" type="text/xsl" ?>
<?xml-stylesheet href="https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-same-site" type="text/xsl" ?>
<?xml-stylesheet href="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-cross-site" type="text/xsl" ?>
<?xml-stylesheet href="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-same-origin{{GET[token]}}" type="text/xsl" ?>
<?xml-stylesheet href="https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-same-site{{GET[token]}}" type="text/xsl" ?>
<?xml-stylesheet href="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=xslt-cross-site{{GET[token]}}" type="text/xsl" ?>
<!-- postMessage parent back when the resources are loaded -->
<script xmlns="http://www.w3.org/1999/xhtml"><![CDATA[

View file

@ -4,30 +4,32 @@
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/fetch/sec-metadata/resources/helper.js></script>
<script src=/common/utils.js></script>
<script>
// Open a window with XML document which loads resources via <?xml-stylesheet/> tag
let w = window.open("resources/xslt-test.sub.xml");
let nonce = token();
let w = window.open("resources/xslt-test.sub.xml?token=" + nonce);
window.addEventListener('message', function(e) {
if (e.source != w)
return;
promise_test(t => {
let expected = {"dest":"xslt", "site":"same-origin", "user":"", "mode": "same-origin"};
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin")
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin" + nonce)
.then(response => response.text())
.then(text => assert_header_equals(text, expected));
}, "Same-Origin xslt");
promise_test(t => {
let expected = {"dest":"xslt", "site":"same-site", "user":"", "mode": "no-cors"};
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-site")
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-site" + nonce)
.then(response => response.text())
.then(text => assert_header_equals(text, expected));
}, "Same-site xslt");
promise_test(t => {
let expected = {"dest":"xslt", "site":"cross-site", "user":"", "mode": "no-cors"};
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site")
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site" + nonce)
.then(response => response.text())
.then(text => assert_header_equals(text, expected));
}, "Cross-site xslt");

View file

@ -175,11 +175,10 @@ function reportload() {
}, 'pushState must not be able to use a DOM node as data');
test(function () {
try { a.b = c; } catch(errdata) {
assert_throws( 'DATA_CLONE_ERR', function () {
history.pushState({dummy:errdata},'');
} );
history.pushState({dummy:errdata},'');
assert_equals(ReferenceError.prototype, Object.getPrototypeOf(history.state.dummy));
}
}, 'pushState must not be able to use an error object as data');
}, 'pushState must be able to use an error object as data');
test(function () {
assert_throws( 'DATA_CLONE_ERR', function () {
iframe.contentWindow.history.pushState(document,'');

View file

@ -156,11 +156,10 @@ function reportload() {
}, 'replaceState must not be able to use a DOM node as data');
test(function () {
try { a.b = c; } catch(errdata) {
assert_throws( 'DATA_CLONE_ERR', function () {
history.replaceState({dummy:errdata},'');
} );
history.replaceState({dummy:errdata},'');
assert_equals(ReferenceError.prototype, Object.getPrototypeOf(history.state.dummy));
}
}, 'replaceState must not be able to use an error object as data');
}, 'replaceState must be able to use an error object as data');
test(function () {
assert_throws( 'DATA_CLONE_ERR', function () {
iframe.contentWindow.history.replaceState(document,'');

View file

@ -509,7 +509,7 @@
});
t.step(function() {
const error = frames[0].URIError("some message");
assert_equals(Object.getPrototypeOf(error), frames[0].prototype, "Checking prototype before cloning");
assert_equals(Object.getPrototypeOf(error), frames[0].URIError.prototype, "Checking prototype before cloning");
assert_equals(error.constructor, frames[0].URIError, "Checking constructor before cloning");
assert_equals(error.name, "URIError", "Checking name before cloning");
error.foo = "bar";

View file

@ -9,7 +9,13 @@
async_test(function(t) {
var video = document.querySelector("video");
var track = document.querySelector("track");
track.onload = t.step_func(trackLoaded);
if (track.readyState != HTMLTrackElement.LOADED) {
assert_not_equals(track.readyState, HTMLTrackElement.ERROR,
"track failed to load resource.");
track.onload = t.step_func(trackLoaded);
} else {
trackLoaded();
}
var cueCount = 0;
var textTrack;

View file

@ -128,7 +128,8 @@ function t(desc, func, expect) {
if (expect == 'timeout') {
setTimeout(this.step_func_done(), 1000);
} else {
img['on' + expect] = this.step_func_done(function() {});
img['on' + expect] = this.step_func_done();
setTimeout(this.unreached_func('update the image data didn\'t run'), 1000);
}
func.call(this, img);
}, desc);

View file

@ -8,11 +8,9 @@ typedef (Int8Array or Int16Array or Int32Array or
Float32Array or Float64Array or DataView) ArrayBufferView;
typedef (ArrayBufferView or ArrayBuffer) BufferSource;
[
Exposed=(Window,Worker),
[Exposed=(Window,Worker),
Constructor(optional DOMString message = "", optional DOMString name = "Error"),
Serializable
]
Serializable]
interface DOMException { // but see below note about ECMAScript binding
readonly attribute DOMString name;
readonly attribute DOMString message;

View file

@ -82,15 +82,11 @@ interface SpeechRecognitionResultList {
interface SpeechRecognitionEvent : Event {
readonly attribute unsigned long resultIndex;
readonly attribute SpeechRecognitionResultList results;
readonly attribute any interpretation;
readonly attribute Document? emma;
};
dictionary SpeechRecognitionEventInit : EventInit {
unsigned long resultIndex = 0;
required SpeechRecognitionResultList results;
any interpretation = null;
Document? emma = null;
};
// The object representing a speech grammar

View file

@ -4,23 +4,23 @@
// Source: User Timing Level 3 (https://w3c.github.io/user-timing/)
dictionary PerformanceMarkOptions {
any detail;
DOMHighResTimeStamp startTime;
};
any detail;
DOMHighResTimeStamp startTime;
};
dictionary PerformanceMeasureOptions {
any detail;
(DOMString or DOMHighResTimeStamp) start;
DOMHighResTimeStamp duration;
(DOMString or DOMHighResTimeStamp) end;
};
dictionary PerformanceMeasureOptions {
any detail;
(DOMString or DOMHighResTimeStamp) start;
DOMHighResTimeStamp duration;
(DOMString or DOMHighResTimeStamp) end;
};
partial interface Performance {
PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions);
void clearMarks(optional DOMString markName);
PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions, optional DOMString endMark);
void clearMeasures(optional DOMString measureName);
};
partial interface Performance {
PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions = {});
void clearMarks(optional DOMString markName);
PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions = {}, optional DOMString endMark);
void clearMeasures(optional DOMString measureName);
};
[Exposed=(Window,Worker),
Constructor(DOMString markName, optional PerformanceMarkOptions markOptions)]

View file

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Largest Contentful Paint: contracted image bounded by display size.</title>
<style type="text/css">
#image_id {
width: 50px;
height: 50px;
}
</style>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
if (!window.LargestContentfulPaint) {
assert_unreached("LargestContentfulPaint is not implemented");
}
let beforeRender = performance.now();
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
assert_equals(entry.entryType, 'largest-contentful-paint');
assert_greater_than_equal(entry.renderTime, beforeRender,
'The rendering timestamp should occur after script starts running.');
assert_greater_than_equal(performance.now(), entry.renderTime,
'The rendering timestamp should occur before the entry is dispatched to the observer.');
assert_equals(entry.startTime, 0);
assert_equals(entry.duration, 0);
// black-rectangle.png is 100 x 50. It occupies 50 x 50 so size will be bounded by the displayed size.
assert_equals(entry.size, 2500);
assert_equals(entry.id, 'image_id');
const pathname = window.location.origin + '/images/black-rectangle.png';
assert_equals(entry.url, pathname);
assert_equals(entry.element, document.getElementById('image_id'));
})
);
observer.observe({type: 'largest-contentful-paint', buffered: true});
}, 'Largest Contentful Paint: |size| attribute is bounded by display size.');
</script>
<img src='/images/black-rectangle.png' id='image_id'/>
</body>

View file

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Largest Contentful Paint: expanded image bounded by intrinsic size.</title>
<style type="text/css">
#image_id {
width: 300px;
height: 300px;
}
</style>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
if (!window.LargestContentfulPaint) {
assert_unreached("LargestContentfulPaint is not implemented");
}
let beforeRender = performance.now();
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
assert_equals(entry.entryType, 'largest-contentful-paint');
assert_greater_than_equal(entry.renderTime, beforeRender,
'The rendering timestamp should occur after script starts running.');
assert_greater_than_equal(performance.now(), entry.renderTime,
'The rendering timestamp should occur before the entry is dispatched to the observer.');
assert_equals(entry.startTime, 0);
assert_equals(entry.duration, 0);
// black-rectangle.png is 100 x 50. It occupies 300 x 300 so size will be bounded by the intrinsic size.
assert_equals(entry.size, 5000);
assert_equals(entry.id, 'image_id');
const pathname = window.location.origin + '/images/black-rectangle.png';
assert_equals(entry.url, pathname);
assert_equals(entry.element, document.getElementById('image_id'));
})
);
observer.observe({type: 'largest-contentful-paint', buffered: true});
}, 'Largest Contentful Paint: |size| attribute is bounded by intrinsic size.');
</script>
<img src='/images/black-rectangle.png' id='image_id'/>
</body>

View file

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>fractions linethickness</title>
<style type="text/css">
@font-face {
font-family: TestFont;
src: url("/fonts/math/fraction-rulethickness10000.woff");
}
math {
/* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
font-family: "TestFont";
font-size: 1px;
}
</style>
</head>
<body>
<p>This test passes if you see fraction with a cyan denominator and
a blue numerator as tall as its black bar.</p>
<math>
<mfrac linethickness="0px">
<mspace width="20px" height="0px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
<math>
<mfrac linethickness="50px">
<mspace width="20px" height="50px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
<math style="font-size: 180px">
<mfrac linethickness="0.3888888888888889em">
<mspace width="20px" height="70px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
</body>
</html>

View file

@ -4,38 +4,82 @@
<meta charset="utf-8">
<title>fractions linethickness</title>
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fractions-mfrac">
<meta name="assert" content="Verifies fraction with negative, percent and named space linethickness values.">
<link rel="match" href="frac-linethickness-002-ref.html">
<meta name="assert" content="Verifies fraction with positive, negative, percent and named space linethickness values.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style type="text/css">
@font-face {
font-family: TestFont;
src: url("/fonts/math/fraction-rulethickness10000.woff");
}
math {
/* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
/* FractionRuleThickness = 10000 * 10 / 1000 = 100px; */
font-family: "TestFont";
font-size: 1px;
font-size: 10px;
}
</style>
<script>
function LineThickness(aId) {
var mfrac = document.getElementById(aId);
var numBox = mfrac.firstElementChild.getBoundingClientRect();
var denumBox = mfrac.lastElementChild.getBoundingClientRect();
return denumBox.top - numBox.bottom;
}
setup({ explicit_done: true });
window.addEventListener("load", function() {
// Delay the check to workaround WebKit's bug https://webkit.org/b/174030.
requestAnimationFrame(() => { document.fonts.ready.then(runTests); });
});
function runTests() {
var defaultRuleThickness = 100;
var epsilon = 2;
test(function() {
assert_approx_equals(LineThickness("positive"), 5.67 * 10, epsilon);
}, "Positive");
test(function() {
/* Negative values are treated as 0 */
assert_approx_equals(LineThickness("negative"), 0, epsilon);
}, "Negative");
test(function() {
assert_approx_equals(LineThickness("percent"), defaultRuleThickness * 234 / 100, epsilon);
}, "Percentage");
test(function() {
/* Namedspace values are invalid in MathML Core. */
assert_approx_equals(LineThickness("namedspace"), defaultRuleThickness, epsilon);
}, "Named space");
done();
}
</script>
</head>
<body>
<p>This test passes if you see fraction with a cyan denominator and
a blue numerator as tall as its black bar.</p>
<math>
<mfrac linethickness="-1.23em">
<mspace width="20px" height="0px" style="background: blue"></mspace>
<mfrac id="positive" linethickness="5.67em">
<mspace width="20px" height="10px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
<math>
<mfrac linethickness="500%">
<mspace width="20px" height="50px" style="background: blue"></mspace>
<mfrac id="negative" linethickness="-1.23em">
<mspace width="20px" height="10px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
<math style="font-size: 180px">
<mfrac linethickness="veryverythickmathspace">
<mspace width="20px" height="70px" style="background: blue"></mspace>
<math>
<mfrac id="percent" linethickness="234%">
<mspace width="20px" height="10px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>
<math>
<mfrac id="namedspace" linethickness="veryverythickmathspace">
<mspace width="20px" height="10px" style="background: blue"></mspace>
<mspace width="20px" height="10px" style="background: cyan"></mspace>
</mfrac>
</math>

View file

@ -39,13 +39,11 @@
assert_equals(getBox("unitEm").width, 120, "em");
assert_equals(getBox("unitEx").width, 500, "ex");
assert_equals(getBox("unitIn").width, 288, "in");
assert_equals(getBox("unitNamed").width, 700, "namedspace");
assert_equals(getBox("unitMm").width, 576, "mm");
assert_equals(getBox("unitPc").width, 96, "pc");
assert_equals(getBox("unitPercentage").width, 60, "%");
assert_equals(getBox("unitPt").width, 96, "pt");
assert_equals(getBox("unitPx").width, 123, "px");
assert_equals(getBox("unitNone").width, 150, "Unitless");
}, "Units");
test(function() {
@ -53,20 +51,17 @@
assert_equals(getBox("spaceEm").width, 120, "em");
assert_equals(getBox("spaceEx").width, 500, "ex");
assert_equals(getBox("spaceIn").width, 288, "in");
assert_equals(getBox("spaceNamed").width, 700, "namedspace");
assert_equals(getBox("spaceMm").width, 576, "mm");
assert_equals(getBox("spacePc").width, 96, "pc");
assert_equals(getBox("spacePercentage").width, 60, "%");
assert_equals(getBox("spacePt").width, 96, "pt");
assert_equals(getBox("spacePx").width, 123, "px");
assert_equals(getBox("spaceNone").width, 150, "Unitless");
}, "Trimming of space");
test(function() {
assert_approx_equals(getBox("n0").width, 0, epsilon, "n0");
assert_approx_equals(getBox("n1").width, 90, epsilon, "n1");
assert_approx_equals(getBox("n2").width, 8, epsilon, "n2");
assert_approx_equals(getBox("n3").width, 70, epsilon, "n3");
assert_approx_equals(getBox("n4").width, 650, epsilon, "n4");
assert_approx_equals(getBox("n5").width, 4320, epsilon, "n5");
assert_approx_equals(getBox("n6").width, 1, epsilon, "n6");
@ -81,7 +76,6 @@
assert_approx_equals(getBox("N0").top - topRef, -0, epsilon, "N0");
assert_approx_equals(topRef - getBox("N1").top, -90, epsilon, "N1");
assert_approx_equals(topRef - getBox("N2").top, -8, epsilon, "N2");
assert_approx_equals(topRef - getBox("N3").top, -70, epsilon, "N3");
assert_approx_equals(topRef - getBox("N4").top, -650, epsilon, "N4");
assert_approx_equals(topRef - getBox("N5").top, -4320, epsilon, "N5");
assert_approx_equals(topRef - getBox("N6").top, -1, epsilon, "N6");
@ -91,6 +85,38 @@
assert_approx_equals(topRef - getBox("N10").top, -123, epsilon, "N10");
}, "Non-positive numbers");
test(function() {
// Namedspace values are invalid in MathML Core.
["veryverythinmathspace",
"verythinmathspace",
"thinmathspace",
"mediummathspace",
"thickmathspace",
"verythickmathspace",
"veryverythickmathspace",
"negativeveryverythinmathspace",
"negativeverythinmathspace",
"negativethinmathspace",
"negativemediummathspace",
"negativethickmathspace",
"negativeverythickmathspace",
"negativeveryverythickmathspace"
].forEach(function(space) {
var mrow = document.getElementById(space);
var boxBefore = mrow.firstElementChild.getBoundingClientRect();
var boxAfter = mrow.lastElementChild.getBoundingClientRect();
assert_equals(boxAfter.left - boxBefore.right, 0, space);
});
}, "Legacy namedspaces");
test(function() {
// These values are invalid in MathML Core.
assert_equals(getBox("unitNone").width, 30, "Unitless");
assert_approx_equals(getBox("n3").width, 0, epsilon, "n3");
var topRef = getBox("ref").top;
assert_approx_equals(topRef - getBox("N3").top, 0, epsilon, "N3");
}, "Legacy numbers");
done();
}
</script>
@ -103,7 +129,6 @@
<mspace id="unitEm" width="12em"/>
<mspace id="unitEx" width="100ex"/>
<mspace id="unitIn" width="3in"/>
<mspace style="font-size: 1800px" id="unitNamed" width="veryverythickmathspace"/>
<mspace id="unitMm" width="152.4mm"/>
<mspace id="unitPc" width="6pc"/>
<mstyle mathsize="200%"><mspace id="unitPercentage" width="3em"/></mstyle>
@ -118,13 +143,11 @@
<mspace id="spaceEm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;12em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace id="spaceEx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;100ex&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace id="spaceIn" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3in&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace style="font-size: 1800px" id="spaceNamed" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;veryverythickmathspace&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace id="spaceMm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;152.4mm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace id="spacePc" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;6pc&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mstyle mathsize="200%"><mspace id="spacePercentage" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
<mspace id="spacePt" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;72pt&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mspace id="spacePx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;123px&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
<mstyle mathsize="5"><mspace id="spaceNone" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
</math>
</p>
<p>
@ -158,5 +181,81 @@
<mpadded voffset="-012.345em"><mspace id="N10"/></mpadded>
</math>
</p>
<p>
<math>
<mrow id="veryverythinmathspace">
<mspace width="1em"/>
<mspace width="veryverythinmathspace"/>
<mspace/>
</mrow>
<mrow id="verythinmathspace">
<mspace width="1em"/>
<mspace width="verythinmathspace"/>
<mspace/>
</mrow>
<mrow id="thinmathspace">
<mspace width="1em"/>
<mspace width="thinmathspace"/>
<mspace/>
</mrow>
<mrow id="mediummathspace">
<mspace width="1em"/>
<mspace width="mediummathspace"/>
<mspace/>
</mrow>
<mrow id="thickmathspace">
<mspace width="1em"/>
<mspace width="thickmathspace"/>
<mspace/>
</mrow>
<mrow id="verythickmathspace">
<mspace width="1em"/>
<mspace width="verythickmathspace"/>
<mspace/>
</mrow>
<mrow id="veryverythickmathspace">
<mspace width="1em"/>
<mspace width="veryverythickmathspace"/>
<mspace/>
</mrow>
</math>
<math>
<mrow id="negativeveryverythinmathspace">
<mspace width="1em"/>
<mspace width="veryverythinmathspace"/>
<mspace/>
</mrow>
<mrow id="negativeverythinmathspace">
<mspace width="1em"/>
<mspace width="verythinmathspace"/>
<mspace/>
</mrow>
<mrow id="negativethinmathspace">
<mspace width="1em"/>
<mspace width="thinmathspace"/>
<mspace/>
</mrow>
<mrow id="negativemediummathspace">
<mspace width="1em"/>
<mspace width="mediummathspace"/>
<mspace/>
</mrow>
<mrow id="negativethickmathspace">
<mspace width="1em"/>
<mspace width="thickmathspace"/>
<mspace/>
</mrow>
<mrow id="negativeverythickmathspace">
<mspace width="1em"/>
<mspace width="verythickmathspace"/>
<mspace/>
</mrow>
<mrow id="negativeveryverythickmathspace">
<mspace width="1em"/>
<mspace width="veryverythickmathspace"/>
<mspace/>
</mrow>
</math>
</p>
</body>
</html>

View file

@ -0,0 +1,34 @@
async_test(t => {
// First observer creates second in callback to ensure the entry has been dispatched by the time
// the second observer begins observing.
let entries_seen = 0;
new PerformanceObserver(firstList => {
entries_seen += firstList.getEntries().length;
// Abort if we have not yet received both paint entries.
if (entries_seen < 2)
return;
// Second observer requires 'buffered: true' to see the entries.
let firstPaintSeen = false;
let firstContentfulPaintSeen = false;
new PerformanceObserver(list => {
list.getEntries().forEach(t.step_func(entry => {
assert_equals(entry.entryType, 'paint');
if (entry.name === 'first-paint')
firstPaintSeen = true;
else if (entry.name === 'first-contentful-paint')
firstContentfulPaintSeen = true;
else
assert_unreached('The observer should only see first paint or first contentful paint!');
if (firstPaintSeen && firstContentfulPaintSeen)
t.done();
}));
}).observe({'type': 'paint', buffered: true});
}).observe({'entryTypes': ['paint']});
// Trigger the first paint entries
const img = document.createElement("IMG");
img.src = "resources/circles.png";
document.body.appendChild(img);
}, "PerformanceObserver with buffered flag sees previous paint entries.");

View file

@ -7,6 +7,9 @@
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="../pointerevent_support.js"></script>
<style>
#target0 {
@ -83,6 +86,7 @@
function run() {
var target0 = document.getElementById("target0");
var btnComplete = document.getElementById("btnComplete");
var actions_promise;
target0.scrollTop = 200;
var scrollListenerExecuted = false;
@ -100,9 +104,22 @@
assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
assert_greater_than(target0.scrollTop, 200, "scroll y offset should be greater than 200 in the end of the test");
});
test_touchaction.done();
// Make sure the test finishes after all the input actions are completed.
actions_promise.then( () => {
test_touchaction.done();
});
updateDescriptionComplete();
});
// Inject touch inputs.
actions_promise = touchScrollInTarget(target0, 'up').then(function() {
return touchScrollInTarget(target0, 'right');
}).then(function() {
return touchScrollInTarget(target0, 'down');
}).then(function() {
return clickInTarget("touch", btnComplete);
});
}
</script>
<h1>touch-action: pan-down</h1>

View file

@ -7,6 +7,9 @@
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="../pointerevent_support.js"></script>
<style>
#target0 {
@ -83,6 +86,7 @@
function run() {
var target0 = document.getElementById("target0");
var btnComplete = document.getElementById("btnComplete");
var actions_promise;
target0.scrollLeft = 200;
var scrollListenerExecuted = false;
@ -100,9 +104,22 @@
assert_less_than(target0.scrollLeft, 200, "scroll x offset should be less than 200 in the end of the test");
assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
});
test_touchaction.done();
// Make sure the test finishes after all the input actions are completed.
actions_promise.then( () => {
test_touchaction.done();
});
updateDescriptionComplete();
});
// Inject touch inputs.
actions_promise = touchScrollInTarget(target0, 'down').then(function() {
return touchScrollInTarget(target0, 'right');
}).then(function() {
return touchScrollInTarget(target0, 'left');
}).then(function() {
return clickInTarget("touch", btnComplete);
});
}
</script>
<h1>touch-action: pan-left</h1>

View file

@ -7,6 +7,9 @@
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="../pointerevent_support.js"></script>
<style>
#target0 {
@ -83,6 +86,7 @@
function run() {
var target0 = document.getElementById("target0");
var btnComplete = document.getElementById("btnComplete");
var actions_promise;
target0.scrollLeft = 200;
var scrollListenerExecuted = false;
@ -100,9 +104,22 @@
assert_greater_than(target0.scrollLeft, 200, "scroll x offset should be greater than 200 in the end of the test");
assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
});
test_touchaction.done();
// Make sure the test finishes after all the input actions are completed.
actions_promise.then( () => {
test_touchaction.done();
});
updateDescriptionComplete();
});
// Inject touch inputs.
actions_promise = touchScrollInTarget(target0, 'down').then(function() {
return touchScrollInTarget(target0, 'left');
}).then(function() {
return touchScrollInTarget(target0, 'right');
}).then(function() {
return clickInTarget("touch", btnComplete);
});
}
</script>
<h1>touch-action: pan-right</h1>

View file

@ -7,6 +7,9 @@
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="../pointerevent_support.js"></script>
<style>
#target0 {
@ -83,6 +86,7 @@
function run() {
var target0 = document.getElementById("target0");
var btnComplete = document.getElementById("btnComplete");
var actions_promise;
target0.scrollTop = 200;
var scrollListenerExecuted = false;
@ -100,9 +104,22 @@
assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
assert_less_than(target0.scrollTop, 200, "scroll y offset should be less than 200 in the end of the test");
});
test_touchaction.done();
// Make sure the test finishes after all the input actions are completed.
actions_promise.then( () => {
test_touchaction.done();
});
updateDescriptionComplete();
});
// Inject touch inputs.
actions_promise = touchScrollInTarget(target0, 'down').then(function() {
return touchScrollInTarget(target0, 'right');
}).then(function() {
return touchScrollInTarget(target0, 'up');
}).then(function() {
return clickInTarget("touch", btnComplete);
});
}
</script>
<h1>touch-action: pan-up</h1>

View file

@ -52,4 +52,14 @@
});
window.open(`resources/portals-adopt-predecessor.html?test=${test}`);
}, "Tests that an adopting, inserting and then removing a predecessor works correctly");
async_test(t => {
var test = "adopt-and-discard";
var bc = new BroadcastChannel(`test-${test}`);
bc.onmessage = t.step_func_done(function(e) {
assert_equals(e.data, "passed");
bc.close();
});
window.open(`resources/portals-adopt-predecessor.html?test=${test}`);
}, "Tests that the adopted predecessor is destroyed if it isn't inserted");
</script>

View file

@ -51,5 +51,18 @@
bc_test.close();
});
}
if (test == "adopt-and-discard") {
var portal = e.adoptPredecessor();
setTimeout(() => {
// portal should be inactive and activate should fail.
portal.activate().catch(e => {
if (e.name == "InvalidStateError") {
var bc_test = new BroadcastChannel(`test-${test}`);
bc_test.postMessage("passed");
bc_test.close();
}
});
});
}
}
</script>

View file

@ -0,0 +1,18 @@
async_test(t => {
performance.clearResourceTimings();
// First observer creates second in callback to ensure the entry has been dispatched by the time
// the second observer begins observing.
new PerformanceObserver(() => {
// Second observer requires 'buffered: true' to see an entry.
new PerformanceObserver(t.step_func_done(list => {
const entries = list.getEntries();
assert_equals(entries.length, 1, 'There should be 1 resource entry.');
assert_equals(entries[0].entryType, 'resource');
assert_greater_than(entries[0].startTime, 0);
assert_greater_than(entries[0].responseEnd, entries[0].startTime);
assert_greater_than(entries[0].duration, 0);
assert_true(entries[0].name.endsWith('resources/empty.js'));
})).observe({'type': 'resource', buffered: true});
}).observe({'entryTypes': ['resource']});
fetch('resources/empty.js');
}, 'PerformanceObserver with buffered flag sees previous resource entries.');

View file

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8" />
<title>Resource Timing embed navigate - back button navigation</title>
<body onunload="/*disable bfcache*/"></body>
<script src="/common/get-host-info.sub.js"></script>
<script src="nested-contexts.js"></script>
<script>

View file

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8" />
<title>Resource Timing iframe navigate - back button navigation</title>
<body onunload="/*disable bfcache*/"></body>
<script src="/common/get-host-info.sub.js"></script>
<script src="nested-contexts.js"></script>
<script>

View file

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8" />
<title>Resource Timing object navigate - back button navigation</title>
<body onunload="/*disable bfcache*/"></body>
<script src="/common/get-host-info.sub.js"></script>
<script src="nested-contexts.js"></script>
<script>

View file

@ -0,0 +1,4 @@
This directory contains a built version of the [webidl2.js library](https://github.com/w3c/webidl2.js).
It is built by running `npx webpack --mode none` at the root of that repository.
The `webidl2.js.headers` file is a local addition to ensure the script is interpreted as UTF-8.

File diff suppressed because it is too large Load diff

View file

@ -1,46 +1,35 @@
import time
def ok_response(request, response, visited_count,
extra_body='', mime_type='application/javascript'):
# |visited_count| is used as a unique id to differentiate responses
# every time.
return (
[
('Cache-Control', 'no-cache, must-revalidate'),
('Pragma', 'no-cache'),
('Content-Type', mime_type)
],
'/* %s */ %s' % (str(visited_count), extra_body))
def main(request, response):
# Set mode to 'init' for initial fetch.
mode = 'init'
if 'mode' in request.cookies:
mode = request.cookies['mode'].value
key = request.GET["Key"]
mode = request.GET["Mode"]
# 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')]
visited_count = request.server.stash.take(key)
if visited_count is None:
visited_count = 0
content_type = ''
extra_body = ''
if mode == 'init':
# Set a normal mimetype.
# Set cookie value to 'normal' so the next fetch will work in 'normal' mode.
content_type = 'application/javascript'
response.set_cookie('mode', 'normal')
elif mode == 'normal':
# Set a normal mimetype.
# Set cookie value to 'error' so the next fetch will work in 'error' mode.
content_type = 'application/javascript'
response.set_cookie('mode', 'error');
elif mode == 'error':
# Set a disallowed mimetype.
# Set cookie value to 'syntax-error' so the next fetch will work in 'syntax-error' mode.
content_type = 'text/html'
response.set_cookie('mode', 'syntax-error');
elif mode == 'syntax-error':
# Set cookie value to 'throw-install' so the next fetch will work in 'throw-install' mode.
content_type = 'application/javascript'
response.set_cookie('mode', 'throw-install');
extra_body = 'badsyntax(isbad;'
elif mode == 'throw-install':
# Unset and delete cookie to clean up the test setting.
content_type = 'application/javascript'
response.delete_cookie('mode')
extra_body = "addEventListener('install', function(e) { throw new Error('boom'); });"
headers.append(('Content-Type', content_type))
# Return a different script for each access. Use .time() and .clock() for
# best time resolution across different platforms.
return headers, '/* %s %s */ %s' % (time.time(), time.clock(), extra_body)
# Keep how many times the test requested this resource.
visited_count += 1
request.server.stash.put(key, visited_count)
# Return a response based on |mode| only when it's the second time (== update).
if visited_count == 2:
if mode == 'normal':
return ok_response(request, response, visited_count)
if mode == 'bad_mime_type':
return ok_response(request, response, visited_count, mime_type='text/html')
if mode == 'syntax_error':
return ok_response(request, response, visited_count, extra_body='badsyntax(isbad;')
if mode == 'throw_install':
return ok_response(request, response, visited_count, extra_body="addEventListener('install', function(e) { throw new Error('boom'); });")
return ok_response(request, response, visited_count)

View file

@ -1,5 +1,7 @@
<!DOCTYPE html>
<title>Service Worker: Registration update()</title>
<meta name="timeout" content="long">
<script src="/common/utils.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/testharness-helpers.js"></script>
@ -7,115 +9,107 @@
<script>
'use strict';
promise_test(function(t) {
var scope = 'resources/simple.txt';
var worker_url = 'resources/update-worker.py';
var expected_url = normalizeURL(worker_url);
var registration;
const SCOPE = 'resources/simple.txt';
const WORKER_URL_BASE = 'resources/update-worker.py';
return service_worker_unregister_and_register(t, worker_url, scope)
.then(function(r) {
registration = r;
return wait_for_state(t, registration.installing, 'activated');
})
.then(function() {
assert_equals(registration.installing, null,
'installing should be null in the initial state.');
assert_equals(registration.waiting, null,
'waiting should be null in the initial state.');
assert_equals(registration.active.scriptURL, expected_url,
'active should exist in the initial state.');
// A new worker (generated by update-worker.py) should be found.
// The returned promise should resolve when a new worker script is
// fetched and starts installing.
return Promise.all([registration.update(),
wait_for_update(t, registration)]);
})
.then(function() {
assert_equals(registration.installing.scriptURL, expected_url,
'new installing should be set after update resolves.');
assert_equals(registration.waiting, null,
'waiting should still be null after update resolves.');
assert_equals(registration.active.scriptURL, expected_url,
'active should still exist after update found.');
return wait_for_state(t, registration.installing, 'installed');
})
.then(function() {
assert_equals(registration.installing, null,
'installing should be null after installing.');
assert_equals(registration.waiting.scriptURL, expected_url,
'waiting should be set after installing.');
assert_equals(registration.active.scriptURL, expected_url,
'active should still exist after installing.');
return wait_for_state(t, registration.waiting, 'activated');
})
.then(function() {
assert_equals(registration.installing, null,
'installing should be null after activated.');
assert_equals(registration.waiting, null,
'waiting should be null after activated.');
assert_equals(registration.active.scriptURL, expected_url,
'new worker should be promoted to active.');
})
.then(function() {
// A new worker(generated by update-worker.py) should be found.
// The returned promise should reject as update-worker.py sets the
// mimetype to a disallowed value for this attempt.
return registration.update();
})
.then(
function() { assert_unreached("update() should reject."); },
function(e) {
assert_throws('SecurityError', function() { throw e; },
'Using a disallowed mimetype should make update() ' +
'promise reject with a SecurityError.');
assert_equals(registration.active.scriptURL, expected_url,
'active should still exist after update failure.');
async function prepare_ready_registration(t, mode) {
const key = token();
const worker_url = `${WORKER_URL_BASE}?Key=${key}&Mode=${mode}`;
const expected_url = normalizeURL(worker_url);
const registration = await service_worker_unregister_and_register(
t, worker_url, SCOPE);
await wait_for_state(t, registration.installing, 'activated');
assert_equals(registration.installing, null,
'prepare_ready: installing');
assert_equals(registration.waiting, null,
'prepare_ready: waiting');
assert_equals(registration.active.scriptURL, expected_url,
'prepare_ready: active');
return [registration, expected_url];
}
// A new worker(generated by update-worker.py) should be found.
// The returned promise should reject as update-worker.py returns
// a worker script with a syntax error.
return registration.update();
})
.then(
function() { assert_unreached("update() should reject."); },
function(e) {
assert_throws({name: 'TypeError'}, function () { throw e; },
'A script syntax error should make update() ' +
'promise reject with a TypeError.');
assert_equals(registration.active.scriptURL, expected_url,
'active should still exist after update failure.');
function assert_installing_and_active(registration, expected_url) {
assert_equals(registration.installing.scriptURL, expected_url,
'assert_installing_and_active: installing');
assert_equals(registration.waiting, null,
'assert_installing_and_active: waiting');
assert_equals(registration.active.scriptURL, expected_url,
'assert_installing_and_active: active');
}
// A new worker(generated by update-worker.py) should be found.
// The returned promise should not reject, even though
// update-worker.py returns a worker script that throws in the
// install event handler.
return Promise.all([registration.update(),
wait_for_update(t, registration)]);
})
.then(function() {
assert_equals(registration.installing.scriptURL, expected_url,
'new installing should be set after update resolves.');
assert_equals(registration.waiting, null,
'waiting should be null after activated.');
assert_equals(registration.active.scriptURL, expected_url,
'active should still exist after update found.');
function assert_waiting_and_active(registration, expected_url) {
assert_equals(registration.installing, null,
'assert_waiting_and_active: installing');
assert_equals(registration.waiting.scriptURL, expected_url,
'assert_waiting_and_active: waiting');
assert_equals(registration.active.scriptURL, expected_url,
'assert_waiting_and_active: active');
}
// We need to hold a client alive so that unregister() below doesn't
// remove the registration before update() has had a chance to look
// at the pending uninstall flag.
return with_iframe(scope);
})
.then(function(frame) {
t.add_cleanup(function() {
frame.remove();
});
function assert_active_only(registration, expected_url) {
assert_equals(registration.installing, null,
'assert_active_only: installing');
assert_equals(registration.waiting, null,
'assert_active_only: waiting');
assert_equals(registration.active.scriptURL, expected_url,
'assert_active_only: active');
}
return assert_promise_rejects(
Promise.all([registration.unregister(), registration.update()]),
new TypeError(),
'Calling update() while the uninstalling flag is set ' +
'should return a promise that rejects with a TypeError.');
});
}, 'Update a registration.');
promise_test(async t => {
const [registration, expected_url] =
await prepare_ready_registration(t, 'normal');
t.add_cleanup(() => registration.unregister());
await Promise.all([registration.update(), wait_for_update(t, registration)]);
assert_installing_and_active(registration, expected_url);
await wait_for_state(t, registration.installing, 'installed');
assert_waiting_and_active(registration, expected_url);
await wait_for_state(t, registration.waiting, 'activated');
assert_active_only(registration, expected_url);
}, 'update() should succeed when new script is available.');
promise_test(async t => {
const [registration, expected_url] =
await prepare_ready_registration(t, 'bad_mime_type');
t.add_cleanup(() => registration.unregister());
promise_rejects(t, 'SecurityError', registration.update());
assert_active_only(registration, expected_url);
}, 'update() should fail when mime type is invalid.');
promise_test(async t => {
const [registration, expected_url] =
await prepare_ready_registration(t, 'syntax_error');
t.add_cleanup(() => registration.unregister());
promise_rejects(t, new TypeError(), registration.update());
assert_active_only(registration, expected_url);
}, 'update() should fail when a new script contains a syntax error.');
promise_test(async t => {
const [registration, expected_url] =
await prepare_ready_registration(t, 'throw_install');
t.add_cleanup(() => registration.unregister());
await Promise.all([registration.update(), wait_for_update(t, registration)]);
assert_installing_and_active(registration, expected_url);
}, 'update() should resolve when the install event throws.');
promise_test(async t => {
const [registration, expected_url] =
await prepare_ready_registration(t, 'normal');
t.add_cleanup(() => registration.unregister());
// We need to hold a client alive so that unregister() below doesn't remove
// the registration before update() has had a chance to look at the pending
// uninstall flag.
const frame = await with_iframe(SCOPE);
t.add_cleanup(() => frame.remove());
promise_rejects(
t, new TypeError(),
Promise.all([registration.unregister(), registration.update()]));
}, 'update() should fail when the pending uninstall flag is set.')
</script>

View file

@ -19,11 +19,23 @@ let interceptor = (async function() {
return load.then(intercept);
})();
class SmsProvider {
// Fake implementation of blink.mojom.SmsReceiver.
class FakeSmsReceiverImpl {
constructor() {
this.returnValues = {}
}
bindHandleToMojoReceiver(handle) {
this.mojoReceiver_ = new blink.mojom.SmsReceiverReceiver(this);
this.mojoReceiver_.$.bindHandle(handle);
}
pushReturnValuesForTesting(callName, returnValues) {
this.returnValues[callName] = this.returnValues[callName] || [];
this.returnValues[callName].push(returnValues);
return this;
}
receive(timeout) {
let call = this.returnValues.receive.shift();
if (!call) {
@ -31,12 +43,6 @@ class SmsProvider {
}
return call(timeout);
}
pushReturnValues(callName, returnValues) {
this.returnValues[callName] = this.returnValues[callName] || [];
this.returnValues[callName].push(returnValues);
return this;
}
}
function receive(timeout, callback) {
@ -46,8 +52,8 @@ function receive(timeout, callback) {
function expect(call) {
return {
async andReturn(callback) {
let provider = await interceptor;
provider.pushReturnValues(call.name, callback);
let smsReceiverImpl = await interceptor;
smsReceiverImpl.pushReturnValuesForTesting(call.name, callback);
}
}
}
@ -55,13 +61,12 @@ function expect(call) {
const Status = {};
function intercept() {
let provider = new SmsProvider();
let smsReceiverImpl = new FakeSmsReceiverImpl();
let interceptor = new MojoInterfaceInterceptor(
blink.mojom.SmsReceiver.$interfaceName);
interceptor.oninterfacerequest = (e) => {
let impl = new blink.mojom.SmsReceiver(provider);
impl.$.bindHandle(e.handle);
smsReceiverImpl.bindHandleToMojoReceiver(e.handle);
}
interceptor.start();
@ -69,5 +74,5 @@ function intercept() {
Status.kSuccess = blink.mojom.SmsStatus.kSuccess;
Status.kTimeout = blink.mojom.SmsStatus.kTimeout;
return provider;
return smsReceiverImpl;
}

View file

@ -115,7 +115,7 @@ testToastElementAsync((t, toast) => {
}, 'toggling open attribute does not start timeout');
testToastElement((toast) => {
const permitted_properties = ['constructor', 'show', 'hide', 'toggle', 'open', 'action'];
const permitted_properties = ['constructor', 'show', 'hide', 'toggle', 'open', 'action', 'closeButton'];
assert_array_equals(permitted_properties.sort(), Object.getOwnPropertyNames(toast.__proto__).sort());
}, 'toast only exposes certain properties');
</script>

View file

@ -0,0 +1,124 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Toast: closebutton tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<main></main>
<script type="module">
import { showToast } from 'std:elements/toast';
import { testToastElement } from './resources/helpers.js';
testToastElement((toast) => {
toast.setAttribute('closebutton', '');
assert_true(toast.closeButton);
}, 'the closeButton property returns true with an empty attribute');
testToastElement((toast) => {
toast.setAttribute('closebutton', 'dismiss');
assert_equals(toast.closeButton, 'dismiss');
}, 'the closeButton property returns the set attribute value');
testToastElement((toast) => {
assert_false(toast.closeButton);
}, 'the closeButton property returns false with no attribute');
testToastElement((toast) => {
toast.setAttribute('closebutton', '');
assert_true(toast.closeButton);
toast.setAttribute('closebutton', 'dismiss');
assert_equals(toast.closeButton, 'dismiss');
toast.removeAttribute('closebutton');
assert_false(toast.closeButton);
}, 'the closeButton property changes when the attribute changes');
testToastElement((toast) => {
toast.closeButton = 'dismiss';
assert_equals(toast.getAttribute('closebutton'), 'dismiss');
}, 'setting the closeButton property to any string changes the attribute to that string');
testToastElement((toast) => {
toast.closeButton = '';
assert_equals(toast.getAttribute('closebutton'), '');
}, 'setting the closeButton property to empty string changes the attribute to empty string');
testToastElement((toast) => {
toast.closeButton = true;
assert_equals(toast.getAttribute('closebutton'), '');
}, 'setting the closeButton property to true changes the attribute to empty string');
testToastElement((toast) => {
toast.closeButton = false;
assert_false(toast.hasAttribute('closebutton'));
}, 'setting the closeButton property to false removes the attribute');
testToastElement((toast) => {
toast.closeButton = undefined;
assert_equals(toast.getAttribute('closebutton'), 'undefined');
}, 'setting the closeButton property to undefined stringifies and sets to that');
testToastElement((toast) => {
toast.closeButton = null;
assert_equals(toast.getAttribute('closebutton'), 'null');
}, 'setting the closeButton property to null stringifies and sets to that');
testToastElement((toast) => {
toast.closeButton = {};
assert_equals(toast.getAttribute('closebutton'), '[object Object]');
}, 'setting the closeButton property to {} stringifies and sets to [object Object]');
test(() => {
const toast = showToast('Message', { closeButton: true });
assert_equals(toast.getAttribute('closebutton'), '');
}, 'setting the showToast closeButton option to true sets the closebutton attribute to empty string');
test(() => {
const toast = showToast('Message', { closeButton: 'dismiss' });
assert_equals(toast.getAttribute('closebutton'), 'dismiss');
}, 'setting the showToast closeButton option to some string sets that string as the closebutton attribute');
test(() => {
const toast = showToast('Message', { closeButton: '' });
assert_equals(toast.getAttribute('closebutton'), '');
}, 'setting the showToast closeButton option to empty string sets the closebutton attribute to empty string');
test(() => {
const toast = showToast('Message', { closeButton: {} });
assert_equals(toast.getAttribute('closebutton'), '[object Object]');
}, 'setting the showToast closeButton option to {} sets the closebutton attribute to [object Object]');
test(() => {
const toast = showToast('Message', { closeButton: document.createElement('span') });
assert_equals(toast.getAttribute('closebutton'), '[object HTMLSpanElement]');
}, 'passing an HTML element into the closeButton option of showToast stringifies and sets it to the closebutton attribute');
test(() => {
const toast = showToast('Message', { closeButton: false });
assert_false(toast.hasAttribute('closebutton'));
}, 'setting the showToast closeButton option to false does not put a close button on the toast');
test(() => {
const toast = showToast('Message');
assert_false(toast.hasAttribute('closebutton'));
}, 'calling showToast without the closeButton option does not put a closebutton on the toast');
</script>

View file

@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
width="800px" height="8000px">
<title>SVG Scripting and Interactivity: getComputedStyle().pointerEvents</title>
<metadata>
<h:link rel="help" href="https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty"/>
<h:meta name="assert" content="pointer-events computed value is as specified."/>
</metadata>
<g id="target"></g>
<h:script src="/resources/testharness.js"/>
<h:script src="/resources/testharnessreport.js"/>
<h:script src="/css/support/computed-testcommon.js"/>
<script><![CDATA[
test_computed_value("pointer-events", "auto");
test_computed_value("pointer-events", "bounding-box");
test_computed_value("pointer-events", "visiblepainted");
test_computed_value("pointer-events", "visiblefill");
test_computed_value("pointer-events", "visiblestroke");
test_computed_value("pointer-events", "visible");
test_computed_value("pointer-events", "painted");
test_computed_value("pointer-events", "fill");
test_computed_value("pointer-events", "stroke");
test_computed_value("pointer-events", "all");
test_computed_value("pointer-events", "none");
]]></script>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
width="800px" height="8000px">

Before

Width:  |  Height:  |  Size: 953 B

After

Width:  |  Height:  |  Size: 914 B

Before After
Before After

View file

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
width="800px" height="8000px">
@ -15,9 +14,9 @@
test_valid_value("pointer-events", "auto");
test_valid_value("pointer-events", "bounding-box");
test_valid_value("pointer-events", "visiblePainted");
test_valid_value("pointer-events", "visibleFill");
test_valid_value("pointer-events", "visibleStroke");
test_valid_value("pointer-events", "visiblePainted", "visiblepainted");
test_valid_value("pointer-events", "visibleFill", "visiblefill");
test_valid_value("pointer-events", "visibleStroke", "visiblestroke");
test_valid_value("pointer-events", "visible");
test_valid_value("pointer-events", "painted");
test_valid_value("pointer-events", "fill");

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

@ -191,4 +191,4 @@ class HTTPWireProtocol(object):
return self.connection.getresponse()
def _has_unread_data(self):
return self._conn and select.select([self._conn.sock], [], [], 0)[0]
return self._conn and self._conn.sock and select.select([self._conn.sock], [], [], 0)[0]

View file

@ -590,6 +590,29 @@ class ChromeAndroid(Browser):
return None
class ChromeiOS(Browser):
"""Chrome-specific interface for iOS.
"""
product = "chrome_ios"
requirements = "requirements_chrome_ios.txt"
def install(self, dest=None, channel=None):
raise NotImplementedError
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self, channel=None):
raise NotImplementedError
def install_webdriver(self, dest=None, channel=None, browser_binary=None):
raise NotImplementedError
def version(self, binary=None, webdriver_binary=None):
return None
class Opera(Browser):
"""Opera-specific interface.

View file

@ -310,6 +310,15 @@ class ChromeAndroid(BrowserSetup):
raise WptrunError("Unable to locate or install chromedriver binary")
class ChromeiOS(BrowserSetup):
name = "chrome_ios"
browser_cls = browser.ChromeiOS
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
raise WptrunError("Unable to locate or install chromedriver binary")
class Opera(BrowserSetup):
name = "opera"
browser_cls = browser.Opera
@ -505,6 +514,7 @@ product_setup = {
"firefox": Firefox,
"chrome": Chrome,
"chrome_android": ChromeAndroid,
"chrome_ios": ChromeiOS,
"edgechromium": EdgeChromium,
"edge": Edge,
"edge_webdriver": EdgeWebDriver,

View file

@ -0,0 +1 @@
mozprocess==1.0.0

View file

@ -24,6 +24,7 @@ module global scope.
product_list = ["chrome",
"chrome_android",
"chrome_ios",
"edgechromium",
"edge",
"edge_webdriver",

View file

@ -0,0 +1,80 @@
from .base import Browser, ExecutorBrowser, require_arg
from .base import get_timeout_multiplier # noqa: F401
from ..webdriver_server import CWTChromeDriverServer
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401
WebDriverRefTestExecutor) # noqa: F401
from ..executors.executorchrome import ChromeDriverWdspecExecutor # noqa: F401
__wptrunner__ = {"product": "chrome_ios",
"check_args": "check_args",
"browser": "ChromeiOSBrowser",
"executor": {"testharness": "WebDriverTestharnessExecutor",
"reftest": "WebDriverRefTestExecutor"},
"browser_kwargs": "browser_kwargs",
"executor_kwargs": "executor_kwargs",
"env_extras": "env_extras",
"env_options": "env_options",
"timeout_multiplier": "get_timeout_multiplier"}
def check_args(**kwargs):
require_arg(kwargs, "webdriver_binary")
def browser_kwargs(test_type, run_info_data, config, **kwargs):
return {"webdriver_binary": kwargs["webdriver_binary"],
"webdriver_args": kwargs.get("webdriver_args")}
def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
**kwargs):
executor_kwargs = base_executor_kwargs(test_type, server_config, cache_manager, run_info_data,
**kwargs)
executor_kwargs["close_after_done"] = True
executor_kwargs["capabilities"] = {}
return executor_kwargs
def env_extras(**kwargs):
return []
def env_options():
return {}
class ChromeiOSBrowser(Browser):
"""ChromeiOS is backed by CWTChromeDriver, which is supplied through
``wptrunner.webdriver.CWTChromeDriverServer``.
"""
init_timeout = 120
def __init__(self, logger, webdriver_binary, webdriver_args=None):
"""Creates a new representation of Chrome."""
Browser.__init__(self, logger)
self.server = CWTChromeDriverServer(self.logger,
binary=webdriver_binary,
args=webdriver_args)
def start(self, **kwargs):
self.server.start(block=False)
def stop(self, force=False):
self.server.stop(force=force)
def pid(self):
return self.server.pid
def is_alive(self):
# TODO(ato): This only indicates the driver is alive,
# and doesn't say anything about whether a browser session
# is active.
return self.server.is_alive()
def cleanup(self):
self.stop()
def executor_browser(self):
return ExecutorBrowser, {"webdriver_url": self.server.url}

View file

@ -9,8 +9,9 @@ import traceback
import mozprocess
__all__ = ["SeleniumServer", "ChromeDriverServer", "EdgeChromiumDriverServer", "OperaDriverServer",
"GeckoDriverServer", "InternetExplorerDriverServer", "EdgeDriverServer",
__all__ = ["SeleniumServer", "ChromeDriverServer", "CWTChromeDriverServer",
"EdgeChromiumDriverServer", "OperaDriverServer", "GeckoDriverServer",
"InternetExplorerDriverServer", "EdgeDriverServer",
"ServoDriverServer", "WebKitDriverServer", "WebDriverServer"]
@ -127,6 +128,14 @@ class ChromeDriverServer(WebDriverServer):
cmd_arg("port", str(self.port)),
cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args
class CWTChromeDriverServer(WebDriverServer):
def __init__(self, logger, binary, port=None, args=None):
WebDriverServer.__init__(self, logger, binary, port=port, args=args)
def make_command(self):
return [self.binary,
"--port=%s" % str(self.port)] + self._args
class EdgeChromiumDriverServer(WebDriverServer):
def __init__(self, logger, binary="msedgedriver", port=None,
base_path="", args=None):
@ -239,7 +248,7 @@ def get_free_port():
s.close()
def wait_for_service(addr, timeout=15):
def wait_for_service(addr, timeout=60):
"""Waits until network service given as a tuple of (host, port) becomes
available or the `timeout` duration is reached, at which point
``socket.error`` is raised."""

View file

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
</head>
<body>
<div id="container"></div>
<script>
const container = document.querySelector("#container");
const policy = window.TrustedTypes.createPolicy("policy", {
createScript: t => t,
});
function stringify(arg) {
return "textContent" in arg.__proto__ ? arg.textContent : arg.toString()
}
// This test case mirrors the block-Node-multiple-arguments case except
// that, because Trusted Types is not enabled, no exceptions should be
// thrown anyhwere.
const targets = ["div", "script"];
const all_args = [
[ policy.createScript("'createScript';") ],
[ policy.createScript("'cresteScript #1';"), policy.createScript("'#2;'") ],
[ "'plain text';" ],
[ "'plain text #1';", "'plain text #2';" ],
[ document.createTextNode("'node';") ],
[ document.createTextNode("'node #1';"),
document.createTextNode("'node #2';") ],
[ "'mixed';", document.createTextNode("'node';") ],
[ "'mixed';", policy.createScript("'script';") ],
[ document.createTextNode("'node';"),
policy.createScript("'script';") ],
];
for (target of targets) {
for (args of all_args) {
for (setter of [container.replaceWith, container.after, container.before]) {
test(t => {
var outer = document.createElement(target);
container.appendChild(outer);
var inner = document.createElement("p");
outer.appendChild(inner);
setter.apply(inner, args);
assert_equals(outer.textContent, args.map(stringify).join(""));
}, `${setter.name}(${args.toString()}) on <${target}> should pass`);
}
for (setter of [container.append, container.prepend]) {
test(t => {
let outer = document.createElement(target);
container.appendChild(outer);
setter.apply(outer, args);
assert_equals(outer.textContent, args.map(stringify).join(""));
}, `${setter.name}(${args.toString()}) on <${target}> should pass`);
}
}
}
</script>
</body>
</html>

View file

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/helper.sub.js"></script>
<meta http-equiv="Content-Security-Policy" content="trusted-types *">
</head>
<body>
<div id="container"></div>
<script>
const container = document.querySelector("#container");
const policy = window.TrustedTypes.createPolicy("policy", {
createScript: t => t,
});
function stringify(arg) {
return "textContent" in arg.__proto__ ? arg.textContent : arg.toString()
}
// Test all combinations of:
// - DOM methods: append, prepend, replaceWith, after, before
// - one or two parameters, string, Text node, Trusted Script
// - into regular container or <script> element.
//
// Test arguments are all string literals with a semicolon, because -
// depending on target - it might be injected into a <script> and shouldn't
// cause syntax errors there.
const targets = ["div", "script"];
const pass_args = [
[ policy.createScript("'createScript';") ],
[ policy.createScript("'cresteScript #1';"), policy.createScript("'#2;'") ],
];
const fail_args = [
[ "'plain text';" ],
[ "'plain text #1';", "'plain text #2';" ],
[ document.createTextNode("'node';") ],
[ document.createTextNode("'node #1';"),
document.createTextNode("'node #2';") ],
[ "'mixed';", document.createTextNode("'node';") ],
[ "'mixed';", policy.createScript("'script';") ],
[ document.createTextNode("'node';"),
policy.createScript("'script';") ],
];
const all_args = [].concat(pass_args).concat(fail_args);
for (target of targets) {
for (args of all_args) {
var should_fail = target == "script" && fail_args.indexOf(args) != -1;
var fail_string = should_fail ? "fail" : "pass";
for (setter of [container.replaceWith, container.after, container.before]) {
test(t => {
var outer = document.createElement(target);
container.appendChild(outer);
var inner = document.createElement("p");
outer.appendChild(inner);
var test_fn = _ => { setter.apply(inner, args); };
var expected;
if (should_fail) {
assert_throws(new TypeError(), test_fn, "This should throw.");
expected = "";
} else {
test_fn();
expected = args.map(stringify).join("");
}
assert_equals(outer.textContent, expected);
}, `${setter.name}(${args.toString()}) on <${target}> should ${fail_string}`);
}
for (setter of [container.append, container.prepend]) {
test(t => {
let outer = document.createElement(target);
container.appendChild(outer);
var test_fn = _ => { setter.apply(outer, args); };
var expected;
if (should_fail) {
assert_throws(new TypeError(), test_fn, "This should throw.");
expected = "";
} else {
test_fn();
expected = args.map(stringify).join("");
}
assert_equals(outer.textContent, expected);
}, `${setter.name}(${args.toString()}) on <${target}> should ${fail_string}`);
}
}
}
</script>
</body>
</html>

View file

@ -3,12 +3,11 @@ async_test(t => {
// the second observer begins observing.
new PerformanceObserver(() => {
// Second observer requires 'buffered: true' to see an entry.
new PerformanceObserver(list => {
new PerformanceObserver(t.step_func_done(list => {
const entries = list.getEntries();
assert_equals(entries.length, 1, 'There should be 1 mark entry.');
assert_equals(entries[0].entryType, 'mark');
t.done();
}).observe({type: 'mark', buffered: true});
})).observe({type: 'mark', buffered: true});
}).observe({entryTypes: ['mark']});
performance.mark('foo');
}, 'PerformanceObserver with buffered flag sees previous marks');
@ -18,12 +17,11 @@ async_test(t => {
// the second observer begins observing.
new PerformanceObserver(() => {
// Second observer requires 'buffered: true' to see an entry.
new PerformanceObserver(list => {
new PerformanceObserver(t.step_func_done(list => {
const entries = list.getEntries();
assert_equals(entries.length, 1, 'There should be 1 measure entry.');
assert_equals(entries[0].entryType, 'measure');
t.done();
}).observe({type: 'measure', buffered: true});
})).observe({type: 'measure', buffered: true});
}).observe({entryTypes: ['measure']});
performance.measure('bar');
}, 'PerformanceObserver with buffered flag sees previous measures');

View file

@ -0,0 +1,93 @@
<!doctype html>
<html>
<head>
<title>
Test Active Processing for ConvolverNode
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webaudio/resources/audit-util.js"></script>
<script src="/webaudio/resources/audit.js"></script>
</head>
<body>
<script id="layout-test-code">
// AudioProcessor that sends a message to its AudioWorkletNode whenver the
// number of channels on its input changes.
let filePath =
'../the-audioworklet-interface/processors/active-processing.js';
const audit = Audit.createTaskRunner();
let context;
audit.define('initialize', (task, should) => {
// Create context and load the module
context = new AudioContext();
should(
context.audioWorklet.addModule(filePath),
'AudioWorklet module loading')
.beResolved()
.then(() => task.done());
});
audit.define('test', (task, should) => {
const src = new OscillatorNode(context);
const response = new AudioBuffer({numberOfChannels: 2, length: 150,
sampleRate: context.sampleRate});
const conv = new ConvolverNode(context, {buffer: response});
const testerNode =
new AudioWorkletNode(context, 'active-processing-tester', {
// Use as short a duration as possible to keep the test from
// taking too much time.
processorOptions: {testDuration: .5},
});
// Expected number of output channels from the convolver node. We should
// start with the number of inputs, because the source (oscillator) is
// actively processing. When the source stops, the number of channels
// should change to 1.
const expectedValues = [2, 1];
let index = 0;
testerNode.port.onmessage = event => {
let count = event.data.channelCount;
let finished = event.data.finished;
// If we're finished, end testing.
if (finished) {
// Verify that we got the expected number of changes.
should(index, 'Number of distinct values')
.beEqualTo(expectedValues.length);
task.done();
return;
}
if (index < expectedValues.length) {
// Verify that the number of channels matches the expected number of
// channels.
should(count, `Test ${index}: Number of convolver output channels`)
.beEqualTo(expectedValues[index]);
}
++index;
};
// Create the graph and go
src.connect(conv).connect(testerNode).connect(context.destination);
src.start();
// Stop the source after a short time so we can test that the convolver
// changes to not actively processing and thus produces a single channel
// of silence.
src.stop(context.currentTime + .1);
});
audit.run();
</script>
</body>
</html>

View file

@ -88,18 +88,6 @@
);
checkCount++;
}
// Don't assert(false) immediately here if the bin is still higher than
// -40db the analyzer node has a window and it's expecte that it takes some
// time for the volume of this bin to decrease. Similarly, -50 may seem
// quite high but is also a product of windowing.
if (frequencyData[indexToCheckForLowEnergy] < -50) {
assert_true(true, "Correct track routed to the AudioContext.");
} else {
assert_true(
false,
"Other track seem to be routed to the AudioContext?"
);
}
if (checkCount > 5 && checkCount < 20) {
twoTrackMediaStream.getAudioTracks().forEach(track => {
if (track.id == ids[0]) {

View file

@ -0,0 +1,361 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="RTCPeerConnection-helper.js"></script>
<script>
"use strict";
function getLines(sdp, startsWith) {
const lines = sdp.split("\r\n").filter(l => l.startsWith(startsWith));
assert_true(lines.length > 0, `One or more ${startsWith} in sdp`);
return lines;
}
const getUfrags = ({sdp}) => getLines(sdp, "a=ice-ufrag:");
const getPwds = ({sdp}) => getLines(sdp, "a=ice-pwd:");
async function doSignalingHandshakeEndOnFirst(pc1, pc2) {
await pc1.setLocalDescription(await pc1.createOffer());
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription(await pc2.createAnswer());
await pc1.setRemoteDescription(pc2.localDescription); // End on pc1. No race
}
async function doSignalingHandshakeEndOnSecond(pc1, pc2) {
await pc1.setLocalDescription(await pc1.createOffer());
await pc2.setRemoteDescription(pc1.localDescription);
await pc1.setRemoteDescription(await pc2.createAnswer());
await pc2.setLocalDescription(pc1.remoteDescription); // End on pc2. No race
}
async function assertNoNegotiationNeeded(t, pc) {
assert_equals(pc.signalingState, "stable", "In stable state");
const event = await Promise.race([
new Promise(r => pc.onnegotiationneeded = r),
new Promise(r => t.step_timeout(r, 10))
]);
assert_equals(event, undefined, "No negotiationneeded event");
}
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.restartIce();
await assertNoNegotiationNeeded(t, pc1);
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() does not trigger negotiation ahead of initial negotiation");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
pc1.restartIce();
await doSignalingHandshakeEndOnFirst(pc1, pc2);
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() has no effect on initial negotiation");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
}, "restartIce() fires negotiationneeded after initial negotiation");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1");
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2");
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
}, "restartIce() causes fresh ufrags");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
await pc1.setLocalDescription(await pc1.createOffer());
pc1.restartIce();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription(await pc2.createAnswer());
await pc1.setRemoteDescription(pc2.localDescription);
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() works in have-local-offer");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await pc1.setLocalDescription(await pc1.createOffer());
pc1.restartIce();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription(await pc2.createAnswer());
await pc1.setRemoteDescription(pc2.localDescription);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() works in initial have-local-offer");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
await pc2.setLocalDescription(await pc2.createOffer());
await pc1.setRemoteDescription(pc2.localDescription);
pc1.restartIce();
await pc2.setRemoteDescription(await pc1.createAnswer());
await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() works in have-remote-offer");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc2.addTransceiver("audio");
await pc2.setLocalDescription(await pc2.createOffer());
await pc1.setRemoteDescription(pc2.localDescription);
pc1.restartIce();
await pc2.setRemoteDescription(await pc1.createAnswer());
await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() does nothing in initial have-remote-offer");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnSecond(pc2, pc1);
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1");
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() survives remote offer");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
pc1.restartIce();
pc2.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnSecond(pc2, pc1);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() is satisfied by remote ICE restart");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
await pc1.setLocalDescription(await pc1.createOffer({iceRestart: false}));
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription(await pc2.createAnswer());
await pc1.setRemoteDescription(pc2.localDescription);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() trumps {iceRestart: false}");
promise_test(async t => {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [oldUfrag1] = getUfrags(pc1.localDescription);
const [oldUfrag2] = getUfrags(pc2.localDescription);
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
await pc1.setLocalDescription(await pc1.createOffer());
await pc1.setLocalDescription({type: "rollback"});
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const [newUfrag1] = getUfrags(pc1.localDescription);
const [newUfrag2] = getUfrags(pc2.localDescription);
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() survives rollback");
promise_test(async t => {
const pc1 = new RTCPeerConnection({bundlePolicy: "max-compat"});
const pc2 = new RTCPeerConnection({bundlePolicy: "max-compat"});
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.addTransceiver("audio");
pc1.addTransceiver("video");
await new Promise(r => pc1.onnegotiationneeded = r);
await doSignalingHandshakeEndOnFirst(pc1, pc2);
const oldUfrags1 = getUfrags(pc1.localDescription);
const oldUfrags2 = getUfrags(pc2.localDescription);
const oldPwds2 = getPwds(pc2.localDescription);
pc1.restartIce();
await new Promise(r => pc1.onnegotiationneeded = r);
// Engineer a partial ICE restart from pc2
pc2.restartIce();
await pc2.setLocalDescription(await pc2.createOffer());
{
let {type, sdp} = pc2.localDescription;
// Restore both old ice-ufrag and old ice-pwd to trigger a partial restart
sdp = sdp.replace(getUfrags({sdp})[0], oldUfrags2[0]);
sdp = sdp.replace(getPwds({sdp})[0], oldPwds2[0]);
const newUfrags2 = getUfrags({sdp});
const newPwds2 = getPwds({sdp});
assert_equals(newUfrags2[0], oldUfrags2[0], "control ufrag match");
assert_equals(newPwds2[0], oldPwds2[0], "control pwd match");
assert_not_equals(newUfrags2[1], oldUfrags2[1], "control ufrag non-match");
assert_not_equals(newPwds2[1], oldPwds2[1], "control pwd non-match");
await pc1.setRemoteDescription({type, sdp});
}
await pc1.setLocalDescription(await pc1.createAnswer());
const newUfrags1 = getUfrags(pc1.localDescription);
assert_equals(newUfrags1[0], oldUfrags1[0], "Unchanged 1");
assert_not_equals(newUfrags1[1], oldUfrags1[1], "Restarted 2");
await new Promise(r => pc1.onnegotiationneeded = r);
await pc1.setLocalDescription(await pc1.createOffer());
const newestUfrags1 = getUfrags(pc1.localDescription);
assert_not_equals(newestUfrags1[0], oldUfrag1[0], "Restarted 1");
assert_not_equals(newestUfrags1[1], oldUfrag1[1], "Restarted 2");
await assertNoNegotiationNeeded(t, pc1);
}, "restartIce() survives remote offer containing partial restart");
</script>