mirror of
https://github.com/servo/servo.git
synced 2025-08-16 10:55:34 +01:00
Update web-platform-tests to revision 8ae1ddbc812733c3a73b103eafad56fb43a2f4b5
This commit is contained in:
parent
d44e9aced2
commit
0e5e5db397
109 changed files with 2053 additions and 708 deletions
|
@ -30,9 +30,3 @@ function waitForAsyncAnimationFrames(count) {
|
|||
// AnimationWorklet.
|
||||
return waitForAnimationFrames(count + 1);
|
||||
}
|
||||
|
||||
async function waitForAnimationFrameWithCondition(condition) {
|
||||
do {
|
||||
await new Promise(window.requestAnimationFrame);
|
||||
} while (!condition())
|
||||
};
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
transform: translateY(100px);
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="box"></div>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
125
tests/wpt/web-platform-tests/css/css-syntax/anb-parsing.html
Normal file
125
tests/wpt/web-platform-tests/css/css-syntax/anb-parsing.html
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
62
tests/wpt/web-platform-tests/css/css-syntax/whitespace.html
Normal file
62
tests/wpt/web-platform-tests/css/css-syntax/whitespace.html
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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)
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
Binary file not shown.
|
@ -7,3 +7,7 @@
|
|||
interface AmbientLightSensor : Sensor {
|
||||
readonly attribute double? illuminance;
|
||||
};
|
||||
|
||||
dictionary AmbientLightReadingValues {
|
||||
required double? illuminance;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ partial interface HTMLVideoElement {
|
|||
attribute EventHandler onenterpictureinpicture;
|
||||
attribute EventHandler onleavepictureinpicture;
|
||||
|
||||
[CEReactions] attribute boolean autoPictureInPicture;
|
||||
[CEReactions] attribute boolean disablePictureInPicture;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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));
|
||||
});
|
|
@ -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();
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"]:
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
|
|
@ -1 +0,0 @@
|
|||
Content-Security-Policy: trusted-types *
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
102
tests/wpt/web-platform-tests/webstorage/set.window.js
Normal file
102
tests/wpt/web-platform-tests/webstorage/set.window.js
Normal 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");
|
||||
});
|
||||
});
|
|
@ -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>
|
|
@ -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>
|
|
@ -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');
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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' })
|
||||
))
|
||||
});
|
||||
}));
|
||||
|
|
|
@ -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); });
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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) {
|
||||
|
|
22
tests/wpt/web-platform-tests/webxr/xrSession_mode.https.html
Normal file
22
tests/wpt/web-platform-tests/webxr/xrSession_mode.https.html
Normal 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>
|
||||
|
|
@ -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' }));
|
||||
});
|
||||
}));
|
||||
}));
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
};
|
||||
|
||||
const fakeDeviceInitOptions = { supportsImmersive:true };
|
||||
const sessionOptions = { immersive:true };
|
||||
const sessionOptions = { mode: 'immersive-vr' };
|
||||
|
||||
let testSession;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue