Update web-platform-tests to revision 6e9693d2690e0648fb9a1bd902af7cc078f28515

This commit is contained in:
WPT Sync Bot 2018-11-03 21:29:40 -04:00
parent 4ec7dedce1
commit 612038c4d6
56 changed files with 1374 additions and 477 deletions

View file

@ -1,20 +1,29 @@
// META: script=support-promises.js
promise_test(async testCase => {
// Delete any databases that may not have been cleaned up after
// previous test runs.
assert_true(indexedDB.databases() instanceof Promise,
"databases() should return a promise.");
}, "Ensure that databases() returns a promise.");
promise_test(async testCase => {
// Delete any databases that may not have been cleaned up after previous test
// runs.
await deleteAllDatabases(testCase);
const db_name = "TestDatabase";
const db = await createNamedDatabase(testCase, db_name, ()=>{});
const databases_promise = await indexedDB.databases();
const expected_result = [
{"name": db_name, "version": 1},
];
assert_object_equals(
databases_promise,
expected_result,
"Call to databases() did not retrieve the single expected result.");
const databases_result = await indexedDB.databases();
db.close();
const expected_result = {"name": db_name, "version": 1};
assert_equals(
databases_result.length,
1,
"The result of databases() should contain one result per database.");
assert_true(
databases_result[0].name === expected_result.name
&& databases_result[0].version === expected_result.version,
"The result of databases() should be a sequence of the correct names "
+ "and versions of all databases for the origin.");
}, "Enumerate one database.");
promise_test(async testCase => {
@ -28,35 +37,81 @@ promise_test(async testCase => {
const db1 = await createNamedDatabase(testCase, db_name1, ()=>{});
const db2 = await createNamedDatabase(testCase, db_name2, ()=>{});
const db3 = await createNamedDatabase(testCase, db_name3, ()=>{});
const databases_promise = await indexedDB.databases();
db1.close();
db2.close();
db3.close();
const version_promise =
await migrateNamedDatabase(testCase, db_name2, 2, () => {});
const databases_result = await indexedDB.databases();
const expected_result = [
{"name": db_name1, "version": 1},
{"name": db_name2, "version": 1},
{"name": db_name2, "version": 2},
{"name": db_name3, "version": 1},
];
assert_object_equals(
databases_promise,
expected_result,
"Call to databases() did not retrieve the multiple expected results");
assert_equals(
databases_result.length,
expected_result.length,
"The result of databases() should contain one result per database.");
for ( let i = 0; i < expected_result.length; i += 1 ) {
result = expected_result[i];
assert_true(
databases_result.some(
e => e.name === result.name && e.version === result.version),
"The result of databases() should be a sequence of the correct names "
+ "and versions of all databases for the origin.");
}
}, "Enumerate multiple databases.");
promise_test(async testCase => {
// Add some databases and close their connections.
const db1 = await createNamedDatabase(testCase, "DB1", ()=>{});
const db2 = await createNamedDatabase(testCase, "DB2", ()=>{});
db1.onversionchange = () => { db1.close() };
db2.onversionchange = () => { db2.close() };
const db1 = await createNamedDatabase(testCase, "DB1", () => {});
const db2 = await createNamedDatabase(testCase, "DB2", () => {});
db1.close();
db2.close();
// Delete any databases that may not have been cleaned up after previous test
// runs as well as the two databases made above.
await deleteAllDatabases(testCase);
// Make sure the databases are no longer returned.
const databases_promise = await indexedDB.databases();
assert_object_equals(
databases_promise,
[],
"Call to databases() found database it should not have.")
const databases_result = await indexedDB.databases();
assert_equals(
databases_result.length,
0,
"The result of databases() should be an empty sequence for the case of "
+ "no databases for the origin.");
}, "Make sure an empty list is returned for the case of no databases.");
done();
promise_test(async testCase => {
// Delete any databases that may not have been cleaned up after previous test
// runs as well as the two databases made above.
await deleteAllDatabases(testCase);
const db1 = await createNamedDatabase(testCase, "DB1", ()=>{});
const db2 = await createNamedDatabase(testCase, "DB2", async () => {
const databases_result1 = await indexedDB.databases();
assert_equals(
databases_result1.length,
1,
"The result of databases() should be only those databases which have "
+ "been created at the time of calling, regardless of versionchange "
+ "transactions currently running.");
});
db1.close();
db2.close();
const databases_result2 = await indexedDB.databases();
assert_equals(
databases_result2.length,
2,
"The result of databases() should include all databases which have "
+ "been created at the time of calling.");
await migrateNamedDatabase(testCase, "DB2", 2, async () => {
const databases_result3 = await indexedDB.databases();
assert_true(
databases_result3[0].version === 1
&& databases_result3[1].version === 1,
"The result of databases() should contain the versions of databases "
+ "at the time of calling, regardless of versionchange transactions "
+ "currently running.");
});
}, "Ensure that databases() doesn't pick up changes that haven't commited.");

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-bottom">
<style>
#container { overflow:hidden; background:blue; }
#container > div { margin-bottom:50%; height:50px; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:456px;" data-expected-width="100" data-expected-height="100">
<div></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "100px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-left">
<style>
#container > div { margin-left:50%; height:100px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:456px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "200px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-right">
<style>
#container > div { margin-right:50%; height:100px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:456px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "200px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-top">
<style>
#container { overflow:hidden; background:blue; }
#container > div { margin-top:50%; height:50px; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:456px;" data-expected-width="100" data-expected-height="100">
<div></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "100px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-bottom">
<style>
#container > div { padding-bottom:10%; width:100px; height:50px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:123px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "500px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-left">
<style>
#container > div { padding-left:10%; width:50px; height:100px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:123px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "500px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-right">
<style>
#container > div { padding-right:10%; width:50px; height:100px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:123px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "500px";
checkLayout("#container");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-top">
<style>
#container > div { padding-top:10%; width:100px; height:50px; background:blue; }
</style>
<p>There should be a blue square below.</p>
<div id="container" style="width:123px;">
<div data-expected-width="100" data-expected-height="100"></div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.body.offsetTop;
document.getElementById("container").style.width = "500px";
checkLayout("#container");
</script>

View file

@ -23,7 +23,11 @@ test_valid_value("animation-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
test_valid_value("animation-timing-function", "steps(4, start)");
test_valid_value("animation-timing-function", "steps(2, end)");
test_valid_value("animation-timing-function", "steps(2, end)", "steps(2)");
test_valid_value("animation-timing-function", "steps(2, jump-start)");
test_valid_value("animation-timing-function", "steps(2, jump-end)", "steps(2)");
test_valid_value("animation-timing-function", "steps(2, jump-both)");
test_valid_value("animation-timing-function", "steps(2, jump-none)");
test_valid_value("animation-timing-function", "linear, ease, linear");
</script>

View file

@ -1,4 +1,4 @@
spec: https://drafts.csswg.org/css-timing/
spec: https://drafts.csswg.org/css-easing/
suggested_reviewers:
- birtles
- BorisChiou

View file

@ -4,7 +4,7 @@
content="This test checks the output of Cubic Bézier functions" />
<title>Tests for the output of Cubic Bézier timing functions</title>
<link rel="help"
href="https://drafts.csswg.org/css-timing/#cubic-bezier-timing-functions">
href="https://drafts.csswg.org/css-easing/#cubic-bezier-timing-functions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="testcommon.js"></script>

View file

@ -0,0 +1,318 @@
<!DOCTYPE html>
<meta charset=utf-8>
<meta name="assert"
content="This test checks the output of step timing functions" />
<title>Tests for the output of step timing functions</title>
<link rel="help"
href="https://drafts.csswg.org/css-easing/#step-timing-functions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="testcommon.js"></script>
<body>
<div id="log"></div>
<script>
'use strict';
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values greater than 1 (but always less than 2)
// in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 3, 1, 3)' });
// The bezier function produces values:
// Input -> Output
// 0.0 0.0
// 0.114 ~ 0.245 1.5~2.0, so current step is 2, jumps is 1 => 2.0
// 0.245 ~ 0.6 2.0~2.4, so current step is 3, jumps is 1 => 3.0
// 0.6 ~ 0.882 2.4~2.0, so current step is 3, jumps is 1 => 3.0
// 0.882 ~ 0.976 2.0~1.5, so current step is 2, jumps is 1 => 2.0
// 1.0 1.0
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 114;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '300px');
anim.currentTime = 900;
assert_equals(getComputedStyle(target).left, '200px');
}, 'step-start easing with input progress greater than 2');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -1)
// in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress less than 0');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -2, 1, -2)' });
// The bezier function produces values less than -1 (but always greater than
// -2) in the range (~0.118, ~0.755)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 100;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '-100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress less than -1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values greater than 1 (but always less than 2)
// in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 3, 1, 3)' });
// The bezier function produces values:
// Input -> Output
// 0.0 0.0
// 0.114 ~ 0.245 1.5~2.0, so current step is 1, jumps is 1 => 1.0
// 0.245 ~ 0.6 2.0~2.4, so current step is 2, jumps is 1 => 2.0
// 0.6 ~ 0.882 2.4~2.0, so current step is 2, jumps is 1 => 2.0
// 0.882 ~ 0.976 2.0~1.5, so current step is 1, jumps is 1 => 1.0
// 1.0 1.0
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 114;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 900;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress greater than 2');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -1)
// in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '-100px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress less than 0');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values greater than 1 (but always less than 2)
// in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '50px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '50px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'steps(1, jump-both) easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 3, 1, 3)' });
// The bezier function produces values:
// Input -> Output
// 0.0 0.0, so current step is 1, jumps is 2 => 0.5
// 0.114 ~ 0.245 1.5~2.0, so current step is 2, jumps is 2 => 1.0
// 0.245 ~ 0.6 2.0~2.4, so current step is 3, jumps is 2 => 1.5
// 0.6 ~ 0.882 2.4~2.0, so current step is 3, jumps is 2 => 1.5
// 0.882 ~ 0.976 2.0~1.5, so current step is 2, jumps is 2 => 1.0
// 1.0 1.0
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '50px');
anim.currentTime = 114;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '150px');
anim.currentTime = 900;
assert_equals(getComputedStyle(target).left, '100px');
}, 'steps(1, jump-both) easing with input progress greater than 2');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -0.5)
// in (0, 0.766312060).
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '50px');
anim.currentTime = 750;
// current step is 0, jumps is 2.
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '50px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'steps(1, jump-both) easing with input progress less than 0');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values between 0.5 and 1 in
// (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1).
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 45;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'steps(2, jump-none) easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 3, 1, 3)' });
// The bezier function produces values:
// Input -> Output
// 0.0 0.0, so current step is 0, jumps is 1 => 0.0
// 0.114 ~ 0.245 1.5~2.0, so current step is 3, jumps is 1 => 3.0
// 0.245 ~ 0.6 2.0~2.4, so current step is 4, jumps is 1 => 4.0
// 0.6 ~ 0.882 2.4~2.0, so current step is 4, jumps is 1 => 4.0
// 0.882 ~ 0.976 2.0~1.5, so current step is 3, jumps is 1 => 3.0
// 1.0 1.0
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 114;
assert_equals(getComputedStyle(target).left, '300px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '400px');
anim.currentTime = 900;
assert_equals(getComputedStyle(target).left, '300px');
}, 'steps(2, jump-none) easing with input progress greater than 2');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -0.5)
// in (0, 0.766312060).
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 750;
// current step is -1, jumps is 1.
assert_equals(getComputedStyle(target).left, '-100px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'steps(2, jump-none) easing with input progress less than 0');
</script>
</body>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<meta charset=utf-8>
<meta name="assert"
content="This test checks the syntax output of step timing functions" />
<title>Step timing function syntax tests</title>
<link rel="help"
href="https://drafts.csswg.org/css-easing-1/#step-timing-functions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="testcommon.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
<body>
<div id="log"></div>
<script>
"use strict";
test_valid_value("animation-timing-function", "step-start", "steps(1, start)");
test_valid_value("animation-timing-function", "step-end", "steps(1)");
test_valid_value("animation-timing-function", "steps(1, start)");
test_valid_value("animation-timing-function", "steps(1, end)", "steps(1)");
test_valid_value("animation-timing-function", "steps(1, jump-start)");
test_valid_value("animation-timing-function", "steps(1, jump-end)", "steps(1)");
test_valid_value("animation-timing-function", "steps(1, jump-both)");
test_valid_value("animation-timing-function", "steps(2, jump-none)");
test_invalid_value("animation-timing-function", "steps(0, start)");
test_invalid_value("animation-timing-function", "steps(0, end)");
test_invalid_value("animation-timing-function", "steps(0, jump-start)");
test_invalid_value("animation-timing-function", "steps(0, jump-end)");
test_invalid_value("animation-timing-function", "steps(0, jump-both)");
test_invalid_value("animation-timing-function", "steps(1, jump-none)");
</script>
</body>

View file

@ -1,141 +0,0 @@
<!DOCTYPE html>
<meta charset=utf-8>
<meta name="assert"
content="This test checks the output of step timing functions" />
<title>Tests for the output of step timing functions</title>
<link rel="help"
href="https://drafts.csswg.org/css-timing/#step-timing-functions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="testcommon.js"></script>
<body>
<div id="log"></div>
<script>
'use strict';
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values greater than 1 (but always less than 2)
// in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
// The bezier function produces values greater than 1 (but always less than 2)
// in (0.23368794, 1)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 230;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 250;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress greater than 1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, 3, 1, 3)' });
// The bezier function produces values greater than 2 (but always less than 3)
// in the range (~0.245, ~0.882)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '200px');
anim.currentTime = 900;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress greater than 2');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -1)
// in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress less than 0');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-start' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -2, 1, -2)' });
// The bezier function produces values less than -1 (but always greater than
// -2) in the range (~0.118, ~0.755)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '100px');
anim.currentTime = 100;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 500;
assert_equals(getComputedStyle(target).left, '-100px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-start easing with input progress less than -1');
test(function(t) {
var target = createDiv(t);
target.style.position = 'absolute';
var anim = target.animate([ { left: '0px', easing: 'step-end' },
{ left: '100px' } ],
{ duration: 1000,
fill: 'forwards',
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
// The bezier function produces negative values (but always greater than -1)
// in (0, 0.766312060)
anim.currentTime = 0;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 750;
assert_equals(getComputedStyle(target).left, '-100px');
anim.currentTime = 800;
assert_equals(getComputedStyle(target).left, '0px');
anim.currentTime = 1000;
assert_equals(getComputedStyle(target).left, '100px');
}, 'step-end easing with input progress less than 0');
</script>
</body>

View file

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>CSS Animations: parsing transition-timing-function with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
<link rel="help" href="https://drafts.csswg.org/css-timing-1/#typedef-timing-function">
<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
<meta name="assert" content="transition-timing-function supports only the grammar '<timing-function> #'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

View file

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>CSS Transitions: parsing transition-timing-function with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
<link rel="help" href="https://drafts.csswg.org/css-timing-1/#typedef-timing-function">
<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
<meta name="assert" content="transition-timing-function supports the full grammar '<timing-function> #'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@ -23,7 +23,11 @@ test_valid_value("transition-timing-function", "cubic-bezier(0, -2, 1, 3)");
test_valid_value("transition-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
test_valid_value("transition-timing-function", "steps(4, start)");
test_valid_value("transition-timing-function", "steps(2, end)");
test_valid_value("transition-timing-function", "steps(2, end)", "steps(2)");
test_valid_value("transition-timing-function", "steps(2, jump-start)");
test_valid_value("transition-timing-function", "steps(2, jump-end)", "steps(2)");
test_valid_value("transition-timing-function", "steps(2, jump-both)");
test_valid_value("transition-timing-function", "steps(2, jump-none)");
test_valid_value("transition-timing-function", "linear, ease, linear");
</script>

View file

@ -42,12 +42,20 @@
'steps(3, start)': 'steps(3, start)',
'steps(3, end)': 'steps(3)',
'steps(3)': 'steps(3)',
'steps(3, jump-start)': 'steps(3, jump-start)',
'steps(3, jump-end)': 'steps(3)',
'steps(3, jump-both)': 'steps(3, jump-both)',
'steps(3, jump-none)': 'steps(3, jump-none)',
// invalid
'cubic-bezier(foobar)': defaultValue,
'steps(foobar)': defaultValue,
'steps(3.3, end)': defaultValue,
'steps(3, top)': defaultValue,
'steps(-3, top)': defaultValue,
'steps(0, jump-start)': defaultValue,
'steps(0, jump-end)': defaultValue,
'steps(0, jump-both)': defaultValue,
'steps(1, jump-none)': defaultValue,
// Both x values must be in the range [0, 1]
'cubic-bezier(-0.1, -0.2, -0.3, -0.4)': defaultValue,
'cubic-bezier(1.1, 1.2, 1.3, 1.4)': defaultValue

View file

@ -30,6 +30,6 @@ partial interface Document {
attribute EventHandler onfullscreenerror;
};
partial interface DocumentOrShadowRoot {
partial interface mixin DocumentOrShadowRoot {
[LenientSetter] readonly attribute Element? fullscreenElement;
};

View file

@ -153,7 +153,7 @@ interface PaymentResponse : EventTarget {
[NewObject]
Promise<void> complete(optional PaymentComplete result = "unknown");
[NewObject]
Promise<void> retry(PaymentValidationErrors errorFields);
Promise<void> retry(optional PaymentValidationErrors errorFields);
attribute EventHandler onpayerdetailchange;
};

View file

@ -760,7 +760,7 @@ MISSING-LINK: css/css-scroll-anchoring/position-change-heuristic.html
MISSING-LINK: css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
MISSING-LINK: css/css-scroll-anchoring/subtree-exclusion.html
MISSING-LINK: css/css-scroll-anchoring/wrapped-text.html
SUPPORT-WRONG-DIR: css/css-timing/testcommon.js
SUPPORT-WRONG-DIR: css/css-easing/testcommon.js
MISSING-LINK: css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html
MISSING-LINK: css/css-typed-om/declared-styleMap-accepts-inherit.html
SUPPORT-WRONG-DIR: css/cssom/stylesheet-same-origin.css

View file

@ -28,7 +28,7 @@ function checkCompletedCantRetry(button) {
return promise_rejects(
t,
"InvalidStateError",
response.retry({}),
response.retry(),
"response.[[complete]] is true, so rejects with InvalidStateError."
);
}, button.textContent.trim());
@ -38,11 +38,11 @@ function repeatedCallsToRetry(button) {
button.disabled = true;
promise_test(async t => {
const { response } = await getPaymentRequestResponse();
const retryPromise = response.retry({});
const retryPromise = response.retry();
await promise_rejects(
t,
"InvalidStateError",
response.retry({}),
response.retry(),
"Calling retry() again rejects with an InvalidStateError"
);
await retryPromise;
@ -54,7 +54,7 @@ function callCompleteWhileRetrying(button) {
button.disabled = true;
promise_test(async t => {
const { response } = await getPaymentRequestResponse();
const retryPromise = response.retry({});
const retryPromise = response.retry();
await promise_rejects(
t,
"InvalidStateError",
@ -70,7 +70,7 @@ function callingRequestAbortMustNotAbort(button) {
button.disabled = true;
promise_test(async t => {
const { response, request } = await getPaymentRequestResponse();
const retryPromise = response.retry({});
const retryPromise = response.retry();
await promise_rejects(
t,
"InvalidStateError",
@ -87,12 +87,12 @@ function canRetryMultipleTimes(button) {
promise_test(async t => {
const { response } = await getPaymentRequestResponse();
assert_equals(
await response.retry({}),
await response.retry(),
undefined,
"Expected undefined as the resolve value"
);
assert_equals(
await response.retry({}),
await response.retry(),
undefined,
"Expected undefined as the resolve value"
);
@ -100,7 +100,7 @@ function canRetryMultipleTimes(button) {
await promise_rejects(
t,
"InvalidStateError",
response.retry({}),
response.retry(),
"Calling retry() after complete() rejects with a InvalidStateError"
);
}, button.textContent.trim());
@ -113,13 +113,13 @@ function userCanAbortARetry(button) {
await promise_rejects(
t,
"AbortError",
response.retry({}),
response.retry(),
"The user aborting a retry rejects with a AbortError"
);
await promise_rejects(
t,
"InvalidStateError",
response.retry({}),
response.retry(),
"After the user aborts, response [[complete]] is true so retry() must reject with InvalidStateError"
);
await promise_rejects(
@ -154,7 +154,7 @@ function abortTheUpdate(button) {
resolve();
};
});
const retryPromise = response.retry({});
const retryPromise = response.retry();
await shippingChangedPromise;
await promise_rejects(
t,
@ -175,11 +175,11 @@ function callingRetryReturnsUniquePromise(button){
button.disabled = true;
promise_test(async t => {
const { response } = await getPaymentRequestResponse();
const retryPromise = response.retry({});
const retryPromise = response.retry();
const promises = new Set([
retryPromise,
response.retry({}),
response.retry({}),
response.retry(),
response.retry(),
]);
assert_equals(promises.size, 3, "Must have three unique objects");
await retryPromise;

View file

@ -2,4 +2,4 @@ html5lib == 1.0.1
mozinfo == 0.10
mozlog==3.9
mozdebug==0.1.1
urllib3[secure]==1.24
urllib3[secure]==1.24.1

View file

@ -32,10 +32,9 @@ for (const params of gEasingTests) {
}, `Transformed progress for ${params.desc}`);
}
// Additional tests for various boundary conditions of step timing functions and
// frames timing functions.
// Additional tests for various boundary conditions of step timing functions.
const gStepAndFramesTimingFunctionTests = [
const gStepTimingFunctionTests = [
{
description: 'Test bounds point of step-start easing',
effect: {
@ -255,12 +254,72 @@ const gStepAndFramesTimingFunctionTests = [
]
},
{
description: 'Test bounds point of frames easing',
description: 'Test bounds point of steps(jump-both) easing',
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
easing: 'frames(2)'
easing: 'steps(2, jump-both)'
},
conditions: [
{ currentTime: 0, progress: 0 },
{ currentTime: 999, progress: 0 },
{ currentTime: 1000, progress: 1/3 },
{ currentTime: 1499, progress: 1/3 },
{ currentTime: 1500, progress: 2/3 },
{ currentTime: 2000, progress: 1 }
]
},
{
description: 'Test bounds point of steps(jump-both) easing ' +
'with iterationStart and delay',
effect: {
duration: 1000,
fill: 'both',
delay: 1000,
iterationStart: 0.5,
easing: 'steps(2, jump-both)'
},
conditions: [
{ currentTime: 0, progress: 1/3 },
{ currentTime: 999, progress: 1/3 },
{ currentTime: 1000, progress: 2/3 },
{ currentTime: 1499, progress: 2/3 },
{ currentTime: 1500, progress: 1/3 },
{ currentTime: 1999, progress: 1/3 },
{ currentTime: 2000, progress: 2/3 },
{ currentTime: 2500, progress: 2/3 }
]
},
{
description: 'Test bounds point of steps(jump-both) easing ' +
'with iterationStart not at a transition point',
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.75,
easing: 'steps(2, jump-both)'
},
conditions: [
{ currentTime: 0, progress: 2/3 },
{ currentTime: 999, progress: 2/3 },
{ currentTime: 1000, progress: 2/3 },
{ currentTime: 1249, progress: 2/3 },
{ currentTime: 1250, progress: 1/3 },
{ currentTime: 1749, progress: 1/3 },
{ currentTime: 1750, progress: 2/3 },
{ currentTime: 2000, progress: 2/3 },
{ currentTime: 2500, progress: 2/3 }
]
},
{
description: 'Test bounds point of steps(jump-none) easing',
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
easing: 'steps(2, jump-none)'
},
conditions: [
{ currentTime: 0, progress: 0 },
@ -271,27 +330,51 @@ const gStepAndFramesTimingFunctionTests = [
]
},
{
description: 'Test bounds point of frames easing ' +
description: 'Test bounds point of steps(jump-none) easing ' +
'with iterationStart and delay',
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
delay: 1000,
iterationStart: 0.5,
easing: 'frames(2)'
easing: 'steps(2, jump-none)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 0, progress: 0 },
{ currentTime: 999, progress: 0 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1499, progress: 1 },
{ currentTime: 1500, progress: 0 },
{ currentTime: 1999, progress: 0 },
{ currentTime: 2000, progress: 1 }
{ currentTime: 2000, progress: 1 },
{ currentTime: 2500, progress: 1 }
]
}
},
{
description: 'Test bounds point of steps(jump-none) easing ' +
'with iterationStart not at a transition point',
effect: {
delay: 1000,
duration: 1000,
fill: 'both',
iterationStart: 0.75,
easing: 'steps(2, jump-none)'
},
conditions: [
{ currentTime: 0, progress: 1 },
{ currentTime: 999, progress: 1 },
{ currentTime: 1000, progress: 1 },
{ currentTime: 1249, progress: 1 },
{ currentTime: 1250, progress: 0 },
{ currentTime: 1749, progress: 0 },
{ currentTime: 1750, progress: 1 },
{ currentTime: 2000, progress: 1 },
{ currentTime: 2500, progress: 1 }
]
},
];
for (const options of gStepAndFramesTimingFunctionTests) {
for (const options of gStepTimingFunctionTests) {
test(t => {
const target = createDiv(t);
const animation = target.animate(null, options.effect);

View file

@ -0,0 +1,3 @@
spec: https://github.com/w3c/webrtc-identity
suggested_reviewers:
- martinthomson

View file

@ -0,0 +1,77 @@
<!doctype html>
<meta charset="utf-8">
<title>RTCCertificate persistent Tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<body>
<script>
function findMatchingFingerprint(fingerprints, fingerprint) {
for (let f of fingerprints) {
if (f.value == fingerprint.value && f.algorithm == fingerprint.algorithm)
return true;
}
return false;
}
function with_iframe(url) {
return new Promise(function(resolve) {
var frame = document.createElement('iframe');
frame.src = url;
frame.onload = function() { resolve(frame); };
document.body.appendChild(frame);
});
}
function testPostMessageCertificate(isCrossOrigin) {
promise_test(async t => {
let certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256' });
let url = "resources/RTCCertificate-postMessage-iframe.html";
if (isCrossOrigin)
url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/" + url;
let iframe = await with_iframe(url);
let promise = new Promise((resolve, reject) => {
window.onmessage = (event) => {
resolve(event.data);
};
t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
});
iframe.contentWindow.postMessage(certificate, "*");
let certificate2 = await promise;
new RTCPeerConnection({certificates: [certificate]});
new RTCPeerConnection({certificates: [certificate2]});
assert_equals(certificate.expires, certificate2.expires);
for (let fingerprint of certificate2.getFingerprints())
assert_true(findMatchingFingerprint(certificate.getFingerprints(), fingerprint), "check fingerprints");
iframe.remove();
}, "Check " + (isCrossOrigin ? "cross-origin" : "same-origin") + " RTCCertificate serialization");
}
testPostMessageCertificate(false);
testPostMessageCertificate(true);
promise_test(async t => {
let url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/resources/RTCCertificate-postMessage-iframe.html";
let iframe = await with_iframe(url);
let promise = new Promise((resolve, reject) => {
window.onmessage = (event) => {
resolve(event.data);
};
t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
});
iframe.contentWindow.postMessage(null, "*");
let certificate2 = await promise;
assert_throws("InvalidAccessError", () => { new RTCPeerConnection({certificates: [certificate2]}) });
iframe.remove();
}, "Check cross-origin created RTCCertificate");
</script>
</body>

View file

@ -6,8 +6,8 @@
<script>
'use strict';
// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
// Test is based on the Candidate Recommendation:
// https://www.w3.org/TR/webrtc/
/*
4.2.1. RTCConfiguration Dictionary
@ -26,8 +26,8 @@
4.10.2. RTCCertificate Interface
interface RTCCertificate {
readonly attribute DOMTimeStamp expires;
static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
sequence<RTCDtlsFingerprint> getFingerprints();
AlgorithmIdentifier getAlgorithm();
};
5.5.1 The RTCDtlsFingerprint Dictionary
@ -257,10 +257,9 @@
TODO
4.10.2. RTCCertificate Interface
getAlgorithm
Returns the result of the WebCrypto algorithm normalization process
[WebCryptoAPI] that occurred when this certificate was generated
with generateCertificate().
getSupportedAlgorithms
Returns a sequence providing a representative set of supported
certificate algorithms. At least one algorithm MUST be returned.
The RTCCertificate object can be stored and retrieved from persistent
storage by an application. When a user agent is required to obtain a

View file

@ -34,7 +34,7 @@
candidate: '',
sdpMid: null,
sdpMLineIndex: null,
ufrag: undefined
usernameFragment: undefined
}));
}, 'new RTCIceCandidate({ ... }) with manually filled default values');
@ -77,7 +77,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, `new RTCIceCandidate({ sdpMid: 'audio' })`);
test(t => {
@ -86,7 +86,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, 'new RTCIceCandidate({ sdpMLineIndex: 0 })');
test(t => {
@ -98,7 +98,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, `new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })`);
test(t => {
@ -110,7 +110,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, `new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }`);
test(t => {
@ -122,7 +122,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 0);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, `new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }`);
test(t => {
@ -134,7 +134,7 @@
assert_equals(candidate.candidate, candidateString);
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, 'new RTCIceCandidate({ ... }) with valid candidate string and sdpMid');
test(t =>{
@ -147,7 +147,7 @@
assert_equals(candidate.candidate, arbitraryString);
assert_equals(candidate.sdpMid, 'audio');
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, 'new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid');
test(t => {
@ -155,13 +155,13 @@
candidate: candidateString,
sdpMid: 'video',
sdpMLineIndex: 1,
ufrag: 'test'
usernameFragment: 'test'
});
assert_equals(candidate.candidate, candidateString);
assert_equals(candidate.sdpMid, 'video');
assert_equals(candidate.sdpMLineIndex, 1);
assert_equals(candidate.ufrag, 'test');
assert_equals(candidate.usernameFragment, 'test');
}, 'new RTCIceCandidate({ ... }) with non default value for all fields');
@ -174,7 +174,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, arbitraryString);
assert_equals(candidate.sdpMLineIndex, null);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, 'new RTCIceCandidate({ ... }) with invalid sdpMid');
@ -190,7 +190,7 @@
assert_equals(candidate.candidate, '');
assert_equals(candidate.sdpMid, null);
assert_equals(candidate.sdpMLineIndex, 65535);
assert_equals(candidate.ufrag, null);
assert_equals(candidate.usernameFragment, null);
}, 'new RTCIceCandidate({ ... }) with invalid sdpMLineIndex');
</script>

View file

@ -5,32 +5,6 @@
<script>
'use strict';
// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.htm
/*
4.3.2. Interface Definition
interface RTCPeerConnection : EventTarget {
...
Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate);
};
interface RTCIceCandidate {
readonly attribute DOMString candidate;
readonly attribute DOMString? sdpMid;
readonly attribute unsigned short? sdpMLineIndex;
readonly attribute DOMString? ufrag;
...
};
dictionary RTCIceCandidateInit {
DOMString candidate = "";
DOMString? sdpMid = null;
unsigned short? sdpMLineIndex = null;
DOMString ufrag;
};
*/
// SDP copied from JSEP Example 7.1
// It contains two media streams with different ufrags
// to test if candidate is added to the correct stream
@ -89,11 +63,11 @@ a=rtcp-rsize
// valid candidate attributes
const sdpMid = 'a1';
const sdpMLineIndex = 0;
const ufrag = 'ETEn';
const usernameFragment = 'ETEn';
const sdpMid2 = 'v1';
const sdpMLineIndex2 = 1;
const ufrag2 = 'BGKk';
const usernameFragment2 = 'BGKk';
const mediaLine1 = 'm=audio';
const mediaLine2 = 'm=video';
@ -151,7 +125,7 @@ a=rtcp-rsize
}, 'Add null candidate should reject with TypeError');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4. Return the result of enqueuing the following steps:
1. If remoteDescription is null return a promise rejected with a
newly created InvalidStateError.
@ -164,7 +138,7 @@ a=rtcp-rsize
return promise_rejects(t, 'InvalidStateError',
pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
}));
}, 'Add ICE candidate before setting remote description should reject with InvalidStateError');
@ -179,7 +153,7 @@ a=rtcp-rsize
return pc.setRemoteDescription(sessionDesc)
.then(() => pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
}));
}, 'Add ICE candidate after setting remote description should succeed');
@ -191,7 +165,7 @@ a=rtcp-rsize
return pc.setRemoteDescription(sessionDesc)
.then(() => pc.addIceCandidate(new RTCIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
})));
}, 'Add ICE candidate with RTCIceCandidate should succeed');
@ -214,12 +188,15 @@ a=rtcp-rsize
}, 'Add candidate with only valid sdpMLineIndex should succeed');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4.6.2. If candidate is applied successfully, the user agent MUST queue
a task that runs the following steps:
2. Let remoteDescription be connection's pendingRemoteDescription
if not null, otherwise connection's currentRemoteDescription.
3. Add candidate to remoteDescription.
2. If connection.pendingRemoteDescription is non-null, and represents
the ICE generation for which candidate was processed, add
candidate to connection.pendingRemoteDescription.
3. If connection.currentRemoteDescription is non-null, and represents
the ICE generation for which candidate was processed, add
candidate to connection.currentRemoteDescription.
*/
promise_test(t => {
const pc = new RTCPeerConnection();
@ -229,7 +206,7 @@ a=rtcp-rsize
return pc.setRemoteDescription(sessionDesc)
.then(() => pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
}))
.then(() => {
assert_candidate_line_between(pc.remoteDescription.sdp,
@ -247,7 +224,7 @@ a=rtcp-rsize
candidate: candidateStr2,
sdpMid: sdpMid2,
sdpMLineIndex: sdpMLineIndex2,
ufrag: ufrag2
usernameFragment: usernameFragment2
}))
.then(() => {
assert_candidate_line_after(pc.remoteDescription.sdp,
@ -264,13 +241,13 @@ a=rtcp-rsize
.then(() => pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex,
ufrag: null
usernameFragment: null
}))
.then(() => {
assert_candidate_line_between(pc.remoteDescription.sdp,
mediaLine1, candidateLine1, mediaLine2);
});
}, 'Add candidate for first media stream with null ufrag should add candidate to first media stream');
}, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
promise_test(t => {
const pc = new RTCPeerConnection();
@ -280,13 +257,13 @@ a=rtcp-rsize
return pc.setRemoteDescription(sessionDesc)
.then(() => pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
}))
.then(() => pc.addIceCandidate({
candidate: candidateStr2,
sdpMid: sdpMid2,
sdpMLineIndex: sdpMLineIndex2,
ufrag: ufrag2
usernameFragment: usernameFragment2
}))
.then(() => {
assert_candidate_line_between(pc.remoteDescription.sdp,
@ -298,15 +275,18 @@ a=rtcp-rsize
}, 'Adding multiple candidates should add candidates to their corresponding media stream');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4.6. If candidate.candidate is an empty string, process candidate as an
end-of-candidates indication for the corresponding media description
and ICE candidate generation.
2. If candidate is applied successfully, the user agent MUST queue
a task that runs the following steps:
2. Let remoteDescription be connection's pendingRemoteDescription
if not null, otherwise connection's currentRemoteDescription.
3. Add candidate to remoteDescription.
2. If connection.pendingRemoteDescription is non-null, and represents
the ICE generation for which candidate was processed, add
candidate to connection.pendingRemoteDescription.
3. If connection.currentRemoteDescription is non-null, and represents
the ICE generation for which candidate was processed, add
candidate to connection.currentRemoteDescription.
*/
promise_test(t => {
const pc = new RTCPeerConnection();
@ -316,12 +296,12 @@ a=rtcp-rsize
return pc.setRemoteDescription(sessionDesc)
.then(() => pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
}))
.then(() => pc.addIceCandidate({
candidate: '',
sdpMid, sdpMLineIndex,
ufrag
usernameFragment
}))
.then(() => {
assert_candidate_line_between(pc.remoteDescription.sdp,
@ -333,7 +313,7 @@ a=rtcp-rsize
}, 'Add with empty candidate string (end of candidate) should succeed');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
with a newly created TypeError.
*/
@ -403,12 +383,12 @@ a=rtcp-rsize
candidate: '',
sdpMid: null,
sdpMLineIndex: null,
ufrag: undefined
usernameFragment: undefined
})));
}, 'Add candidate with manually filled default values should reject with TypeError');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4.3. If candidate.sdpMid is not null, run the following steps:
1. If candidate.sdpMid is not equal to the mid of any media
description in remoteDescription , reject p with a newly
@ -424,12 +404,12 @@ a=rtcp-rsize
promise_rejects(t, 'OperationError',
pc.addIceCandidate({
candidate: candidateStr1,
sdpMid: 'invalid', sdpMLineIndex, ufrag
sdpMid: 'invalid', sdpMLineIndex, usernameFragment
})));
}, 'Add candidate with invalid sdpMid should reject with OperationError');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4.4. Else, if candidate.sdpMLineIndex is not null, run the following
steps:
1. If candidate.sdpMLineIndex is equal to or larger than the
@ -447,7 +427,7 @@ a=rtcp-rsize
pc.addIceCandidate({
candidate: candidateStr1,
sdpMLineIndex: 2,
ufrag
usernameFragment
})));
}, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
@ -463,7 +443,7 @@ a=rtcp-rsize
candidate: candidateStr1,
sdpMid,
sdpMLineIndex: 2,
ufrag
usernameFragment
}));
}, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
@ -477,18 +457,18 @@ a=rtcp-rsize
candidate: candidateStr2,
sdpMid: sdpMid2,
sdpMLineIndex: sdpMLineIndex2,
ufrag: null
usernameFragment: null
}))
.then(() => {
assert_candidate_line_after(pc.remoteDescription.sdp,
mediaLine2, candidateLine2);
});
}, 'Add candidate for media stream 2 with null ufrag should succeed');
}, 'Add candidate for media stream 2 with null usernameFragment should succeed');
/*
4.3.2. addIceCandidate
4.5. If candidate.ufrag is neither undefined nor null, and is not equal
to any ufrag present in the corresponding media description of an
4.5. If candidate.usernameFragment is neither undefined nor null, and is not equal
to any usernameFragment present in the corresponding media description of an
applied remote description, reject p with a newly created
OperationError and abort these steps.
*/
@ -503,12 +483,12 @@ a=rtcp-rsize
pc.addIceCandidate({
candidate: candidateStr1,
sdpMid, sdpMLineIndex,
ufrag: 'invalid'
usernameFragment: 'invalid'
})));
}, 'Add candidate with invalid ufrag should reject with OperationError');
}, 'Add candidate with invalid usernameFragment should reject with OperationError');
/*
4.3.2. addIceCandidate
4.4.2. addIceCandidate
4.6.1. If candidate could not be successfully added the user agent MUST
queue a task that runs the following steps:
2. Reject p with a DOMException object whose name attribute has
@ -524,7 +504,7 @@ a=rtcp-rsize
promise_rejects(t, 'OperationError',
pc.addIceCandidate({
candidate: invalidCandidateStr,
sdpMid, sdpMLineIndex, ufrag
sdpMid, sdpMLineIndex, usernameFragment
})));
}, 'Add candidate with invalid candidate string should reject with OperationError');
@ -540,52 +520,8 @@ a=rtcp-rsize
candidate: candidateStr2,
sdpMid: sdpMid2,
sdpMLineIndex: sdpMLineIndex2,
ufrag: ufrag
usernameFragment
})));
}, 'Add candidate with sdpMid belonging to different ufrag should reject with OperationError');
}, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError');
/*
TODO
4.3.2. addIceCandidate
4.6. In parallel, add the ICE candidate candidate as described in [JSEP]
(section 4.1.17.). Use candidate.ufrag to identify the ICE generation;
If the ufrag is null, process the candidate for the most recent ICE
generation.
- Call with candidate string containing partial malformed syntax, i.e. malformed IP.
Some browsers may ignore the syntax error and add it to the SDP regardless.
Non-Testable
4.3.2. addIceCandidate
4.6. (The steps are non-testable because the abort step in enqueue operation
steps in before they can reach here):
1. If candidate could not be successfully added the user agent MUST
queue a task that runs the following steps:
1. If connection's [[isClosed]] slot is true, then abort
these steps.
2. If candidate is applied successfully, the user agent MUST queue
a task that runs the following steps:
1. If connection's [[isClosed]] slot is true, then abort these steps.
Issues
w3c/webrtc-pc#1213
addIceCandidate end of candidates woes
w3c/webrtc-pc#1216
Clarify addIceCandidate behavior when adding candidate after end of candidate
w3c/webrtc-pc#1227
addIceCandidate may add ice candidate to the wrong remote description
w3c/webrtc-pc#1345
Make promise rejection/enqueing consistent
Coverage Report
Total: 23
Tested: 19
Not Tested: 2
Non-Testable: 2
*/
</script>

View file

@ -358,7 +358,7 @@ const trackFactories = {
*/
canCreate(requested) {
const supported = {
audio: !!window.MediaStreamAudioDestinationNode,
audio: !!window.AudioContext && !!window.MediaStreamAudioDestinationNode,
video: !!HTMLCanvasElement.prototype.captureStream
};

View file

@ -92,11 +92,11 @@ both the sdpMid and sdpMLineIndex dictionary members are null, throw a TypeError
const candidate = "";
const sdpMid = "sdpMid";
const sdpMLineIndex = 1;
const ufrag = "";
const usernameFragment = "";
const url = "foo.bar";
test(() => {
const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, ufrag });
const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, usernameFragment });
const event = new RTCPeerConnectionIceEvent("type", {
candidate: iceCandidate,
url,
@ -108,33 +108,10 @@ test(() => {
}, "RTCPeerConnectionIceEvent with RTCIceCandidate");
test(() => {
const plain = { candidate, sdpMid, sdpMLineIndex, ufrag };
const plain = { candidate, sdpMid, sdpMLineIndex, usernameFragment };
assert_throws(new TypeError(), () => new RTCPeerConnectionIceEvent("type", { candidate: plain }));
}, "RTCPeerConnectionIceEvent with non RTCIceCandidate object throws");
/*
This will remain commented out until https://github.com/w3c/webrtc-pc/issues/1232
is resolved.
test(() => {
// When firing an RTCPeerConnectionIceEvent event that contains a RTCIceCandidate
// object, it must include values for both sdpMid and sdpMLineIndex.
assert_throws(new TypeError(), () => {
new RTCPeerConnectionIceEvent("type", {
candidate: new RTCIceCandidate({ candidate, sdpMid, ufrag })
});
});
assert_throws(new TypeError(), () => {
new RTCPeerConnectionIceEvent("type", {
candidate: new RTCIceCandidate({ candidate, sdpMLineIndex, ufrag })
});
});
}, "RTCIceCandidate must include values for both sdpMid and sdpMLineIndex");
*/
test(() => {
const event = new RTCPeerConnectionIceEvent("type", {
candidate: null,
@ -145,4 +122,5 @@ test(() => {
assert_true(event.bubbles);
assert_true(event.cancelable);
}, "RTCPeerConnectionIceEvent bubbles and cancelable");
</script>

View file

@ -0,0 +1,9 @@
<!doctype html>
<script>
window.onmessage = async (event) => {
let certificate = event.data;
if (!certificate)
certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256'});
event.source.postMessage(certificate, "*");
}
</script>

View file

@ -0,0 +1,122 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>RTCPeerConnection Connection Test</title>
<script src="RTCPeerConnection-helper.js"></script>
</head>
<body>
<div id="log"></div>
<div>
<video id="local-view" muted autoplay="autoplay"></video>
<video id="remote-view" muted autoplay="autoplay"/>
</video>
</div>
<!-- These files are in place when executing on W3C. -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="text/javascript">
var test = async_test('Can set up a basic WebRTC call without announcing ssrcs.', {timeout: 5000});
var gFirstConnection = null;
var gSecondConnection = null;
// if the remote video gets video data that implies the negotiation
// as well as the ICE and DTLS connection are up.
document.getElementById('remote-view')
.addEventListener('loadedmetadata', function() {
// Call negotiated: done.
test.done();
});
function getNoiseStreamOkCallback(localStream) {
gFirstConnection = new RTCPeerConnection(null);
gFirstConnection.onicecandidate = onIceCandidateToFirst;
localStream.getTracks().forEach(function(track) {
gFirstConnection.addTrack(track, localStream);
});
gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
var videoTag = document.getElementById('local-view');
videoTag.srcObject = localStream;
};
var onOfferCreated = test.step_func(function(offer) {
gFirstConnection.setLocalDescription(offer);
// remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
var sdp = offer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
.replace(/^a=msid-semantic.*$\r\n/gm, '')
.replace(/^a=msid:.*$\r\n/gm, '');
// This would normally go across the application's signaling solution.
// In our case, the "signaling" is to call this function.
receiveCall(sdp);
});
function receiveCall(offerSdp) {
gSecondConnection = new RTCPeerConnection(null);
gSecondConnection.onicecandidate = onIceCandidateToSecond;
gSecondConnection.ontrack = onRemoteTrack;
var parsedOffer = new RTCSessionDescription({ type: 'offer',
sdp: offerSdp });
gSecondConnection.setRemoteDescription(parsedOffer);
gSecondConnection.createAnswer().then(onAnswerCreated,
failed('createAnswer'));
};
var onAnswerCreated = test.step_func(function(answer) {
gSecondConnection.setLocalDescription(answer);
// remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
var sdp = answer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
.replace(/^a=msid-semantic.*$\r\n/gm, '')
.replace(/^a=msid:.*$\r\n/gm, '');
// Similarly, this would go over the application's signaling solution.
handleAnswer(sdp);
});
function handleAnswer(answerSdp) {
var parsedAnswer = new RTCSessionDescription({ type: 'answer',
sdp: answerSdp });
gFirstConnection.setRemoteDescription(parsedAnswer);
};
var onIceCandidateToFirst = test.step_func(function(event) {
// If event.candidate is null = no more candidates.
if (event.candidate) {
gSecondConnection.addIceCandidate(event.candidate);
}
});
var onIceCandidateToSecond = test.step_func(function(event) {
if (event.candidate) {
gFirstConnection.addIceCandidate(event.candidate);
}
});
var onRemoteTrack = test.step_func(function(event) {
var videoTag = document.getElementById('remote-view');
if (!videoTag.srcObject) {
videoTag.srcObject = event.streams[0];
}
});
// Returns a suitable error callback.
function failed(function_name) {
return test.unreached_func('WebRTC called error callback for ' + function_name);
}
// This function starts the test.
test.step(function() {
getNoiseStream({ video: true, audio: true })
.then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
});
</script>
</body>
</html>