Update web-platform-tests to revision 8ae1ddbc812733c3a73b103eafad56fb43a2f4b5

This commit is contained in:
WPT Sync Bot 2019-01-26 20:37:16 -05:00
parent d44e9aced2
commit 0e5e5db397
109 changed files with 2053 additions and 708 deletions

View file

@ -30,9 +30,3 @@ function waitForAsyncAnimationFrames(count) {
// AnimationWorklet.
return waitForAnimationFrames(count + 1);
}
async function waitForAnimationFrameWithCondition(condition) {
do {
await new Promise(window.requestAnimationFrame);
} while (!condition())
};

View file

@ -1,11 +0,0 @@
<!DOCTYPE html>
<style>
#box {
width: 100px;
height: 100px;
transform: translateY(100px);
background-color: green;
}
</style>
<div id="box"></div>

View file

@ -1,37 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<title>Verify that calling pause immediately after playing works as expected</title>
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<link rel="match" href="references/translated-box-ref.html">
<script src="/common/reftest-wait.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<style>
#box {
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id="box"></div>
<script>
registerPassthroughAnimator().then(async _ => {
const box = document.getElementById('box');
const effect = new KeyframeEffect(box,
{ transform: ['translateY(100px)', 'translateY(200px)'] },
{ duration: 100, iterations: 1 }
);
const animation = new WorkletAnimation('passthrough', effect);
animation.play();
// Immediately pausing animation should freeze the current time at 0.
animation.pause();
// Wait at least one frame to ensure a paused animation actually freezes.
await waitForAsyncAnimationFrames(1);
takeScreenshot();
});
</script>
</html>

View file

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<title>Verify that calling pause immediately after playing works as expected</title>
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<link rel="match" href="references/translated-box-ref.html">
<script src="/common/reftest-wait.js"></script>
<script src="common.js"></script>
<style>
#box {
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id="box"></div>
<script>
registerPassthroughAnimator().then(async _ => {
const duration = 18; // a bit longer than a frame
const box = document.getElementById('box');
const effect = new KeyframeEffect(box,
{ transform: ['translateY(0px)', 'translateY(100px)'] },
{ duration: duration, iterations: 1, fill: 'forwards'}
);
const animation = new WorkletAnimation('passthrough', effect);
// Immediately pausing animation should freeze the current time at 0.
animation.pause();
// Playing should cause animation to resume.
animation.play();
// Wait until we ensure animation has reached completion.
await waitForAnimationFrameWithCondition( _ => {
return animation.currentTime >= duration;
});
takeScreenshot();
});
</script>
</html>

View file

@ -1,58 +0,0 @@
<!DOCTYPE html>
<title>Verify that currentTime and playState are correct when animation is paused</title>
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<div id="box"></div>
<script>
setup(setupAndRegisterTests, {explicit_done: true});
function createAnimation() {
const box = document.getElementById('box');
const effect = new KeyframeEffect(box,
{ transform: ['translateY(100px)', 'translateY(200px)'] },
{ duration: 100, iterations: 1 }
);
return new WorkletAnimation('passthrough', effect);
}
async function setupAndRegisterTests() {
await registerPassthroughAnimator();
promise_test(async t => {
const animation = createAnimation();
animation.play();
// Immediately pausing animation should freeze the current time at 0.
animation.pause();
assert_equals(animation.currentTime, 0);
assert_equals(animation.playState, "paused");
// Wait some time to ensure a paused animation actually freezes.
await waitForNextFrame();
assert_equals(animation.currentTime, 0);
assert_equals(animation.playState, "paused");
}, 'pausing an animation freezes its current time');
promise_test(async t => {
const animation = createAnimation();
const startTime = document.timeline.currentTime;
animation.pause();
animation.play();
await waitForNextFrame();
const timelineTime = document.timeline.currentTime;
assert_equals(animation.playState, "running");
assert_greater_than(animation.currentTime, 0);
assert_times_equal(animation.currentTime, (timelineTime - startTime));
}, 'playing a paused animation should resume it');
done();
}
</script>

View file

@ -3,12 +3,22 @@
<head>
<meta charset="utf-8">
<title>css-conditional IDL tests</title>
<title>CSS Conditional Rules IDL tests</title>
<link rel="help" href="https://drafts.csswg.org/css-conditional/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>
<script src="/resources/idlharness.js"></script>
<!-- used to provide objects -->
<style>
div { display: block; }
</style>
<style>
@media print { }
</style>
<style>
@supports (display: block) { }
</style>
</head>
<body>
@ -16,16 +26,20 @@
<script>
'use strict';
promise_test(async () => {
const idl = await fetch('/interfaces/css-conditional.idl').then(r => r.text());
const cssom = await fetch('/interfaces/cssom.idl').then(r => r.text());
const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
const idl_array = new IdlArray();
idl_array.add_idls(idl);
idl_array.add_dependency_idls(cssom);
idl_array.add_dependency_idls(dom);
idl_array.test();
}, 'Test css-conditional IDL implementation');
idl_test(
['css-conditional'],
['cssom', 'dom'],
idl_array => {
idl_array.add_objects({
CSSRule: ['cssRule'],
CSSMediaRule: ['cssMediaRule'],
CSSSupportsRule: ['cssSupportsRule'],
});
self.cssRule = document.styleSheets[0].cssRules[0];
self.cssMediaRule = document.styleSheets[1].cssRules[0];
self.cssSupportsRule = document.styleSheets[2].cssRules[0];
}
);
</script>
</body>

View file

@ -1,19 +1,34 @@
<!doctype html>
<title>css-fonts IDL tests</title>
<title>CSS Fonts IDL tests</title>
<link rel="help" href="https://drafts.csswg.org/css-fonts-4/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>
<script src="/resources/idlharness.js"></script>
<style>
div { display: block; }
</style>
<style>
@font-face {
font-family: fwf;
src: url(support/fonts/FontWithFancyFeatures.otf);
}
</style>
<script>
"use strict";
promise_test(async () => {
const idl_array = new IdlArray();
const idl = await fetch("/interfaces/css-fonts.idl").then(r => r.text());
const cssom = await fetch("/interfaces/cssom.idl").then(r => r.text());
idl_array.add_idls(idl);
idl_array.add_dependency_idls(cssom);
idl_array.test();
}, "Test IDL implementation of css-fonts API");
idl_test(
["css-fonts"],
["cssom"],
idl_array => {
idl_array.add_objects({
CSSRule: ['cssRule'],
CSSFontFaceRule: ['cssFontFaceRule'],
});
self.cssRule = document.styleSheets[0].cssRules[0];
self.cssFontFaceRule = document.styleSheets[1].cssRules[0];
}
);
</script>

View file

@ -8,19 +8,9 @@
<script>
"use strict";
promise_test(async () => {
const idl_array = new IdlArray();
const idl = await fetch("/interfaces/css-paint-api.idl").then(r => r.text());
const cssom = await fetch("/interfaces/cssom.idl").then(r => r.text());
const html = await fetch("/interfaces/html.idl").then(r => r.text());
idl_array.add_idls(idl);
idl_array.add_dependency_idls(cssom);
idl_array.add_dependency_idls(html);
idl_array.add_untested_idls(`
[Exposed=Worklet]
interface WorkletGlobalScope {
attribute Console console;
};`);
idl_array.test();
}, "Test IDL implementation of CSS Painting API");
idl_test(
["css-paint-api"],
["cssom", "html", "worklets"]
// No objects in Window global
);
</script>

View file

@ -8,13 +8,9 @@
<script>
"use strict";
promise_test(async () => {
const idl = await fetch("/interfaces/css-properties-values-api.idl").then(r => r.text());
const cssom = await fetch("/interfaces/cssom.idl").then(r => r.text());
const idl_array = new IdlArray();
idl_array.add_idls(idl);
idl_array.add_dependency_idls(cssom);
idl_array.test();
}, "Test IDL implementation of CSS Properties Values API");
idl_test(
["css-properties-values-api"],
["cssom"]
// No objects
);
</script>

View file

@ -0,0 +1,125 @@
<!doctype html>
<title>An+B Parsing</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
foo { color: blue; }
</style>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#the-anb-type">
<script>
function roundtripANB(str) {
const rule = document.styleSheets[0].cssRules[0];
rule.selectorText = "foo";
rule.selectorText = `:nth-child(${str})`;
// Check for parse error.
if(rule.selectorText == "foo") return "parse error";
return rule.selectorText.slice(11, -1);
}
function testANB(input, expected) {
test(()=>{
assert_equals(roundtripANB(input), expected);
}, `"${input}" becomes "${expected}"`);
}
/* Just going down all the syntax clauses one-by-one */
// odd | even |
testANB("odd", "2n+1");
testANB("even", "2n");
// <integer> |
testANB("1", "1");
testANB("+1", "1");
testANB("-1", "-1");
//
// <n-dimension> |
testANB("5n", "5n");
testANB("5N", "5n");
// '+'?† n |
testANB("+n", "n");
testANB("n", "n");
testANB("N", "n");
testANB("+ n", "parse error");
// -n |
testANB("-n", "-n");
testANB("-N", "-n");
//
// <ndashdigit-dimension> |
testANB("5n-5", "5n-5");
// '+'?† <ndashdigit-ident> |
testANB("+n-5", "n-5");
testANB("n-5", "n-5");
testANB("+ n-5", "parse error");
// <dashndashdigit-ident> |
testANB("-n-5", "-n-5");
//
// <n-dimension> <signed-integer> |
testANB("5n +5", "5n+5");
testANB("5n -5", "5n-5");
// '+'?† n <signed-integer> |
testANB("+n +5", "n+5");
testANB("n +5", "n+5");
testANB("+n -5", "n-5");
testANB("+ n +5", "parse error");
testANB("n 5", "parse error");
// -n <signed-integer> |
testANB("-n +5", "-n+5");
testANB("-n -5", "-n-5");
testANB("-n 5", "parse error");
//
// <ndash-dimension> <signless-integer> |
testANB("5n- 5", "5n-5");
testANB("5n- -5", "parse error");
testANB("5n- +5", "parse error");
testANB("-5n- 5", "-5n-5");
// '+'?† n- <signless-integer> |
testANB("+n- 5", "n-5");
testANB("n- 5", "n-5");
testANB("+ n- 5", "parse error");
testANB("n- +5", "parse error");
testANB("n- -5", "parse error");
// -n- <signless-integer> |
testANB("-n- 5", "-n-5");
testANB("-n- +5", "parse error");
testANB("-n- -5", "parse error");
//
// <n-dimension> ['+' | '-'] <signless-integer>
testANB("5n + 5", "5n+5");
testANB("5n - 5", "5n-5");
testANB("5n + +5", "parse error");
testANB("5n + -5", "parse error");
testANB("5n - +5", "parse error");
testANB("5n - -5", "parse error");
// '+'?† n ['+' | '-'] <signless-integer> |
testANB("+n + 5", "n+5");
testANB("n + 5", "n+5");
testANB("+ n + 5", "parse error");
testANB("+n - 5", "n-5");
testANB("+n + +5", "parse error");
testANB("+n + -5", "parse error");
testANB("+n - +5", "parse error");
testANB("+n - -5", "parse error");
// -n ['+' | '-'] <signless-integer>
testANB("-n + 5", "-n+5");
testANB("-n - 5", "-n-5");
testANB("-n + +5", "parse error");
testANB("-n + -5", "parse error");
testANB("-n - +5", "parse error");
testANB("-n - -5", "parse error");
/* Swapped ordering is invalid */
testANB("1 - n", "parse error");
testANB("0 - n", "parse error");
testANB("-1 + n", "parse error");
/* Odd space usage */
testANB("2 n + 2", "parse error");
testANB("- 2n", "parse error");
testANB("+ 2n", "parse error");
testANB("+2 n", "parse error");
</script>

View file

@ -0,0 +1,62 @@
<!doctype html>
<title>An+B Serialization</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
foo { color: blue; }
</style>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#serializing-anb">
<script>
function roundtripANB(str) {
const rule = document.styleSheets[0].cssRules[0];
rule.selectorText = "foo";
rule.selectorText = `:nth-child(${str})`;
// Check for parse error.
if(rule.selectorText == "foo") return "parse error";
return rule.selectorText.slice(11, -1);
}
function testANB(input, expected) {
test(()=>{
assert_equals(roundtripANB(input), expected);
}, `"${input}" becomes "${expected}"`);
}
/* A is 0, or omitted */
testANB("1", "1");
testANB("+1", "1");
testANB("-1", "-1");
testANB("0n + 0", "0");
testANB("0n + 1", "1");
testANB("0n - 1", "-1");
/* A is 1 */
testANB("1n", "n");
testANB("1n - 0", "n");
testANB("1n + 1", "n+1");
testANB("1n - 1", "n-1");
/* A is -1 */
testANB("-1n", "-n");
testANB("-1n - 0", "-n");
testANB("-1n + 1", "-n+1");
testANB("-1n - 1", "-n-1");
/* A is implied via + or - */
testANB("+n+1", "n+1");
testANB("-n-1", "-n-1");
/* B is 0 */
testANB("n + 0", "n");
testANB("n - 0", "n");
/* A & B both nonzero */
testANB("2n + 2", "2n+2");
testANB("-2n - 2", "-2n-2");
</script>

View file

@ -0,0 +1,60 @@
<!doctype html>
<title>Inclusive Ranges</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
foo { z-index: 0; }
</style>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#digit">
<link rel=help href="https://drafts.csswg.org/css-syntax/#non-printable-code-point">
<script>
function roundtripIdent(str) {
const rule = document.styleSheets[0].cssRules[0];
rule.selectorText = "original-ident";
rule.selectorText = str;
// Check for parse error.
if(rule.selectorText == "original-ident") return "parse error";
return rule.selectorText;
}
function roundtripInteger(str) {
const rule = document.styleSheets[0].cssRules[0];
rule.style.zIndex = "12345";
rule.style.zIndex = str;
// Check for parse error.
if(rule.style.zIndex == "12345") return "parse error";
return rule.style.zIndex;
}
function testInteger(input, expected) {
test(()=>{
assert_equals(roundtripInteger(input), expected);
}, `"${input}" becomes "${expected}"`);
}
function testIdent(input, expected) {
test(()=>{
assert_equals(roundtripIdent(input), expected);
}, `"${input}" becomes "${expected}"`);
}
/* Digits are the inclusive range 0-9 */
for(var i = 0; i <= 9; i++) {
testInteger(i+"", i+"");
}
/* Non-printables are the inclusive ranges 0-8, b, e-1f, or 7f */
// 0 never shows up due to preprocessing, so start at 1
for(var i = 1; i <= 8; i++) {
testIdent("foo"+String.fromCodePoint(i), "parse error");
}
testIdent("foo"+String.fromCodePoint(0xb), "parse error");
for(var i = 0xe; i <= 0x1f; i++) {
testIdent("foo"+String.fromCodePoint(i), "parse error");
}
testIdent("foo" + String.fromCodePoint(0x7f), "parse error");
</script>

View file

@ -0,0 +1,46 @@
<!doctype html>
<title>Input Preprocessing</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
foo { color: blue; }
</style>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#input-preprocessing">
<script>
function roundtripIdent(str) {
const rule = document.styleSheets[0].cssRules[0];
rule.selectorText = "original-ident";
rule.selectorText = str;
// Check for parse error.
if(rule.selectorText == "original-ident") return "parse error";
return rule.selectorText;
}
function testParsing(input, expected) {
test(()=>{
assert_equals(roundtripIdent(input), expected);
}, `"${input}" becomes "${expected}"`);
}
/* Can't figure out how to test the newline normalization... */
/* NULL becomes FFFD */
testParsing("foo\x00", "foo\ufffd");
testParsing("f\x00oo", "f\ufffdoo");
testParsing("\x00foo", "\ufffdfoo");
testParsing("\x00", "\ufffd");
testParsing("\x00\x00\x00", "\ufffd\ufffd\ufffd");
/* surrogates become FFFD */
testParsing("foo\ud800", "foo\ufffd");
testParsing("f\ud800oo", "f\ufffdoo");
testParsing("\ud800foo", "\ufffdfoo");
testParsing("\ud800", "\ufffd");
testParsing("\ud800\ud800\ud800", "\ufffd\ufffd\ufffd");
</script>

View file

@ -0,0 +1,36 @@
<!doctype html>
<title>Unclosed Constructs Are Valid</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#rule-defs">
<!--
Tests that unclosed constructs are valid and match grammars,
because grammar-matching only sees the "block",
not the opening/closing characters themselves.
-->
<script>
function validSelector(str) {
try {
document.querySelector(str);
return true;
} catch(e) {
return false;
}
}
function shouldBeValid(str) {
test(()=>{
assert_true(validSelector(str));
}, `"${str}" is a valid selector`)
}
shouldBeValid("[foo]");
shouldBeValid("[foo");
shouldBeValid(":nth-child(1)");
shouldBeValid(":nth-child(1");
</script>

View file

@ -0,0 +1,62 @@
<!doctype html>
<title>CSS Whitespace</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<meta name="author" title="Tab Atkins-Bittner">
<link rel=help href="https://drafts.csswg.org/css-syntax/#whitespace">
<div class=a><b></b></div>
<div id=foo></div>
<!--
CSS's definition of "whitespace" matches HTML,
and includes only the five ASCII characters
U+0009, U+000A, U+000C, U+000D, and U+0020.
The rest of Unicode's whitespace characters,
many of which are recognized as whitespace by JS,
are not valid whitespace in CSS.
-->
<script>
function isWhitespace(codepoint) {
const char = String.fromCodePoint(codepoint);
const codepointName = "U+" + codepoint.toString(16).padStart(4, "0");
test(()=>{
const withSpace = document.querySelector(".a b");
const withChar = document.querySelector(`.a${char}b`);
assert_equals(withSpace, withChar);
}, `${codepointName} is CSS whitespace`);
}
function isNotWhitespace(codepoint) {
const char = String.fromCodePoint(codepoint);
const codepointName = "U+" + codepoint.toString(16).padStart(4, "0");
test(()=>{
const withSpace = document.querySelector(".a b");
document.querySelector("#foo").setAttribute("class", `.a${char}b`);
try {
var withChar = document.querySelector(`.a${char}b`);
} catch(e) {
assert_true(true, `${codepointName} isn't valid in a selector at all`);
return;
}
assert_not_equals(withSpace, withChar);
}, `${codepointName} is *not* CSS whitespace`);
}
// CSS Whitespace characters
var whitespace = [0x9, 0xa, 0xc, 0xd, 0x20];
// Unicode Whitespace characters not recognized by CSS
// https://en.wikipedia.org/wiki/Whitespace_character#Unicode
var notWhitespace = [0xb, 0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x2928, 0x2029, 0x202f, 0x205f, 0x3000, 0x180e, 0x200b, 0x200c, 0x200d, 0x2060, 0xfeff];
for(var codepoint of whitespace) {
isWhitespace(codepoint);
}
for(var codepoint of notWhitespace) {
isNotWhitespace(codepoint);
}
</script>

View file

@ -6,6 +6,7 @@
<link rel="author" title="Marc Bourlon" href="mailto:marc@bourlon.com">
<link rel="help" href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths">
<link rel="match" href="reference/vh_not_refreshing_on_chrome-ref.html">
<meta charset="UTF-8">
<meta name="assert" content="vh-based dimension doesn't change when the element's other dimension doesn't change.">
<!-- This test exhibits a bug for Chrome 19.0.1084.56 / Mac OS X 10.6.8 -->
<script src="/common/reftest-wait.js"></script>

View file

@ -3,6 +3,7 @@
<!-- Submitted from TestTWF Paris -->
<head>
<title>CSS Values and Units Test: Viewport units in scaled viewport</title>
<meta charset="UTF-8">
<meta name="assert" content="viewport relative units scale with viewport.">
<link rel="author" title="Emil A Eklund" href="mailto:eae@chromium.org">
<link rel="help" href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths">

View file

@ -2,6 +2,7 @@
<html>
<head>
<title>CSS Values and Units Test: Checks viewport units against CSS 2.1 properties and the CSSOM</title>
<meta charset="UTF-8">
<meta name="assert" content="Testing what happens when one applies and rereads viewport unit lengths to CSS 2.1 properties that accept length values" />
<link rel="author" title="Christian Schaefer" href="mailto:schaepp@gmx.de">
<link rel="help" href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths">

View file

@ -23,11 +23,11 @@ promise_test(async t => {
{types: ['feature-policy-violation']}).observe();
});
try {
await navigator.xr.requestDevice();
await navigator.xr.supportsSessionMode('inline');
} catch (err) {
// If no XR devices are available, requestDevice() will throw NotFoundError,
// but the report should be generated anyway.
assert_equals(err.name, 'NotFoundError');
// If no XR devices are available, supportsSessionMode() will reject with a
// NotSupportedError, but the report should be generated anyway.
assert_equals(err.name, 'NotSupportedError');
}
check_report_format(await report);
}, "XR report only mode");

View file

@ -22,7 +22,7 @@ promise_test(async (t) => {
new ReportingObserver((reports, observer) => resolve([reports, observer]),
{types: ['feature-policy-violation']}).observe();
});
await promise_rejects(t, 'SecurityError', navigator.xr.requestDevice(),
await promise_rejects(t, 'SecurityError', navigator.xr.supportsSessionMode('inline'),
"XR device access should not be allowed in this document.");
const [reports, observer] = await report;
check_report_format(reports, observer);

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<!---
Tentative test against:
https://github.com/whatwg/fetch/pull/853
-->
<meta charset="utf-8">
<title>Tests Stale While Revalidate is not executed for fetch API</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async (test) => {
const response = await fetch(`stale-script.py`);
const response2 = await fetch(`stale-script.py`);
assert_not_equals(response.headers.get('Token'), response2.headers.get('Token'));
}, 'Second fetch does not return same response');
</script>

View file

@ -0,0 +1,20 @@
def main(request, response):
cookie = request.cookies.first("Count", None)
count = 0
if cookie != None:
count = int(cookie.value)
if request.GET.first("query", None) != None:
headers = [("Count", count)]
content = ""
return 200, headers, content
else:
count = count + 1
content = "body { background: rgb(0, 128, 0); }"
if count > 1:
content = "body { background: rgb(255, 0, 0); }"
headers = [("Content-Type", "text/css"),
("Set-Cookie", "Count={}".format(count)),
("Cache-Control", "private, max-age=0, stale-while-revalidate=10")]
return 200, headers, content

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<!---
Tentative test against:
https://github.com/whatwg/fetch/pull/853
-->
<meta charset="utf-8">
<title>Tests Stale While Revalidate works for css</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
async_test(t => {
window.onload = t.step_func(() => {
step_timeout(() => {
assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)");
var link2 = document.createElement("link");
link2.onload = t.step_func(() => {
assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)");
var checkResult = () => {
// We poll because we don't know when the revalidation will occur.
fetch("stale-css.py?query").then(t.step_func((response) => {
var count = response.headers.get("Count");
if (count == '2') {
t.done();
} else {
t.step_timeout(checkResult, 25);
}
}));
};
t.step_timeout(checkResult, 25);
});
link2.rel = "stylesheet";
link2.type = "text/css";
link2.href = "stale-css.py";
document.body.appendChild(link2);
}, 0);
});
}, 'Cache returns stale resource');
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "stale-css.py";
document.body.appendChild(link);
</script>
</body>

View file

@ -0,0 +1,30 @@
import os.path
def main(request, response):
cookie = request.cookies.first("Count", None)
count = 0
if cookie != None:
count = int(cookie.value)
if request.GET.first("query", None) != None:
headers = [("Count", count)]
content = ""
return 200, headers, content
else:
count = count + 1
filename = "green-16x16.png"
if cookie > 1:
filename = "green-256x256.png"
path = os.path.join(os.path.dirname(__file__), "../../images", filename)
body = open(path, "rb").read()
response.add_required_headers = False
response.writer.write_status(200)
response.writer.write_header("content-length", len(body))
response.writer.write_header("Cache-Control", "private, max-age=0, stale-while-revalidate=10")
response.writer.write_header("content-type", "image/png")
response.writer.write_header("Set-Cookie", "Count={}".format(count))
response.writer.end_headers()
response.writer.write(body)

View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<!---
Tentative test against:
https://github.com/whatwg/fetch/pull/853
-->
<meta charset="utf-8">
<title>Tests Stale While Revalidate works for images</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<!--
Use a child document to load the second stale image into because
an image loaded into the same document will skip cache-control headers.
See: https://html.spec.whatwg.org/#the-list-of-available-images
-->
<iframe id="child" srcdoc=""></iframe>
<script>
async_test(t => {
window.onload = t.step_func(() => {
step_timeout(() => {
assert_equals(document.getElementById("firstimage").width, 16, "Width is 16");
var childDocument = document.getElementById('child').contentDocument;
var img2 = childDocument.createElement("img");
img2.onload = t.step_func(() => {
assert_equals(img2.width, 16, "image dimension");
var checkResult = () => {
// We poll because we don't know when the revalidation will occur.
fetch("stale-image.py?query").then(t.step_func((response) => {
var count = response.headers.get("Count");
if (count == '2') {
t.done();
} else {
t.step_timeout(checkResult, 25);
}
}));
};
t.step_timeout(checkResult, 25);
});
img2.src = "stale-image.py";
childDocument.body.appendChild(img2);
}, 0);
});
}, 'Cache returns stale resource');
var img = document.createElement("img");
img.src = "stale-image.py";
img.id = "firstimage";
document.body.appendChild(img);
</script>
</body>

View file

@ -0,0 +1,25 @@
import random, string, datetime
def token():
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(20))
def main(request, response):
cookie = request.cookies.first("Count", None)
count = 0
if cookie != None:
count = int(cookie.value)
if request.GET.first("query", None) != None:
headers = [("Count", count)]
content = ""
return 200, headers, content
else:
count = count + 1
unique_id = token()
headers = [("Content-Type", "text/javascript"),
("Cache-Control", "private, max-age=0, stale-while-revalidate=10"),
("Set-Cookie", "Count={}".format(count)),
("Token", unique_id)]
content = "report('{}')".format(unique_id)
return 200, headers, content

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<!---
Tentative test against:
https://github.com/whatwg/fetch/pull/853
-->
<meta charset="utf-8">
<title>Tests Stale While Revalidate works for scripts</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
var last_modified;
var last_modified_count = 0;
// The script will call report via a uniquely generated ID on the subresource.
// If it is a cache hit the ID will be the same and the test will pass.
function report(mod) {
if (!last_modified) {
last_modified = mod;
last_modified_count = 1;
} else if (last_modified == mod) {
last_modified_count++;
}
}
async_test(t => {
window.onload = t.step_func(() => {
step_timeout(() => {
var script = document.createElement("script");
script.src = "stale-script.py";
document.body.appendChild(script);
script.onload = t.step_func(() => {
assert_equals(last_modified_count, 2, "last modified");
var checkResult = () => {
// We poll because we don't know when the revalidation will occur.
fetch("stale-script.py?query").then(t.step_func((response) => {
var count = response.headers.get("Count");
if (count == '2') {
t.done();
} else {
t.step_timeout(checkResult, 25);
}
}));
};
t.step_timeout(checkResult, 25);
});
}, 0);
});
}, 'Cache returns stale resource');
var script = document.createElement("script");
script.src = "stale-script.py";
document.body.appendChild(script);
</script>
</body>

View file

@ -7,3 +7,7 @@
interface AmbientLightSensor : Sensor {
readonly attribute double? illuminance;
};
dictionary AmbientLightReadingValues {
required double? illuminance;
};

View file

@ -20,22 +20,22 @@ dictionary LayoutOptions {
[Exposed=LayoutWorklet]
enum ChildDisplayType {
"block",
"block", // default - "blockifies" the child boxes.
"normal",
};
[Exposed=LayoutWorklet]
enum LayoutSizingMode {
"block-like",
"manual",
"block-like", // default - Sizing behaves like block containers.
"manual", // Sizing is specified by the web developer.
};
[Exposed=LayoutWorklet]
interface LayoutChild {
readonly attribute StylePropertyMapReadOnly styleMap;
IntrinsicSizesRequest intrinsicSizes();
LayoutFragmentRequest layoutNextFragment(LayoutConstraints constraints, ChildBreakToken breakToken);
Promise<IntrinsicSizes> intrinsicSizes();
Promise<LayoutFragment> layoutNextFragment(LayoutConstraintsOptions constraints, ChildBreakToken breakToken);
};
[Exposed=LayoutWorklet]
@ -57,7 +57,7 @@ interface IntrinsicSizes {
readonly attribute double maxContentSize;
};
[Constructor(optional LayoutConstraintsOptions options),Exposed=LayoutWorklet]
[Exposed=LayoutWorklet]
interface LayoutConstraints {
readonly attribute double availableInlineSize;
readonly attribute double availableBlockSize;
@ -74,9 +74,11 @@ interface LayoutConstraints {
readonly attribute any data;
};
enum BlockFragmentationType { "none", "page", "column", "region" };
dictionary LayoutConstraintsOptions {
double availableInlineSize = 0;
double availableBlockSize = 0;
double availableInlineSize;
double availableBlockSize;
double fixedInlineSize;
double fixedBlockSize;
@ -90,8 +92,6 @@ dictionary LayoutConstraintsOptions {
any data;
};
enum BlockFragmentationType { "none", "page", "column", "region" };
[Exposed=LayoutWorklet]
interface ChildBreakToken {
readonly attribute BreakType breakType;
@ -112,7 +112,7 @@ dictionary BreakTokenOptions {
enum BreakType { "none", "line", "column", "page", "region" };
[Exposed=LayoutWorklet]
interface LayoutEdgeSizes {
interface LayoutEdges {
readonly attribute double inlineStart;
readonly attribute double inlineEnd;
@ -124,26 +124,6 @@ interface LayoutEdgeSizes {
readonly attribute double block;
};
[Exposed=LayoutWorklet]
interface LayoutEdges {
readonly attribute LayoutEdgeSizes border;
readonly attribute LayoutEdgeSizes scrollbar;
readonly attribute LayoutEdgeSizes padding;
readonly attribute LayoutEdgeSizes all;
};
[Exposed=LayoutWorklet]
interface IntrinsicSizesRequest {
};
[Exposed=LayoutWorklet]
interface LayoutFragmentRequest {
};
typedef (IntrinsicSizesRequest or LayoutFragmentRequest)
LayoutFragmentRequestOrIntrinsicSizesRequest;
// This is the final return value from the author defined layout() method.
dictionary FragmentResultOptions {
double inlineSize = 0;
@ -154,6 +134,12 @@ dictionary FragmentResultOptions {
BreakTokenOptions breakToken = null;
};
[Constructor(FragmentResultOptions)]
interface FragmentResult {
readonly attribute double inlineSize;
readonly attribute double blockSize;
};
dictionary IntrinsicSizesResultOptions {
double maxContentSize;
double minContentSize;

View file

@ -28,3 +28,93 @@ interface SensorErrorEvent : Event {
dictionary SensorErrorEventInit : EventInit {
required DOMException error;
};
dictionary MockSensorConfiguration {
required MockSensorType mockSensorType;
boolean connected = true;
double? maxSamplingFrequency;
double? minSamplingFrequency;
};
dictionary MockSensor {
double maxSamplingFrequency;
double minSamplingFrequency;
double requestedSamplingFrequency;
};
enum MockSensorType {
"ambient-light",
"accelerometer",
"linear-acceleration",
"gravity",
"gyroscope",
"magnetometer",
"uncalibrated-magnetometer",
"absolute-orientation",
"relative-orientation",
"geolocation",
"proximity",
};
dictionary MockSensorReadingValues {
};
dictionary AmbientLightReadingValues {
required double? illuminance;
};
dictionary AccelerometerReadingValues {
required double? x;
required double? y;
required double? z;
};
dictionary LinearAccelerationReadingValues : AccelerometerReadingValues {
};
dictionary GravityReadingValues : AccelerometerReadingValues {
};
dictionary GyroscopeReadingValues {
required double? x;
required double? y;
required double? z;
};
dictionary MagnetometerReadingValues {
required double? x;
required double? y;
required double? z;
};
dictionary UncalibratedMagnetometerReadingValues {
required double? x;
required double? y;
required double? z;
required double? xBias;
required double? yBias;
required double? zBias;
};
dictionary AbsoluteOrientationReadingValues {
required FrozenArray<double>? quaternion;
};
dictionary RelativeOrientationReadingValues : AbsoluteOrientationReadingValues {
};
dictionary GeolocationReadingValues {
required double? latitude;
required double? longitude;
required double? altitude;
required double? accuracy;
required double? altitudeAccuracy;
required double? heading;
required double? speed;
};
dictionary ProximityReadingValues {
required double? distance;
required double? max;
required boolean? near;
};

View file

@ -3,8 +3,6 @@
// (https://github.com/tidoust/reffy-reports)
// Source: HTML Standard (https://html.spec.whatwg.org/)
// Example interface manually removed here, see https://github.com/tidoust/reffy/issues/129.
[Exposed=Window,
LegacyUnenumerableNamedProperties]
interface HTMLAllCollection {
@ -1524,6 +1522,7 @@ interface Window : EventTarget {
void postMessage(any message, optional WindowPostMessageOptions options);
};
Window includes GlobalEventHandlers;
Window includes WindowEventHandlers;
dictionary WindowPostMessageOptions : PostMessageOptions {
USVString targetOrigin = "/";
@ -1817,7 +1816,7 @@ interface mixin NavigatorID {
[Exposed=Window] readonly attribute DOMString vendorSub; // constant ""
};
partial interface NavigatorID {
partial interface mixin NavigatorID {
[Exposed=Window] boolean taintEnabled(); // constant false
[Exposed=Window] readonly attribute DOMString oscpu;
};
@ -2450,8 +2449,7 @@ partial interface Window {
[Replaceable, SameObject] readonly attribute External external;
};
[Exposed=Window,
NoInterfaceObject]
[Exposed=Window]
interface External {
void AddSearchProvider();
void IsSearchProviderInstalled();

View file

@ -92,7 +92,6 @@ interface PaymentAddress {
readonly attribute DOMString postalCode;
readonly attribute DOMString recipient;
readonly attribute DOMString region;
readonly attribute DOMString regionCode;
readonly attribute DOMString sortingCode;
readonly attribute FrozenArray<DOMString> addressLine;
};
@ -101,7 +100,6 @@ dictionary AddressInit {
DOMString country;
sequence<DOMString> addressLine;
DOMString region;
DOMString regionCode;
DOMString city;
DOMString dependentLocality;
DOMString postalCode;
@ -121,7 +119,6 @@ dictionary AddressErrors {
DOMString postalCode;
DOMString recipient;
DOMString region;
DOMString regionCode;
DOMString sortingCode;
};

View file

@ -9,6 +9,7 @@ partial interface HTMLVideoElement {
attribute EventHandler onenterpictureinpicture;
attribute EventHandler onleavepictureinpicture;
[CEReactions] attribute boolean autoPictureInPicture;
[CEReactions] attribute boolean disablePictureInPicture;
};

View file

@ -34,7 +34,7 @@ enum LandmarkType {
[Exposed=(Window,Worker),
Constructor(optional BarcodeDetectorOptions barcodeDetectorOptions)]
interface BarcodeDetector {
readonly attribute FrozenArray<BarcodeFormat> supportedFormats;
static Promise<sequence<BarcodeFormat>> getSupportedFormats();
Promise<sequence<DetectedBarcode>> detect(ImageBitmapSource image);
};

View file

@ -43,7 +43,7 @@ dictionary ModuleImportDescriptor {
interface Module {
static sequence<ModuleExportDescriptor> exports(Module moduleObject);
static sequence<ModuleImportDescriptor> imports(Module moduleObject);
static sequence<ArrayBuffer> customSections(Module moduleObject, USVString sectionName);
static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
};
[LegacyNamespace=WebAssembly, Constructor(Module module, optional object importObject), Exposed=(Window,Worker,Worklet)]

View file

@ -3,12 +3,6 @@
// (https://github.com/tidoust/reffy-reports)
// Source: Identifiers for WebRTC's Statistics API (https://w3c.github.io/webrtc-stats/)
dictionary RTCStats {
DOMHighResTimeStamp timestamp;
RTCStatsType type;
DOMString id;
};
enum RTCStatsType {
"codec",
"inbound-rtp",
@ -314,7 +308,7 @@ partial dictionary RTCIceCandidatePairStats {
unsigned long long priority;
};
partial dictionary RTCRTPStreamStats {
partial dictionary RTCRtpStreamStats {
DOMString mediaType;
double averageRTCPInterval;
};

View file

@ -9,8 +9,8 @@
<script nonce="abc">
window.addEventListener('load', t.step_func(function() {
verifyPreloadAndRTSupport();
verifyNumberOfDownloads("resources/dummy.js?without-nonce", 0);
verifyNumberOfDownloads("resources/dummy.js?with-nonce", 1);
verifyNumberOfDownloads("resources/dummy.js?from-header&without-nonce", 0);
verifyNumberOfDownloads("resources/dummy.js?from-header&with-nonce", 1);
t.done();
}));
</script>

View file

@ -1,3 +1,3 @@
Content-Security-Policy: script-src 'nonce-abc'
Link: </preload/resources/dummy.js?without-nonce>;rel=preload;as=script
Link: </preload/resources/dummy.js?with-nonce>;rel=preload;as=script;nonce=abc
Link: </preload/resources/dummy.js?from-header&without-nonce>;rel=preload;as=script
Link: </preload/resources/dummy.js?from-header&with-nonce>;rel=preload;as=script;nonce=abc

View file

@ -11,16 +11,16 @@
<script>
window.addEventListener("load", t.step_func(function() {
verifyPreloadAndRTSupport();
verifyNumberOfDownloads('resources/square.png?1x', 1);
verifyNumberOfDownloads('resources/square.png?2x', 0);
verifyNumberOfDownloads('resources/square.png?3x', 0);
verifyNumberOfDownloads('resources/square.png?base', 0);
verifyNumberOfDownloads('resources/square.png?200', 0);
verifyNumberOfDownloads('resources/square.png?400', 1);
verifyNumberOfDownloads('resources/square.png?800', 0);
verifyNumberOfDownloads('resources/square.png?150', 0);
verifyNumberOfDownloads('resources/square.png?300', 1);
verifyNumberOfDownloads('resources/square.png?600', 0);
verifyNumberOfDownloads('resources/square.png?from-header&1x', 1);
verifyNumberOfDownloads('resources/square.png?from-header&2x', 0);
verifyNumberOfDownloads('resources/square.png?from-header&3x', 0);
verifyNumberOfDownloads('resources/square.png?from-header&base', 0);
verifyNumberOfDownloads('resources/square.png?from-header&200', 0);
verifyNumberOfDownloads('resources/square.png?from-header&400', 1);
verifyNumberOfDownloads('resources/square.png?from-header&800', 0);
verifyNumberOfDownloads('resources/square.png?from-header&150', 0);
verifyNumberOfDownloads('resources/square.png?from-header&300', 1);
verifyNumberOfDownloads('resources/square.png?from-header&600', 0);
t.done();
}));
</script>

View file

@ -1,3 +1,3 @@
Link: <resources/square.png?1x>; rel=preload; as=image; imagesrcset="resources/square.png?2x 2x, resources/square.png?3x 3x"
Link: <resources/square.png?base>; rel=preload; as=image; imagesrcset="resources/square.png?200 200w, resources/square.png?400 400w, resources/square.png?800 800w"; imagesizes=400px
Link: <resources/square.png?base>; rel=preload; as=image; imagesrcset="resources/square.png?150 150w, resources/square.png?300 300w, resources/square.png?600 600w"; imagesizes="(min-width: 300px) 300px, 150px"
Link: <resources/square.png?from-header&1x>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&2x 2x, resources/square.png?from-header&3x 3x"
Link: <resources/square.png?from-header&base>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&200 200w, resources/square.png?from-header&400 400w, resources/square.png?from-header&800 800w"; imagesizes=400px
Link: <resources/square.png?from-header&base>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&150 150w, resources/square.png?from-header&300 300w, resources/square.png?from-header&600 600w"; imagesizes="(min-width: 300px) 300px, 150px"

View file

@ -41,7 +41,7 @@ function onload_test() {
test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
if(!window.isSecureConnection) {
test_equals(entry.secureConnectionStart, 0, 'secureConnectStart should be zero');
test_equals(entry.secureConnectionStart, 0, 'secureConnectionStart should be zero');
}
test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')

View file

@ -40,7 +40,7 @@ function onload_test() {
const entry = entries[1];
test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectionStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
}

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Resource Timing connection reuse</title>
<link rel="author" title="Google" href="http://www.google.com/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({explicit_done: true});
let iframe;
let d;
let body;
// Explicitly test the namespace before we start testing.
test_namespace('getEntriesByType');
function setup_iframe() {
iframe = document.getElementById('frameContext');
d = iframe.contentWindow.document;
iframe.addEventListener('load', onload_test, false);
}
function onload_test() {
const entries = iframe.contentWindow.performance.getEntriesByType('resource');
// When a persistent connection is used, follow-on resources should be included as PerformanceResourceTiming objects.
test_equals(entries.length, 2, 'There should be 2 PerformanceEntries');
if (entries.length >= 2) {
// When a persistent connection is used, for the resource that reuses the socket, connectStart and connectEnd should have the same value as fetchStart.
const entry = entries[1];
test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
// secureConnectionStart is the same as fetchStart since the subresource is fetched over https
test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectionStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
}
done();
}
window.setup_iframe = setup_iframe;
</script>
</head>
<body>
<h1>Description</h1>
<p>This test validates that connectStart and connectEnd are the same when a connection is reused (e.g. when a persistent connection is used).</p>
<div id="log"></div>
<iframe id="frameContext" src="resources/fake_responses_https.sub.html"></iframe>
</body>
</html>

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Resource Timing connection reuse</title>
<link rel="author" title="Google" href="http://www.google.com/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({explicit_done: true});
let iframe;
let d;
let body;
// Explicitly test the namespace before we start testing.
test_namespace('getEntriesByType');
function setup_iframe() {
iframe = document.getElementById('frameContext');
d = iframe.contentWindow.document;
iframe.addEventListener('load', onload_test, false);
}
function onload_test() {
const entries = iframe.contentWindow.performance.getEntriesByType('resource');
// When a persistent connection is used, follow-on resources should be included as PerformanceResourceTiming objects.
test_equals(entries.length, 2, 'There should be 2 PerformanceEntries');
if (entries.length >= 2) {
// When a persistent connection is used, for the resource that reuses the socket, connectStart and connectEnd should have the same value as fetchStart.
const entry = entries[1];
test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
// secureConnectionStart is the same as fetchStart since the subresource is eventually redirected to https.
test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectionStart and fetchStart should be the same');
test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
}
done();
}
window.setup_iframe = setup_iframe;
</script>
</head>
<body>
<h1>Description</h1>
<p>This test validates that connectStart and connectEnd are the same when a connection is reused (e.g. when a persistent connection is used).</p>
<div id="log"></div>
<iframe id="frameContext" src="resources/fake_responses_https_redirect.sub.html"></iframe>
</body>
</html>

View file

@ -2,13 +2,20 @@
def main(request, response):
tag = request.GET.first("tag", None)
redirect = request.GET.first("redirect", None)
match = request.headers.get("If-None-Match", None)
date = request.GET.first("date", "")
modified = request.headers.get("If-Modified-Since", None)
response.headers.set("Access-Control-Allow-Origin", "*");
response.headers.set("Timing-Allow-Origin", "*");
if tag:
response.headers.set("ETag", '"%s"' % tag)
elif date:
response.headers.set("Last-Modified", date)
if redirect:
response.headers.set("Location", redirect)
response.status = (302, "Moved")
return ""
if ((match is not None and match == tag) or
(modified is not None and modified == date)):
@ -16,4 +23,4 @@ def main(request, response):
return ""
else:
response.headers.set("Content-Type", "text/plain")
return "MAYBE NOT"
return "MAYBE NOT"

View file

@ -0,0 +1,18 @@
<body>
<script>
function request() {
var client = new XMLHttpRequest,
baseurl = "https://{{hosts[][www]}}:{{ports[https][0]}}{{location[pathname]}}",
url = new URL("fake_responses.py", baseurl).href;
client.open("GET", url, false)
client.send(null)
client.open("GET", url, false)
client.send(null)
}
if(window.parent.setup_iframe) {
window.parent.setup_iframe();
request();
}
</script>
</body>

View file

@ -0,0 +1,20 @@
<body>
<script>
function request() {
var client = new XMLHttpRequest,
baseurl = "http://{{hosts[][www]}}:{{ports[http][0]}}{{location[pathname]}}",
subresource = "fake_responses.py",
redirecturl = new URL(subresource, "https://{{hosts[][www]}}:{{ports[https][0]}}{{location[pathname]}}").href,
url = new URL(subresource + "?redirect=" + redirecturl, baseurl).href;
client.open("GET", url, false)
client.send(null)
client.open("GET", url, false)
client.send(null)
}
if(window.parent.setup_iframe) {
window.parent.setup_iframe();
request();
}
</script>
</body>

View file

@ -0,0 +1,177 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test clients.get(resultingClientId)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
const scope = "resources/";
let worker;
// Setup. Keep this as the first promise_test.
promise_test(async (t) => {
const registration = await service_worker_unregister_and_register(
t, 'resources/get-resultingClientId-worker.js',
scope);
worker = registration.installing;
await wait_for_state(t, worker, 'activated');
}, 'global setup');
// Sends |command| to the worker and returns a promise that resolves to its
// response. There should only be one inflight command at a time.
async function sendCommand(command) {
const saw_message = new Promise((resolve) => {
navigator.serviceWorker.onmessage = (event) => {
resolve(event.data);
};
});
worker.postMessage(command);
return saw_message;
}
// Wrapper for 'startTest' command. Tells the worker a test is starting,
// so it resets state and keeps itself alive until 'finishTest'.
async function startTest(t) {
const result = await sendCommand({command: 'startTest'});
assert_equals(result, 'ok', 'startTest');
t.add_cleanup(async () => {
return finishTest();
});
}
// Wrapper for 'finishTest' command.
async function finishTest() {
const result = await sendCommand({command: 'finishTest'});
assert_equals(result, 'ok', 'finishTest');
}
// Wrapper for 'getResultingClient' command. Tells the worker to return
// clients.get(event.resultingClientId) for the navigation that occurs
// during this test.
//
// The return value describes how clients.get() settled. It also includes
// |queriedId| which is the id passed to clients.get() (the resultingClientId
// in this case).
//
// Example value:
// {
// queriedId: 'abc',
// promiseState: fulfilled,
// promiseValue: client,
// client: {
// id: 'abc',
// url: '//example.com/client'
// }
// }
async function getResultingClient() {
return sendCommand({command: 'getResultingClient'});
}
// Wrapper for 'getClient' command. Tells the worker to return
// clients.get(|id|). The return value is as in the getResultingClient()
// documentation.
async function getClient(id) {
return sendCommand({command: 'getClient', id: id});
}
// Navigates to |url|. Returns the result of clients.get() on the
// resultingClientId.
async function navigateAndGetResultingClient(t, url) {
const resultPromise = getResultingClient();
const frame = await with_iframe(url);
t.add_cleanup(() => {
frame.remove();
});
const result = await resultPromise;
const resultingClientId = result.queriedId;
// First test clients.get(event.resultingClientId) inside the fetch event. The
// behavior of this is subtle due to the use of iframes and about:blank
// replacement. The spec probably requires that it resolve to the original
// about:blank client, and that later that client should be discarded after
// load if the load was to another origin. Implementations might differ. For
// now, this test just asserts that the promise resolves. See
// https://github.com/w3c/ServiceWorker/issues/1385.
assert_equals(result.promiseState, 'fulfilled',
'get(event.resultingClientId) in the fetch event should fulfill');
// Test clients.get() on the previous resultingClientId again. By this
// time the load finished, so it's more straightforward how this promise
// should settle. Return the result of this promise.
return await getClient(resultingClientId);
}
// Test get(resultingClientId) in the basic same-origin case.
promise_test(async (t) => {
await startTest(t);
const url = new URL('resources/empty.html', window.location);
const result = await navigateAndGetResultingClient(t, url);
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
assert_equals(result.promiseValue, 'client', 'promiseValue');
assert_equals(result.client.url, url.href, 'client.url',);
assert_equals(result.client.id, result.queriedId, 'client.id');
}, 'get(resultingClientId) for same-origin document');
// Test get(resultingClientId) when the response redirects to another origin.
promise_test(async (t) => {
await startTest(t);
// Navigate to a URL that redirects to another origin.
const base_url = new URL('.', window.location);
const host_info = get_host_info();
const other_origin_url = new URL(base_url.pathname + 'resources/empty.html',
host_info['HTTPS_REMOTE_ORIGIN']);
const url = new URL('resources/empty.html', window.location);
const pipe = `status(302)|header(Location, ${other_origin_url})`;
url.searchParams.set('pipe', pipe);
// The original reserved client should have been discarded on cross-origin
// redirect.
const result = await navigateAndGetResultingClient(t, url);
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
}, 'get(resultingClientId) on cross-origin redirect');
// Test get(resultingClientId) when the document is sandboxed to a unique
// origin using a CSP HTTP response header.
promise_test(async (t) => {
await startTest(t);
// Navigate to a URL that has CSP sandboxing set in the HTTP response header.
const url = new URL('resources/empty.html', window.location);
const pipe = 'header(Content-Security-Policy, sandbox)';
url.searchParams.set('pipe', pipe);
// The original reserved client should have been discarded upon loading
// the sandboxed document.
const result = await navigateAndGetResultingClient(t, url);
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
}, 'get(resultingClientId) for document sandboxed by CSP header');
// Test get(resultingClientId) when the document is sandboxed with
// allow-same-origin.
promise_test(async (t) => {
await startTest(t);
// Navigate to a URL that has CSP sandboxing set in the HTTP response header.
const url = new URL('resources/empty.html', window.location);
const pipe = 'header(Content-Security-Policy, sandbox allow-same-origin)';
url.searchParams.set('pipe', pipe);
// The client should be the original reserved client, as it's same-origin.
const result = await navigateAndGetResultingClient(t, url);
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
assert_equals(result.promiseValue, 'client', 'promiseValue');
assert_equals(result.client.url, url.href, 'client.url',);
assert_equals(result.client.id, result.queriedId, 'client.id');
}, 'get(resultingClientId) for document sandboxed by CSP header with allow-same-origin');
// Cleanup. Keep this as the last promise_test.
promise_test(async (t) => {
return service_worker_unregister(t, scope);
}, 'global cleanup');
</script>

View file

@ -0,0 +1,107 @@
// This worker expects a fetch event for a navigation and messages back the
// result of clients.get(event.resultingClientId).
// Resolves when the test finishes.
let testFinishPromise;
let resolveTestFinishPromise;
let rejectTestFinishPromise;
// Resolves to clients.get(event.resultingClientId) from the fetch event.
let getPromise;
let resolveGetPromise;
let rejectGetPromise;
let resultingClientId;
function startTest() {
testFinishPromise = new Promise((resolve, reject) => {
resolveTestFinishPromise = resolve;
rejectTestFinishPromise = reject;
});
getPromise = new Promise((resolve, reject) => {
resolveGetPromise = resolve;
rejectGetPromise = reject;
});
}
async function describeGetPromiseResult(promise) {
const result = {};
await promise.then(
(client) => {
result.promiseState = 'fulfilled';
if (client === undefined) {
result.promiseValue = 'undefinedValue';
} else if (client instanceof Client) {
result.promiseValue = 'client';
result.client = {
id: client.id,
url: client.url
};
} else {
result.promiseValue = 'unknown';
}
},
(error) => {
result.promiseState = 'rejected';
});
return result;
}
async function handleGetResultingClient(event) {
// Note that this message can arrive before |resultingClientId| is populated.
const result = await describeGetPromiseResult(getPromise);
// |resultingClientId| must be populated by now.
result.queriedId = resultingClientId;
event.source.postMessage(result);
};
async function handleGetClient(event) {
const id = event.data.id;
const result = await describeGetPromiseResult(self.clients.get(id));
result.queriedId = id;
event.source.postMessage(result);
};
self.addEventListener('message', (event) => {
if (event.data.command == 'startTest') {
startTest();
event.waitUntil(testFinishPromise);
event.source.postMessage('ok');
return;
}
if (event.data.command == 'finishTest') {
resolveTestFinishPromise();
event.source.postMessage('ok');
return;
}
if (event.data.command == 'getResultingClient') {
event.waitUntil(handleGetResultingClient(event));
return;
}
if (event.data.command == 'getClient') {
event.waitUntil(handleGetClient(event));
return;
}
});
async function handleFetch(event) {
try {
resultingClientId = event.resultingClientId;
const client = await self.clients.get(resultingClientId);
resolveGetPromise(client);
} catch (error) {
rejectGetPromise(error);
}
}
self.addEventListener('fetch', (event) => {
if (event.request.mode != 'navigate')
return;
event.waitUntil(handleFetch(event));
});

View file

@ -1,10 +1,10 @@
// Opens |url| in an iframe, establish a message channel with it, and waits for
// a message from the frame content. Returns a promise that resolves with the
// data of the message, or rejects on 2000ms timeout.
// data of the message, or rejects on 3000ms timeout.
function openSXGInIframeAndWaitForMessage(test_object, url, referrerPolicy) {
return new Promise(async (resolve, reject) => {
// We can't catch the network error on iframe. So we use the timer.
test_object.step_timeout(() => reject('timeout'), 2000);
test_object.step_timeout(() => reject('timeout'), 3000);
const frame = await withIframe(url, 'sxg_iframe', referrerPolicy);
const channel = new MessageChannel();

View file

@ -15,9 +15,9 @@ passenv =
HYPOTHESIS_PROFILE
[testenv:py27-flake8]
deps = -r requirements_flake8.txt
commands = flake8 --append-config=py27-flake8.ini {posargs}
deps = -rrequirements_flake8.txt
commands = flake8 --append-config={toxinidir}/py27-flake8.ini {posargs}
[testenv:py36-flake8]
deps = -r requirements_flake8.txt
commands = flake8 --append-config=py36-flake8.ini {posargs}
deps = -rrequirements_flake8.txt
commands = flake8 --append-config={toxinidir}/py36-flake8.ini {posargs}

View file

@ -171,7 +171,8 @@ class BrowserSetup(object):
return self.browser.install(venv.path, channel)
def install_requirements(self):
self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
if not self.venv.skip_virtualenv_setup:
self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
def setup(self, kwargs):
self.setup_kwargs(kwargs)
@ -563,7 +564,8 @@ def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
wptrunner_path = os.path.join(wpt_root, "tools", "wptrunner")
venv.install_requirements(os.path.join(wptrunner_path, "requirements.txt"))
if not venv.skip_virtualenv_setup:
venv.install_requirements(os.path.join(wptrunner_path, "requirements.txt"))
kwargs['browser_version'] = setup_cls.browser.version(binary=kwargs.get("binary"),
webdriver_binary=kwargs.get("webdriver_binary"))

View file

@ -17,6 +17,7 @@ def venv():
class Virtualenv(virtualenv.Virtualenv):
def __init__(self):
self.path = tempfile.mkdtemp()
self.skip_virtualenv_setup = False
def create(self):
return

View file

@ -357,7 +357,7 @@ def test_tests_affected_idlharness(capsys, manifest_dir):
wpt.main(argv=["tests-affected", "--metadata", manifest_dir, "%s~..%s" % (commit, commit)])
assert excinfo.value.code == 0
out, err = capsys.readouterr()
assert "webrtc/idlharness.https.window.js\n" == out
assert "webrtc-stats/idlharness.window.js\nwebrtc/idlharness.https.window.js\n" == out
@pytest.mark.slow # this updates the manifest

View file

@ -9,11 +9,13 @@ from tools.wpt.utils import call
logger = logging.getLogger(__name__)
class Virtualenv(object):
def __init__(self, path):
def __init__(self, path, skip_virtualenv_setup):
self.path = path
self.virtualenv = find_executable("virtualenv")
if not self.virtualenv:
raise ValueError("virtualenv must be installed and on the PATH")
self.skip_virtualenv_setup = skip_virtualenv_setup
if not skip_virtualenv_setup:
self.virtualenv = find_executable("virtualenv")
if not self.virtualenv:
raise ValueError("virtualenv must be installed and on the PATH")
@property
def exists(self):

View file

@ -43,6 +43,9 @@ def load_commands():
def parse_args(argv, commands):
parser = argparse.ArgumentParser()
parser.add_argument("--venv", action="store", help="Path to an existing virtualenv to use")
parser.add_argument("--skip-venv-setup", action="store_true",
dest="skip_venv_setup",
help="Whether to use the virtualenv as-is. Must set --venv as well")
parser.add_argument("--debug", action="store_true", help="Run the debugger in case of an exception")
subparsers = parser.add_subparsers(dest="command")
for command, props in iteritems(commands):
@ -77,15 +80,19 @@ def import_command(prog, command, props):
return script, parser
def setup_virtualenv(path, props):
def setup_virtualenv(path, skip_venv_setup, props):
if skip_venv_setup and path is None:
raise ValueError("Must set --venv when --skip-venv-setup is used")
should_skip_setup = path is not None and skip_venv_setup
if path is None:
path = os.path.join(wpt_root, "_venv")
venv = virtualenv.Virtualenv(path)
venv.start()
for name in props["install"]:
venv.install(name)
for path in props["requirements"]:
venv.install_requirements(path)
venv = virtualenv.Virtualenv(path, should_skip_setup)
if not should_skip_setup:
venv.start()
for name in props["install"]:
venv.install(name)
for path in props["requirements"]:
venv.install_requirements(path)
return venv
@ -105,7 +112,7 @@ def main(prog=None, argv=None):
props = commands[command]
venv = None
if props["virtualenv"]:
venv = setup_virtualenv(main_args.venv, props)
venv = setup_virtualenv(main_args.venv, main_args.skip_venv_setup, props)
script, parser = import_command(prog, command, props)
if parser:
if props["parse_known"]:

View file

@ -1,42 +0,0 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="trusted-types *">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<script>
// To test workers, we need to importScripts source files in the workers.
// Since the point of this test is to test blocking of importScripts, we need
// to set up one policy that will blindly pass through URLs for use in the test
// setup, and then have additional policies for the actual test cases.
//
// For the same reason we cannot use the otherwise preferred 'META: workers'
// tag, since the test setup that uses would be blocked as soon trusted types
// enforcement is enabled.
const test_setup_policy = TrustedTypes.createPolicy("hurrayanythinggoes", {
createScriptURL: x => new URL(x, location.href)
});
const test_url =
test_setup_policy.createScriptURL("WorkerGlobalScope-importScripts.https.js");
fetch_tests_from_worker(new Worker(test_url));
fetch_tests_from_worker(new SharedWorker(test_url));
// Cargo-culted from code generated from "META: worker".
if ('serviceWorker' in navigator) {
(async function() {
const scope = 'some/scope/for/this/test';
let reg = await navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
reg = await navigator.serviceWorker.register(test_url, {scope});
fetch_tests_from_worker(reg.installing);
})();
}
</script>
</body>

View file

@ -1,70 +0,0 @@
let test_setup_policy = TrustedTypes.createPolicy("hurrayanythinggoes", {
createScriptURL: x => new URL(x, location.href)
});
importScripts(test_setup_policy.createScriptURL("/resources/testharness.js"));
// Determine worker type (for better logging)
let worker_type = "unknown";
if (this.DedicatedWorkerGlobalScope !== undefined) {
worker_type = "dedicated worker";
} else if (this.SharedWorkerGlobalScope !== undefined) {
worker_type = "shared worker";
} else if (this.ServiceWorkerGlobalScope !== undefined) {
worker_type = "service worker";
}
const test_policy = TrustedTypes.createPolicy('xxx', {
createScriptURL: url => new URL(url.replace("play", "work"), this.location.href) });
test(t => {
self.result = "Fail";
let trusted_url = test_policy.createScriptURL(new URL("support/player.js", location.href));
assert_true(TrustedTypes.isScriptURL(trusted_url));
importScripts(trusted_url); // support/worker.js modifies self.result.
assert_equals(self.result, "Pass");
}, "importScripts with TrustedScriptURL works in " + worker_type);
test(t => {
let untrusted_url = "support/player.js";
assert_throws(new TypeError(),
function() { importScripts(untrusted_url) },
"importScripts(untrusted_url)");
}, "importScripts with untrusted URLs throws in " + worker_type);
test(t => {
assert_throws(new TypeError(),
function() { importScripts(null) },
"importScripts(null)");
}, "null is not a trusted script URL throws in " + worker_type);
test(t => {
self.result = "Fail";
let trusted_url = test_policy.createScriptURL(
new URL("support/player.js?variant1", location.href));
let trusted_url2 = test_policy.createScriptURL(
new URL("support/player.js?variant2", location.href));
importScripts(trusted_url, trusted_url2);
assert_equals(self.result, "Pass");
}, "importScripts with two URLs, both trusted, in " + worker_type);
test(t => {
let untrusted_url = "support/player.js?variant1";
let untrusted_url2 = "support/player.js?variant2";
assert_throws(new TypeError(),
function() { importScripts(untrusted_url, untrusted_url2) },
"importScripts(untrusted_url, untrusted_url2)");
}, "importScripts with two URLs, both strings, in " + worker_type);
test(t => {
let untrusted_url = "support/player.js";
let trusted_url = test_policy.createScriptURL(
new URL(untrusted_url, location.href));
assert_throws(new TypeError(),
function() { importScripts(untrusted_url, trusted_url) },
"importScripts(untrusted_url, trusted_url)");
}, "importScripts with two URLs, one trusted, in " + worker_type);
done();

View file

@ -1 +0,0 @@
Content-Security-Policy: trusted-types *

View file

@ -109,7 +109,7 @@ ALL_KEYS = getmembers(Keys, lambda x: type(x) == unicode)
ALL_EVENTS = {
"ADD": {
"code": "",
"code": "NumpadAdd",
"ctrl": False,
"key": "+",
"location": 3,
@ -496,7 +496,7 @@ ALL_EVENTS = {
"value": u"\ue023",
},
"PAGE_DOWN": {
"code": "",
"code": "PageDown",
"ctrl": False,
"key": "PageDown",
"location": 0,
@ -505,7 +505,7 @@ ALL_EVENTS = {
"value": u"\ue00f",
},
"PAGE_UP": {
"code": "",
"code": "PageUp",
"ctrl": False,
"key": "PageUp",
"location": 0,
@ -676,7 +676,7 @@ ALL_EVENTS = {
"value": u"\ue018",
},
"SEPARATOR": {
"code": "NumpadSubtract",
"code": "NumpadComma",
"ctrl": False,
"key": ",",
"location": 3,
@ -703,7 +703,7 @@ ALL_EVENTS = {
"value": u"\ue00d",
},
"SUBTRACT": {
"code": "",
"code": "NumpadSubtract",
"ctrl": False,
"key": "-",
"location": 3,

View file

@ -74,19 +74,19 @@
test(t => {
const candidate = new RTCIceCandidate({ sdpMid: 'audio' });
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, `new RTCIceCandidate({ sdpMid: 'audio' })`);
test(t => {
const candidate = new RTCIceCandidate({ sdpMLineIndex: 0 });
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, null, 'sdpMid');
assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, 'new RTCIceCandidate({ sdpMLineIndex: 0 })');
test(t => {
@ -95,10 +95,10 @@
sdpMLineIndex: 0
});
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, `new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })`);
test(t => {
@ -107,10 +107,10 @@
sdpMid: 'audio'
});
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, `new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }`);
test(t => {
@ -119,10 +119,10 @@
sdpMLineIndex: 0
});
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, null, 'sdpMid', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, `new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }`);
test(t => {
@ -131,10 +131,10 @@
sdpMid: 'audio'
});
assert_equals(candidate.candidate, candidateString);
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, candidateString, 'candidate');
assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, 'new RTCIceCandidate({ ... }) with valid candidate string and sdpMid');
test(t =>{
@ -144,10 +144,10 @@
sdpMid: 'audio'
});
assert_equals(candidate.candidate, arbitraryString);
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, arbitraryString, 'candidate');
assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, 'new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid');
test(t => {
@ -158,10 +158,10 @@
usernameFragment: 'test'
});
assert_equals(candidate.candidate, candidateString);
assert_equals(candidate.sdpMid, 'video');
assert_equals(candidate.sdpMLineIndex, 1);
assert_equals(candidate.usernameFragment, 'test');
assert_equals(candidate.candidate, candidateString, 'candidate');
assert_equals(candidate.sdpMid, 'video', 'sdpMid');
assert_equals(candidate.sdpMLineIndex, 1, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, 'test', 'usernameFragment');
}, 'new RTCIceCandidate({ ... }) with non default value for all fields');
@ -171,10 +171,10 @@
sdpMid: arbitraryString
});
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, arbitraryString);
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, arbitraryString, 'sdpMid');
assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, 'new RTCIceCandidate({ ... }) with invalid sdpMid');
@ -187,10 +187,10 @@
sdpMLineIndex: 65535
});
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 65535);
assert_equals(candidate.usernameFragment, null);
assert_equals(candidate.candidate, '', 'candidate');
assert_equals(candidate.sdpMid, null, 'sdpMid');
assert_equals(candidate.sdpMLineIndex, 65535, 'sdpMLineIndex');
assert_equals(candidate.usernameFragment, null, 'usernameFragment');
}, 'new RTCIceCandidate({ ... }) with invalid sdpMLineIndex');
</script>

View file

@ -177,6 +177,7 @@ test(t => {
const candidate1 = new RTCIceCandidate({
candidate: 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host',
sdpMid: '',
});
test(() => {
@ -191,7 +192,7 @@ test(() => {
const iceTransport = new RTCIceTransport();
assert_throws('OperationError',
() => iceTransport.addRemoteCandidate(
new RTCIceCandidate({ candidate: 'invalid' })));
new RTCIceCandidate({ candidate: 'invalid', sdpMid: '' })));
assert_array_equals(iceTransport.getRemoteCandidates(), []);
}, 'addRemoteCandidate() throws on invalid candidate');

View file

@ -0,0 +1,57 @@
["localStorage", "sessionStorage"].forEach(function(name) {
[9, "x"].forEach(function(key) {
test(function() {
var desc = {
value: "value",
};
var storage = window[name];
storage.clear();
assert_equals(storage[key], undefined);
assert_equals(storage.getItem(key), null);
assert_equals(Object.defineProperty(storage, key, desc), storage);
assert_equals(storage[key], "value");
assert_equals(storage.getItem(key), "value");
}, "Defining data property for key " + key + " on " + name);
test(function() {
var desc1 = {
value: "value",
};
var desc2 = {
value: "new value",
};
var storage = window[name];
storage.clear();
assert_equals(storage[key], undefined);
assert_equals(storage.getItem(key), null);
assert_equals(Object.defineProperty(storage, key, desc1), storage);
assert_equals(storage[key], "value");
assert_equals(storage.getItem(key), "value");
assert_equals(Object.defineProperty(storage, key, desc2), storage);
assert_equals(storage[key], "new value");
assert_equals(storage.getItem(key), "new value");
}, "Defining data property for key " + key + " on " + name + " twice");
test(function() {
var desc = {
value: {
toString: function() { return "value"; }
},
};
var storage = window[name];
storage.clear();
assert_equals(storage[key], undefined);
assert_equals(storage.getItem(key), null);
assert_equals(Object.defineProperty(storage, key, desc), storage);
assert_equals(storage[key], "value");
assert_equals(storage.getItem(key), "value");
}, "Defining data property with toString for key " + key + " on " + name);
});
});

View file

@ -0,0 +1,102 @@
["localStorage", "sessionStorage"].forEach(function(name) {
[9, "x"].forEach(function(key) {
test(function() {
var value = "value";
var storage = window[name];
storage.clear();
assert_equals(storage[key], undefined);
assert_equals(storage.getItem(key), null);
assert_equals(storage[key] = value, value);
assert_equals(storage[key], "value");
assert_equals(storage.getItem(key), "value");
}, "Setting property for key " + key + " on " + name);
test(function() {
var value = {
toString: function() { return "value"; }
};
var storage = window[name];
storage.clear();
assert_equals(storage[key], undefined);
assert_equals(storage.getItem(key), null);
assert_equals(storage[key] = value, value);
assert_equals(storage[key], "value");
assert_equals(storage.getItem(key), "value");
}, "Setting property with toString for key " + key + " on " + name);
test(function() {
Storage.prototype[key] = "proto";
this.add_cleanup(function() { delete Storage.prototype[key]; });
var value = "value";
var storage = window[name];
storage.clear();
assert_equals(storage[key], "proto");
assert_equals(storage.getItem(key), null);
assert_equals(storage[key] = value, value);
// Hidden because no [OverrideBuiltins].
assert_equals(storage[key], "proto");
assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
assert_equals(storage.getItem(key), "value");
}, "Setting property for key " + key + " on " + name + " with data property on prototype");
test(function() {
Storage.prototype[key] = "proto";
this.add_cleanup(function() { delete Storage.prototype[key]; });
var value = "value";
var storage = window[name];
storage.clear();
storage.setItem(key, "existing");
// Hidden because no [OverrideBuiltins].
assert_equals(storage[key], "proto");
assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
assert_equals(storage.getItem(key), "existing");
assert_equals(storage[key] = value, value);
assert_equals(storage[key], "proto");
assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
assert_equals(storage.getItem(key), "value");
}, "Setting property for key " + key + " on " + name + " with data property on prototype and existing item");
test(function() {
var calledSetter = [];
Object.defineProperty(Storage.prototype, key, {
"get": function() { return "proto getter"; },
"set": function(v) { calledSetter.push(v); },
configurable: true,
});
this.add_cleanup(function() { delete Storage.prototype[key]; });
var value = "value";
var storage = window[name];
storage.clear();
assert_equals(storage[key], "proto getter");
assert_equals(storage.getItem(key), null);
assert_equals(storage[key] = value, value);
// Property is hidden because no [OverrideBuiltins].
if (typeof key === "number") {
// P is an array index: call through to OrdinarySetWithOwnDescriptor()
assert_array_equals(calledSetter, [value]);
assert_equals(storage[key], "proto getter");
assert_equals(storage.getItem(key), null);
} else {
// P is not an array index: early return in [[Set]] step 2.
// https://github.com/heycam/webidl/issues/630
assert_equals(storage[key], "proto getter");
assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
assert_equals(storage.getItem(key), "value");
}
}, "Setting property for key " + key + " on " + name + " with accessor property on prototype");
});
});

View file

@ -1,19 +0,0 @@
<!DOCTYPE html>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="resources/webxr_util.js"></script>
<script>
xr_promise_test("navigator.xr.requestDevice returns a device", (t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive: true })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => {
t.step(() => {
assert_true(device != null);
assert_true(device instanceof XRDevice);
});
});
});
</script>
</body>

View file

@ -1,12 +0,0 @@
<!DOCTYPE html>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="resources/webxr_util.js"></script>
<script>
promise_test( (t) => {
return promise_rejects(t, 'NotFoundError', navigator.xr.requestDevice());
}, "navigator.xr.requestDevice properly rejects when there are 0 devices");
</script>
</body>

View file

@ -26,7 +26,6 @@ function xr_promise_test(name, func, properties) {
// Requires a webglCanvas on the page.
function xr_session_promise_test(
name, func, fakeDeviceInit, sessionOptions, properties) {
let testDevice;
let testDeviceController;
let testSession;
@ -44,16 +43,12 @@ function xr_session_promise_test(
XRTest.simulateDeviceConnection(fakeDeviceInit)
.then((controller) => {
testDeviceController = controller;
return navigator.xr.requestDevice();
})
.then((device) => {
testDevice = device;
return gl.makeXRCompatible();
})
.then(() => new Promise((resolve, reject) => {
// Perform the session request in a user gesture.
XRTest.simulateUserActivation(() => {
testDevice.requestSession(sessionOptions)
navigator.xr.requestSession(sessionOptions)
.then((session) => {
testSession = session;
// Session must have a baseLayer or frame requests
@ -74,7 +69,7 @@ function xr_session_promise_test(
.then(() => {
// Cleanup system state.
testSession.end().catch(() => {});
XRTest.simulateDeviceDisconnection(testDevice);
XRTest.simulateDeviceDisconnection();
}),
properties);
}
@ -97,7 +92,6 @@ function getOutputContext() {
// that API object.
function forEachWebxrObject(callback) {
callback(window.navigator.xr, 'navigator.xr');
callback(window.XRDevice, 'XRDevice');
callback(window.XRSession, 'XRSession');
callback(window.XRSessionCreationOptions, 'XRSessionCreationOptions');
callback(window.XRFrameRequestCallback, 'XRFrameRequestCallback');

View file

@ -9,6 +9,6 @@
"Tests requestSession resolves when supported",
(session) => {
assert_not_equals(session, null);
}, { supportsImmersive:true }, { immersive: true });
}, { supportsImmersive:true }, { mode: 'immersive-vr' });
</script>
</body>

View file

@ -8,9 +8,8 @@
"Requesting immersive session outside of a user gesture rejects",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:true })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => promise_rejects(
t, 'SecurityError', device.requestSession({ immersive: true })));
.then( (controller) => promise_rejects(
t, 'SecurityError', navigator.xr.requestSession({ mode: 'immersive-vr' })));
});
</script>
</body>

View file

@ -8,13 +8,12 @@
"Requesting an immersive session when unsupported rejects",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:false })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (magicWindowOnlyDevice) => new Promise((resolve) => {
.then( (controller) => new Promise((resolve) => {
XRTest.simulateUserActivation( () => {
resolve(promise_rejects(
t,
"NotSupportedError",
magicWindowOnlyDevice.requestSession({ immersive: true })
navigator.xr.requestSession({ mode: 'immersive-vr' })
))
});
}));

View file

@ -8,9 +8,8 @@
"Requesting non-immersive session outside of a user gesture succeeds",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:false })
.then( (controller) => { return navigator.xr.requestDevice(); })
.then( (device) => device.requestSession({
immersive: false,
.then( (controller) => navigator.xr.requestSession({
mode: 'inline',
outputContext: getOutputContext()
}))
.then( (session) => { assert_not_equals(session, null); });

View file

@ -5,11 +5,10 @@
<script src="resources/webxr_util.js"></script>
<script>
xr_promise_test(
"supportsSession resolves when immersive options supported",
"supportsSessionMode resolves when immersive options supported",
() => {
return XRTest.simulateDeviceConnection({ supportsImmersive:true })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => device.supportsSession({ immersive: true }));
.then( (controller) => navigator.xr.supportsSessionMode('immersive-vr'));
});
</script>
</body>

View file

@ -5,15 +5,14 @@
<script src="resources/webxr_util.js"></script>
<script>
xr_promise_test(
"supportsSession rejects when options not supported",
"supportsSessionMode rejects when options not supported",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:false })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => {
.then( (controller) => {
return promise_rejects(
t,
"NotSupportedError",
device.supportsSession({ immersive: true })
navigator.xr.supportsSessionMode('immersive-vr')
);
});
});

View file

@ -5,18 +5,12 @@
<script src="resources/webxr_util.js"></script>
<script>
xr_promise_test(
"supportsSession resolves when non-immersive options supported",
"supportsSessionMode resolves when inline options supported",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:true })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => {
// Non-immersive sessions without a outputContext should not be supported.
promise_rejects(t, 'NotSupportedError', device.supportsSession());
// Non-immersive sessions with an outputContext should be supported.
return device.supportsSession({
outputContext: getOutputContext()
});
.then( (controller) => {
// Inline sessions should be supported.
return navigator.xr.supportsSessionMode('inline');
});
});
</script>

View file

@ -13,7 +13,7 @@
let fakeDeviceInitParams = { supportsImmersive:true };
let immersiveSessionOptions = { immersive: true };
let immersiveSessionOptions = { mode: 'immersive-vr' };
let nonImmersiveSessionOptions = { outputContext: getOutputContext() };
let testFunction = (session) => new Promise((resolve, reject) => {

View file

@ -12,7 +12,7 @@
let fakeDeviceInitParams = { supportsImmersive:true };
let immersiveSessionOptions = { immersive: true };
let immersiveSessionOptions = { mode: 'immersive-vr' };
let nonImmersiveSessionOptions = { outputContext: getOutputContext() };
let testFunction = (testSession) => new Promise((resolve) => {

View file

@ -11,7 +11,7 @@
let watcherDone = new Event("watcherdone");
const fakeDeviceInitParams = { supportsImmersive:true };
const immersiveSessionOptions = { immersive: true };
const immersiveSessionOptions = { mode: 'immersive-vr' };
const nonImmersiveSessionOptions = { outputContext: getOutputContext() };
let testFunction = function(session, testDeviceController, t) {

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="resources/webxr_util.js"></script>
<canvas></canvas>
<script>
xr_promise_test("Requested session has it's mode set",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:true })
.then( (controller) => new Promise((resolve) => {
XRTest.simulateUserActivation( () => {
resolve(navigator.xr.requestSession({ mode: 'immersive-vr' }).then( (session) => {
assert_equals(session.mode, 'immersive-vr');
}));
});
}));
});
</script>
</body>

View file

@ -10,26 +10,25 @@
"Test prevention of multiple simultaneous immersive sessions",
(t) => {
return XRTest.simulateDeviceConnection({ supportsImmersive:true })
.then( (controller) => { return navigator.xr.requestDevice() })
.then( (device) => new Promise((resolve) => {
.then( (controller) => new Promise((resolve) => {
XRTest.simulateUserActivation( () => {
resolve(device.requestSession({ immersive: true })
resolve(navigator.xr.requestSession({ mode: 'immersive-vr' })
.then( (session) => new Promise((resolve) => {
XRTest.simulateUserActivation( () => {
// Requesting a second immersive session from a device that already
// has an active immersive session should fail. Immersive sessions
// Requesting a second immersive session when another immersive
// session is active should fail. Immersive sessions
// should take up the users entire view, and therefore it should
// be impossible for a user to be engaged with more than one.
resolve(promise_rejects(
t,
"InvalidStateError",
device.requestSession({ immersive: true })
navigator.xr.requestSession({ mode: 'immersive-vr' })
).then( () => {
// End the immersive session and try again. Now the immersive
// session creation should succeed.
return session.end().then( () => new Promise((resolve) => {
XRTest.simulateUserActivation( () => {
resolve(device.requestSession({ immersive: true }));
resolve(navigator.xr.requestSession({ mode: 'immersive-vr' }));
});
}));
}));

View file

@ -13,7 +13,7 @@
let fakeDeviceInitParams = { supportsImmersive:true };
let immersiveSessionOptions = { immersive: true };
let immersiveSessionOptions = { mode: 'immersive-vr' };
let nonImmersiveSessionOptions = { outputContext: getOutputContext() };
let testFunction = (testSession) => new Promise((resolve) => {

View file

@ -28,7 +28,7 @@
};
const fakeDeviceInitOptions = { supportsImmersive:true };
const sessionOptions = { immersive:true };
const sessionOptions = { mode: 'immersive-vr' };
let testSession;

View file

@ -14,7 +14,7 @@
let fakeDeviceInitParams = { supportsImmersive: true };
let immersiveSessionOptions = { immersive: true };
let immersiveSessionOptions = { mode: 'immersive-vr' };
let nonImmersiveSessionOptions = { outputContext: getOutputContext() };
// Valid matrices for when we don't care about specific values

View file

@ -13,7 +13,7 @@
let fakeDeviceInitParams = { supportsImmersive: true };
let immersiveSessionOptions = { immersive: true };
let immersiveSessionOptions = { mode: 'immersive-vr' };
let nonImmersiveSessionOptions = { outputContext: getOutputContext() };
let testFunction = function(session, fakeDeviceController, t) {

View file

@ -2,20 +2,14 @@
<title>handling for 404 response</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
setup({allow_uncaught_exception: true});
async_test(function() {
var worker = new Worker('404_worker');
worker.onerror = this.step_func(function(e) { this.done(); });
async_test(t => {
const worker = new Worker('404_worker');
worker.onerror = e => t.done();
}, 'worker');
async_test(function() {
var shared = new SharedWorker('404_shared');
// NOTE: this handler will not fire, as runtime scripting errors
// are not forwarded to SharedWorker objects, but instead reported to the user directly.
shared.onerror = this.step_func(function(e) { assert_unreached(); }, shared, 'error');
step_timeout(this.step_func(function() { this.done(); }), 5000);
async_test(t => {
const shared = new SharedWorker('404_shared');
shared.onerror = e => t.done();
}, 'shared');
</script>