Update web-platform-tests to revision d647a1bc742a533186d8297cae2a2bee669c7780

This commit is contained in:
WPT Sync Bot 2018-10-11 21:45:52 -04:00
parent bf192caf4b
commit 4cf0a092d0
41 changed files with 897 additions and 487 deletions

View file

@ -262509,6 +262509,11 @@
{}
]
],
"css/css-properties-values-api/resources/utils.js": [
[
{}
]
],
"css/css-properties-values-api/support/alt/alt.css": [
[
{}
@ -304389,6 +304394,11 @@
{}
]
],
"service-workers/service-worker/resources/enable-client-message-queue.html": [
[
{}
]
],
"service-workers/service-worker/resources/end-to-end-worker.js": [
[
{}
@ -304864,6 +304874,11 @@
{}
]
],
"service-workers/service-worker/resources/message-vs-microtask.html": [
[
{}
]
],
"service-workers/service-worker/resources/mime-sniffing-worker.js": [
[
{}
@ -304944,6 +304959,11 @@
{}
]
],
"service-workers/service-worker/resources/nested-iframe-parent.html": [
[
{}
]
],
"service-workers/service-worker/resources/nested_load_worker.js": [
[
{}
@ -305329,6 +305349,11 @@
{}
]
],
"service-workers/service-worker/resources/stalling-service-worker.js": [
[
{}
]
],
"service-workers/service-worker/resources/success.py": [
[
{}
@ -328133,6 +328158,12 @@
{}
]
],
"background-fetch/abort.https.window.js": [
[
"/background-fetch/abort.https.window.html",
{}
]
],
"background-fetch/content-security-policy.https.window.js": [
[
"/background-fetch/content-security-policy.https.window.html",
@ -337499,6 +337530,12 @@
{}
]
],
"css/css-properties-values-api/self-utils.html": [
[
"/css/css-properties-values-api/self-utils.html",
{}
]
],
"css/css-properties-values-api/typedom.tentative.html": [
[
"/css/css-properties-values-api/typedom.tentative.html",
@ -443900,12 +443937,16 @@
"8ce9f8faa2acdfe7a2ef8dfc6c1ad8cbdf01c72d",
"support"
],
"background-fetch/abort.https.window.js": [
"db01bf94b85fe9aeb05c63ec02186bbb40ec8206",
"testharness"
],
"background-fetch/content-security-policy.https.window.js": [
"0b5b1cb5e94d3f27bebbb5a462bf1e823dfc57b4",
"testharness"
],
"background-fetch/fetch.https.window.js": [
"77297186ca456148c94ce3375434673aa54a90de",
"9ed7e94da3bf7fc6cba5690813848ed269bfe8eb",
"testharness"
],
"background-fetch/get-ids.https.window.js": [
@ -443945,7 +443986,7 @@
"support"
],
"background-fetch/service_workers/sw.js": [
"af4655dbad4ef6ad6b17d79bb2645aee98ce1102",
"2e3fbfff1a83e2d1f4aa40e738fa305a6eba513c",
"support"
],
"background-fetch/update-ui.https.window.js": [
@ -553705,7 +553746,7 @@
"testharness"
],
"css/css-properties-values-api/registered-property-computation.html": [
"30d6b4bd609bf01f1bb10a485baa787f22b635dc",
"cbcc0bea64d47a296adff0759cb91509ecb5beb4",
"testharness"
],
"css/css-properties-values-api/registered-property-cssom.html": [
@ -553716,6 +553757,14 @@
"d655af661f7fd95ed0289cddb9c5546467d28592",
"testharness"
],
"css/css-properties-values-api/resources/utils.js": [
"c4dc3fd5a8d98106395e3e99566f05d6d9a30c0c",
"support"
],
"css/css-properties-values-api/self-utils.html": [
"530c5f677ad25858a06281a9e526584e57081af5",
"testharness"
],
"css/css-properties-values-api/support/alt/alt.css": [
"aeb6ad5abe0e2b7423b90b0d94ad11dae74e11b7",
"support"
@ -594553,7 +594602,7 @@
"support"
],
"docs/_running-tests/safari.md": [
"e6cedd97f965fe0848df5b29efe6fd32257b79d1",
"3ef508d3780aae433100702f03bdac9f33190c62",
"support"
],
"docs/_writing-tests/ahem.md": [
@ -599853,7 +599902,7 @@
"testharness"
],
"fetch/api/abort/serviceworker-intercepted.https.html": [
"623036d46639fe5aac8a5d5f5bdd9695d2a24dac",
"a88aa896c90bd30dde2800ad5fe428b2410bdec9",
"testharness"
],
"fetch/api/basic/accept-header.any.js": [
@ -600333,7 +600382,7 @@
"support"
],
"fetch/api/request/destination/resources/fetch-destination-worker-no-load-event.js": [
"5a3c679cc03e4694e92051f32b1e7c797ecaff05",
"c1b6c506e957198c97db679c7d25e93952af3376",
"support"
],
"fetch/api/request/destination/resources/fetch-destination-worker.js": [
@ -604645,7 +604694,7 @@
"testharness"
],
"html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html": [
"cac23648ade4c11a4fca671823a6064dbe697652",
"c31e75fdf57e1d35d45afceb24ab2216dfbfe483",
"testharness"
],
"html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-screenx-screeny.html": [
@ -622117,7 +622166,7 @@
"support"
],
"interfaces/web-animations.idl": [
"7dce1002e666d3efa9b18531e05b087f0f4adc0d",
"9a3579da75f23c33512b12e631f24a365080363e",
"support"
],
"interfaces/web-bluetooth.idl": [
@ -622129,7 +622178,7 @@
"support"
],
"interfaces/web-share.idl": [
"36ffa43e37971adc75017cb5e80a9fe98552227e",
"7fa83b0fed51fa17c6e10b5ce065558d314d2f70",
"support"
],
"interfaces/webaudio.idl": [
@ -634385,7 +634434,7 @@
"testharness"
],
"picture-in-picture/resources/picture-in-picture-helpers.js": [
"96972dcbc8ef07aa7ea0150c4ee645507eea0856",
"7561944a18d0296b33dbb3acb1f3a82b1512d08f",
"support"
],
"picture-in-picture/shadow-dom.html": [
@ -643697,7 +643746,7 @@
"testharness"
],
"resource-timing/resource_timing_buffer_full_eventually.html": [
"7ca8237b02cc398786d78dd61aea3dcb1163d48a",
"ce745237c0657c7045b00d9c7b8e71770ed490fc",
"testharness"
],
"resource-timing/resource_timing_buffer_full_when_populate_entries.html": [
@ -647213,7 +647262,7 @@
"testharness"
],
"service-workers/service-worker/postmessage-to-client.https.html": [
"15d2e889337078869e3c3e97d312649e6a8bd8b2",
"b1dc41a018f273832f4ac90c17b4b981f095b0ef",
"testharness"
],
"service-workers/service-worker/postmessage.https.html": [
@ -647329,7 +647378,7 @@
"support"
],
"service-workers/service-worker/resources/about-blank-replacement-ping-frame.py": [
"58fb4403f9c6597d2707b1e3241155fec07189a8",
"bb07c241ad49a7535ba62ee8664a75c8c59cd64c",
"support"
],
"service-workers/service-worker/resources/about-blank-replacement-popup-frame.py": [
@ -647556,6 +647605,10 @@
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
"support"
],
"service-workers/service-worker/resources/enable-client-message-queue.html": [
"512bd14bc67d46b902e68eb8773107de529cc798",
"support"
],
"service-workers/service-worker/resources/end-to-end-worker.js": [
"d45a50556a93c7e38d94ac05b90d2d733c04896a",
"support"
@ -647936,6 +647989,10 @@
"501521ff3e37dfc75bc61f3213c8282410f91fbe",
"support"
],
"service-workers/service-worker/resources/message-vs-microtask.html": [
"2c45c59a475ae9b2e6bc168dc75b31eab9d231f4",
"support"
],
"service-workers/service-worker/resources/mime-sniffing-worker.js": [
"046628055e15ca7291a14247efb560460d01ae24",
"support"
@ -648000,6 +648057,10 @@
"8539b40066dd91bbfaf7ef240b8104dcb2ab3b27",
"support"
],
"service-workers/service-worker/resources/nested-iframe-parent.html": [
"115ab26e1221024b30313569f484942b10f6dba0",
"support"
],
"service-workers/service-worker/resources/nested_load_worker.js": [
"6e2e9edc4d8b35e03f5aa4b29966812addf43444",
"support"
@ -648308,6 +648369,10 @@
"7341132745be2bee9e47114cda4167865e8a9699",
"support"
],
"service-workers/service-worker/resources/stalling-service-worker.js": [
"fdf1e6cac04e1651f30d960897da8740a40c9138",
"support"
],
"service-workers/service-worker/resources/success.py": [
"bcbb487d2b29d4ef089a6c7dc18e1cc166a262fc",
"support"
@ -658833,7 +658898,7 @@
"support"
],
"tools/wpt/browser.py": [
"3b3074a985607abfdb1bd125f3803e25acf7822d",
"51f0dbdba926550725ec4d42bc69cd69106bd19d",
"support"
],
"tools/wpt/commands.json": [
@ -658841,7 +658906,7 @@
"support"
],
"tools/wpt/install.py": [
"62c833aa3f0c707e659f691be7a166d8f7ec43d8",
"f588a412845848b896a063e50f07cd0e3e0758e7",
"support"
],
"tools/wpt/markdown.py": [
@ -658857,7 +658922,7 @@
"support"
],
"tools/wpt/run.py": [
"d9a44fd3711563a0134ad2fbfc2ee90ac73c6fbd",
"da01a816974bfe445967faeaf3855ab5dcb0cf33",
"support"
],
"tools/wpt/testfiles.py": [
@ -658945,7 +659010,7 @@
"support"
],
"tools/wptrunner/requirements.txt": [
"0e71ed50411b6697198d2b19787506ff959d7e11",
"2ae1622a6a398b65cf43a37bca8962bf7d3196a4",
"support"
],
"tools/wptrunner/requirements_chrome.txt": [
@ -659581,7 +659646,7 @@
"support"
],
"tools/wptserve/tests/functional/base.py": [
"f8331f5086d31730a8b86c0b708162d8e505f30d",
"190e385f1020a7a5184fa34ad5bd59a75920a15c",
"support"
],
"tools/wptserve/tests/functional/docroot/document.txt": [
@ -659709,7 +659774,7 @@
"support"
],
"tools/wptserve/tests/functional/test_pipes.py": [
"fdac4537d64fb5d9c1fb8dd3e148cac7c5ec240a",
"693cb82e2410b6a66ce15085fb91218f04eb683c",
"support"
],
"tools/wptserve/tests/functional/test_request.py": [
@ -665337,7 +665402,7 @@
"testharness"
],
"webrtc/RTCDTMFSender-helper.js": [
"1dd2bccb361d4baefc18d33252c15e6d984caeed",
"84cc771dda283da81a0568fe58ad52a77a262347",
"support"
],
"webrtc/RTCDTMFSender-insertDTMF.https.html": [
@ -665349,7 +665414,7 @@
"testharness"
],
"webrtc/RTCDTMFSender-ontonechange.https.html": [
"6beefb5287d65f5bf90b5866e0881f6d8de385fb",
"ff6d117b3c75dde71cc52b4087f223477ad08bb4",
"testharness"
],
"webrtc/RTCDataChannel-bufferedAmount.html": [

View file

@ -71,6 +71,3 @@
[bottom intermediate]
expected: FAIL
[border-bottom-width end]
expected: FAIL

View file

@ -1,4 +1,5 @@
[fetch-in-iframe.html]
expected: CRASH
[Untitled]
expected: FAIL

View file

@ -1,4 +0,0 @@
[traverse_the_history_1.html]
[Multiple history traversals from the same task]
expected: FAIL

View file

@ -1,4 +0,0 @@
[traverse_the_history_5.html]
[Multiple history traversals, last would be aborted]
expected: FAIL

View file

@ -5,3 +5,6 @@
[invalid feature names should not tokenize as "noopener"]
expected: FAIL
[Integer value of 0 should not activate the feature]
expected: FAIL

View file

@ -11,7 +11,7 @@
expected: TIMEOUT
[picture: source (max-width:500px) valid image, img valid image, resize to narrow]
expected: TIMEOUT
expected: FAIL
[img (srcset 1 cand) valid image, resize to wide]
expected: FAIL
@ -22,3 +22,12 @@
[picture: source (max-width:500px) valid image, img broken image, resize to wide]
expected: FAIL
[picture: source (max-width:500px) broken image, img valid image, resize to narrow]
expected: FAIL
[img (srcset 1 cand) valid image, resize to narrow]
expected: FAIL
[picture: same URL in source (max-width:500px) and img, resize to narrow]
expected: FAIL

View file

@ -1,10 +0,0 @@
[non-active-document.html]
[DOMParser]
expected: FAIL
[createHTMLDocument]
expected: FAIL
[<template>]
expected: FAIL

View file

@ -1,4 +0,0 @@
[DOMContentLoaded-defer.html]
[The end: DOMContentLoaded and defer scripts]
expected: FAIL

View file

@ -2,3 +2,6 @@
[document.open() after parser is aborted]
expected: FAIL
[async document.open() after parser is aborted]
expected: FAIL

View file

@ -1,283 +0,0 @@
[quirks.html]
[top: -\\31 .5]
expected: FAIL
[bottom: -1A]
expected: FAIL
[bottom: -1a]
expected: FAIL
[top: @1]
expected: FAIL
[top: "1a"]
expected: FAIL
[top: @a]
expected: FAIL
[bottom: "1"]
expected: FAIL
[bottom: -/**/1]
expected: FAIL
[top: +/**/1]
expected: FAIL
[bottom: @1a]
expected: FAIL
[top: 1\\31 ]
expected: FAIL
[top: url('1')]
expected: FAIL
[bottom: -\\31 ]
expected: FAIL
[top: calc(1)]
expected: FAIL
[top: \\31 ]
expected: FAIL
[bottom: +1\\31 ]
expected: FAIL
[bottom: 1\\31 .5]
expected: FAIL
[bottom: #0001]
expected: FAIL
[top: calc(2 * 2px)]
expected: FAIL
[bottom: 1a]
expected: FAIL
[bottom: A]
expected: FAIL
[bottom: #01]
expected: FAIL
[top: +\\31 .5]
expected: FAIL
[bottom: #1]
expected: FAIL
[top: -/**/1]
expected: FAIL
[bottom: +\\31 .5]
expected: FAIL
[bottom: \\31 ]
expected: FAIL
[bottom: calc(1)]
expected: FAIL
[top: #001]
expected: FAIL
[top: +\\31 ]
expected: FAIL
[bottom: +\\31 ]
expected: FAIL
[top: +1.5]
expected: FAIL
[top: +1\\31 ]
expected: FAIL
[bottom: @a]
expected: FAIL
[bottom: @1]
expected: FAIL
[top: #1]
expected: FAIL
[top: 1a]
expected: FAIL
[bottom: +1a]
expected: FAIL
[bottom: +1A]
expected: FAIL
[bottom: "a"]
expected: FAIL
[top: #00001]
expected: FAIL
[bottom: -1\\31 .5]
expected: FAIL
[top: "1"]
expected: FAIL
[bottom: 1.5]
expected: FAIL
[bottom: -\\31 .5]
expected: FAIL
[bottom: url('1')]
expected: FAIL
[bottom: -1.5]
expected: FAIL
[top: \\31 .5]
expected: FAIL
[bottom: "1a"]
expected: FAIL
[bottom: calc(2 * 2px)]
expected: FAIL
[bottom: +1\\31 .5]
expected: FAIL
[bottom: 1\\31 ]
expected: FAIL
[bottom: +/**/1]
expected: FAIL
[bottom: #00001]
expected: FAIL
[top: url(1)]
expected: FAIL
[bottom: #001]
expected: FAIL
[top: +1\\31 .5]
expected: FAIL
[top: -1a]
expected: FAIL
[top: -1A]
expected: FAIL
[bottom: url(1)]
expected: FAIL
[top: a]
expected: FAIL
[top: A]
expected: FAIL
[top: #000001]
expected: FAIL
[top: 1]
expected: FAIL
[top: 1\\31 .5]
expected: FAIL
[bottom: a]
expected: FAIL
[bottom: 1]
expected: FAIL
[bottom: +1]
expected: FAIL
[bottom: #000001]
expected: FAIL
[bottom: +a]
expected: FAIL
[bottom: +A]
expected: FAIL
[top: 1.5]
expected: FAIL
[top: +A]
expected: FAIL
[top: +a]
expected: FAIL
[top: +1]
expected: FAIL
[top: -1.5]
expected: FAIL
[top: -1\\31 .5]
expected: FAIL
[top: +1a]
expected: FAIL
[top: +1A]
expected: FAIL
[top: @1a]
expected: FAIL
[bottom: \\31 .5]
expected: FAIL
[top: "a"]
expected: FAIL
[top: #01]
expected: FAIL
[bottom: +1.5]
expected: FAIL
[bottom: -A]
expected: FAIL
[bottom: -a]
expected: FAIL
[bottom: -1\\31 ]
expected: FAIL
[top: #0001]
expected: FAIL
[bottom: -1]
expected: FAIL
[top: -\\31 ]
expected: FAIL
[top: -A]
expected: FAIL
[top: -a]
expected: FAIL
[top: -1]
expected: FAIL
[top: -1\\31 ]
expected: FAIL

View file

@ -11,20 +11,41 @@
[response.formData() with input: a=b&c=d&]
expected: FAIL
[urlencoded-parser.any.worker.html]
[request.formData() with input: a&b&c]
expected: FAIL
[response.formData() with input: a&b&c]
expected: FAIL
[request.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[request.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL
[response.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL
[response.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[request.formData() with input: a=b&c=d&]
expected: FAIL
[urlencoded-parser.any.worker.html]
[request.formData() with input: a&b&c]
expected: FAIL
[request.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[request.formData() with input: a=b&c=d]
expected: FAIL
[response.formData() with input: a=b&c=d&]
expected: FAIL
[response.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL
[response.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[response.formData() with input: a=b&c=d]
expected: FAIL

View file

@ -1,2 +1,73 @@
[realtimeanalyser-fft-scaling.html]
expected: TIMEOUT
[X 2048-point FFT peak position is not equal to 64. Got 0.]
expected: FAIL
[X 128-point FFT peak position is not equal to 4. Got 0.]
expected: FAIL
[X 32768-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 64-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 4096-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[< [FFT scaling tests\] 22 out of 22 assertions were failed.]
expected: FAIL
[X 128-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 8192-point FFT peak position is not equal to 256. Got 0.]
expected: FAIL
[X 32-point FFT peak value in dBFS is not greater than or equal to -14.43. Got -1000.]
expected: FAIL
[X 16384-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 256-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 8192-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 1024-point FFT peak position is not equal to 32. Got 0.]
expected: FAIL
[X 64-point FFT peak position is not equal to 2. Got 0.]
expected: FAIL
[X 512-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 32-point FFT peak position is not equal to 1. Got 0.]
expected: FAIL
[X 16384-point FFT peak position is not equal to 512. Got 0.]
expected: FAIL
[X 1024-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 2048-point FFT peak value in dBFS is not greater than or equal to -13.56. Got -1000.]
expected: FAIL
[X 32768-point FFT peak position is not equal to 1024. Got 0.]
expected: FAIL
[X 4096-point FFT peak position is not equal to 128. Got 0.]
expected: FAIL
[X 512-point FFT peak position is not equal to 16. Got 0.]
expected: FAIL
[X 256-point FFT peak position is not equal to 8. Got 0.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL

View file

@ -0,0 +1,59 @@
// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
// META: script=resources/utils.js
'use strict';
// Covers basic functionality provided by BackgroundFetchManager.abort().
// https://wicg.github.io/background-fetch/#background-fetch-registration-abort
backgroundFetchTest(async (test, backgroundFetch) => {
const registration = await backgroundFetch.fetch(
uniqueId(),
['resources/feature-name.txt', '/serviceworker/resources/slow-response.php']);
assert_true(await registration.abort());
assert_false(await registration.abort());
}, 'Aborting the same registration twice fails');
backgroundFetchTest(async (test, backgroundFetch) => {
const registration = await backgroundFetch.fetch(
uniqueId(),
['resources/feature-name.txt', '/serviceworker/resources/slow-response.php']);
await new Promise(resolve => {
let aborted = false;
const expectedResultText = 'Background Fetch';
registration.onprogress = async event => {
if (event.target.downloaded < expectedResultText.length)
return;
if (aborted)
return;
// Abort after the first file has been downloaded and check the results.
aborted = true;
assert_true(await registration.abort());
const {type, eventRegistration, results} = await getMessageFromServiceWorker();
assert_equals(eventRegistration.result, 'failure');
assert_equals(eventRegistration.failureReason, 'aborted');
assert_equals(registration.result, 'failure');
assert_equals(registration.failureReason, 'aborted');
assert_equals(type, 'backgroundfetchabort');
// The abort might have gone through before the first result was persisted.
if (results.length === 1) {
assert_true(results[0].url.includes('resources/feature-name.txt'));
assert_equals(results[0].status, 200);
assert_equals(results[0].text, expectedResultText);
}
resolve();
};
});
}, 'Calling BackgroundFetchRegistration.abort sets the correct fields and responses are still available');

View file

@ -145,6 +145,24 @@ backgroundFetchTest(async (test, backgroundFetch) => {
}, 'Using Background Fetch to successfully fetch a single resource');
backgroundFetchTest(async (test, backgroundFetch) => {
const registrationId = uniqueId();
const registration =
await backgroundFetch.fetch(registrationId, 'resources/feature-name.txt');
assert_equals(registration.result, '');
assert_equals(registration.failureReason, '');
const {type, eventRegistration, results} =
await getMessageFromServiceWorker();
assert_equals('backgroundfetchsuccess', type);
assert_equals(eventRegistration.id, registration.id);
assert_equals(registration.result, 'success');
assert_equals(registration.failureReason, '');
}, 'Registration object gets updated values when a background fetch completes.');
backgroundFetchTest(async (test, backgroundFetch) => {
const registrationId = uniqueId();
@ -240,6 +258,9 @@ backgroundFetchTest(async (test, backgroundFetch) => {
assert_equals(eventRegistration.result, 'failure');
assert_equals(eventRegistration.failureReason, 'bad-status');
assert_equals(registration.result, 'failure');
assert_equals(registration.failureReason, 'bad-status');
}, 'Using Background Fetch to fetch a non-existent resource should fail.');
backgroundFetchTest(async (test, backgroundFetch) => {

View file

@ -27,3 +27,4 @@ function handleBackgroundFetchUpdateEvent(event) {
self.addEventListener('backgroundfetchsuccess', handleBackgroundFetchUpdateEvent);
self.addEventListener('backgroundfetchfail', handleBackgroundFetchUpdateEvent);
self.addEventListener('backgroundfetchabort', handleBackgroundFetchUpdateEvent);

View file

@ -1,117 +1,115 @@
<!DOCTYPE HTML>
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#calculation-of-computed-values" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<style>
#divWithFontSizeSet, #parentDiv {
font-size: 10px;
}
#divWithFontSizeSet, #divWithFontSizeInherited {
--length-1: 12px;
--length-2: 13vw;
--length-3: 14em;
--length-4: 15vmin;
--length-5: calc(16px - 7em + 10vh);
--length-6: var(--length-3);
--length-percentage-1: 17em;
--length-percentage-2: 18%;
--length-percentage-3: calc(19em - 2%);
--csv-1: 10px, 3em;
--csv-2: 4em ,9px;
--csv-3: 8em;
--csv-4: 3% , 10vmax , 22px;
--csv-5: calc(50% + 1em), 4px;
--csv-6: calc(13% + 37px);
--list-1: 10px 3em;
--list-2: 4em 9px;
--list-3: 3% 10vmax 22px;
--list-4: calc(50% + 1em) 4px;
--transform-function-1: translateX(2px);
--transform-function-2: translateX(10em);
--transform-function-3: translateX(calc(11em + 10%));
--transform-function-4: translateX(10%) scale(2);
}
</style>
<div id=divWithFontSizeSet></div>
<div id=parentDiv>
<div id=divWithFontSizeInherited></div>
</div>
<div id="ref"></div>
<script>
test(() => {
CSS.registerProperty({name: '--length-1', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-2', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-3', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-4', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-5', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-6', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-percentage-1', syntax: '<length-percentage>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-percentage-2', syntax: '<length-percentage>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-percentage-3', syntax: '<length-percentage>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-1', syntax: '<length>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-2', syntax: '<length>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-3', syntax: '<length>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-4', syntax: '<length-percentage>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-5', syntax: '<length-percentage>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--csv-6', syntax: '<length-percentage>#', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--list-1', syntax: '<length>+', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--list-2', syntax: '<length>+', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--list-3', syntax: '<length-percentage>+', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--list-4', syntax: '<length-percentage>+', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--transform-function-1', syntax: '<transform-function>', initialValue: 'translateX(0px)', inherits: false});
CSS.registerProperty({name: '--transform-function-2', syntax: '<transform-function>', initialValue: 'translateX(0px)', inherits: false});
CSS.registerProperty({name: '--transform-function-3', syntax: '<transform-function>', initialValue: 'translateX(0px)', inherits: false});
CSS.registerProperty({name: '--transform-function-4', syntax: '<transform-function>+', initialValue: 'translateX(0px)', inherits: false});
}, "CSS.registerProperty");
for (var element of [divWithFontSizeSet, divWithFontSizeInherited]) {
var id = element.id;
var computedStyle = getComputedStyle(element);
for (let element of [divWithFontSizeSet, divWithFontSizeInherited]) {
let id = element.id;
// Generate a property and temporarily set its value. Then call 'fn' with
// the name of the generated property.
function with_custom_property(reg, value, fn) {
let name = generate_property(reg);
// Because we want to include the parsing step, insert a stylesheet
// node with textContent.
let node = document.createElement('style');
node.textContent = `#${id} { ${name}: ${value}; }`;
document.body.append(node);
try {
fn(name);
} finally {
node.remove();
}
}
function assert_computed_value(syntax, value, expected) {
with_custom_property(syntax, value, (name) => {
let actual = getComputedStyle(element).getPropertyValue(name);
assert_equals(actual, expected);
});
}
// Computes an absolute reference value for some length.
//
// E.g. to figure out how many pixels '10vh' is, do length_ref('10vh').
function length_ref(value, refnode = ref) {
try {
// The reference property 'min-height' is chosen arbitrarily, but
// avoid properties with "resolved value is used value"-behavior
// [1], as it may affect rounding, and custom properties do not
// have this behavior.
//
// [1] https://drafts.csswg.org/cssom/#resolved-values
const ref_property = 'min-height';
refnode.style = `${ref_property}: ${value}`;
return getComputedStyle(refnode).getPropertyValue(ref_property);
} finally {
refnode.style = '';
}
}
test(function() {
assert_equals(computedStyle.getPropertyValue('--length-1'), '12px');
assert_equals(computedStyle.getPropertyValue('--length-2'), '104px');
assert_equals(computedStyle.getPropertyValue('--length-3'), '140px');
assert_equals(computedStyle.getPropertyValue('--length-4'), '90px');
assert_equals(computedStyle.getPropertyValue('--length-5'), '6px');
assert_equals(computedStyle.getPropertyValue('--length-6'), '140px');
assert_computed_value('<length>', '12px', '12px');
assert_computed_value('<length>', '13vw', length_ref('13vw'));
assert_computed_value('<length>', '14em', '140px');
assert_computed_value('<length>', '15vmin', length_ref('15vmin'));
assert_computed_value('<length>', 'calc(16px - 7em + 10vh)', length_ref('calc(10vh - 54px)'));
with_custom_property('<length>', '14em', (name) => {
assert_computed_value('<length>', `var(${name})`, '140px');
});
}, "<length> values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--length-percentage-1'), '170px');
assert_equals(computedStyle.getPropertyValue('--length-percentage-2'), '18%');
assert_equals(computedStyle.getPropertyValue('--length-percentage-3'), 'calc(190px + -2%)');
assert_computed_value('<length-percentage>', '17em', '170px');
assert_computed_value('<length-percentage>', '18%', '18%');
assert_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(190px + -2%)');
}, "<length-percentage> values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--csv-1'), '10px, 30px');
assert_equals(computedStyle.getPropertyValue('--csv-2'), '40px, 9px');
assert_equals(computedStyle.getPropertyValue('--csv-3'), '80px');
assert_computed_value('<length>#', '10px, 3em', '10px, 30px');
assert_computed_value('<length>#', '10px, 3em', '10px, 30px');
assert_computed_value('<length>#', '4em ,9px', '40px, 9px');
assert_computed_value('<length>#', '8em', '80px');
}, "<length># values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--csv-4'), '3%, 80px, 22px');
assert_equals(computedStyle.getPropertyValue('--csv-5'), 'calc(10px + 50%), 4px');
assert_equals(computedStyle.getPropertyValue('--csv-6'), 'calc(37px + 13%)');
assert_computed_value('<length-percentage>#', '3% , 10vmax , 22px', ['3%', length_ref('10vmax'), '22px'].join(', '));
assert_computed_value('<length-percentage>#', 'calc(50% + 1em), 4px', 'calc(10px + 50%), 4px');
assert_computed_value('<length-percentage>#', 'calc(13% + 37px)', 'calc(37px + 13%)');
}, "<length-percentage># values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--list-1'), '10px 30px');
assert_equals(computedStyle.getPropertyValue('--list-2'), '40px 9px');
assert_computed_value('<length>+', '10px 3em', '10px 30px');
assert_computed_value('<length>+', '4em 9px', '40px 9px');
}, "<length>+ values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--list-3'), '3% 80px 22px');
assert_equals(computedStyle.getPropertyValue('--list-4'), 'calc(10px + 50%) 4px');
assert_computed_value('<length-percentage>+', '3% 10vmax 22px', ['3%', length_ref('10vmax'), '22px'].join(' '));
assert_computed_value('<length-percentage>+', 'calc(50% + 1em) 4px', 'calc(10px + 50%) 4px');
}, "<length-percentage>+ values are computed correctly for " + id);
test(function() {
assert_equals(computedStyle.getPropertyValue('--transform-function-1'), 'translateX(2px)');
assert_equals(computedStyle.getPropertyValue('--transform-function-2'), 'translateX(100px)');
assert_equals(computedStyle.getPropertyValue('--transform-function-3'), 'translateX(calc(110px + 10%))');
assert_equals(computedStyle.getPropertyValue('--transform-function-4'), 'translateX(10%) scale(2)');
assert_computed_value('<transform-function>', 'translateX(2px)', 'translateX(2px)');
assert_computed_value('<transform-function>', 'translateX(10em)', 'translateX(100px)');
assert_computed_value('<transform-function>', 'translateX(calc(11em + 10%))', 'translateX(calc(110px + 10%))');
assert_computed_value('<transform-function>+', 'translateX(10%) scale(2)', 'translateX(10%) scale(2)');
}, "<transform-function> values are computed correctly for " + id);
}
</script>

View file

@ -0,0 +1,86 @@
let next_property_id = 1;
// Generate a unique property name on the form --prop-N.
function generate_name() {
return `--prop-${next_property_id++}`;
}
// Produce a compatible initial value for the specified syntax.
function any_initial_value(syntax) {
let components = syntax.split('|').map(x => x.trim())
let first_component = components[0];
if (first_component.endsWith('+') || first_component.endsWith('#'))
first_component = first_component.slice(0, -1);
switch (first_component) {
case '*':
case '<custom-ident>':
return 'NULL';
case '<angle>':
return '0deg';
case '<color>':
return 'rgb(0, 0, 0)';
case '<image>':
case '<url>':
return 'url(0)';
case '<integer>':
case '<length-percentage>':
case '<length>':
case '<number>':
return '0';
case '<percentage>':
return '0%';
case '<resolution>':
return '0dpi';
case '<time>':
return '0s';
case '<transform-function>':
case '<transform-list>':
return 'matrix(0, 0, 0, 0, 0, 0)';
default:
// We assume syntax is a specific custom ident.
return first_component;
}
}
// Registers a unique property on the form '--prop-N' and returns the name.
// Any value except 'syntax' may be omitted, in which case the property will
// not inherit, and some undefined (but compatible) initial value will be
// generated. If a single string is used as the argument, it is assumed to be
// the syntax.
function generate_property(reg) {
let syntax = typeof(reg) === 'string' ? reg : reg.syntax;
let initial = typeof(reg.initialValue) === 'undefined' ? any_initial_value(syntax)
: reg.initialValue;
let inherits = typeof(reg.inherits) === 'undefined' ? false : reg.inherits;
let name = generate_name();
CSS.registerProperty({
name: name,
syntax: syntax,
initialValue: initial,
inherits: inherits
});
return name;
}
function all_syntaxes() {
return [
'*',
'<angle>',
'<color>',
'<custom-ident>',
'<image>',
'<integer>',
'<length-percentage>',
'<length>',
'<number>',
'<percentage>',
'<resolution>',
'<time>',
'<transform-function>',
'<transform-list>',
'<url>'
]
}

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<title>Self-test for utils.js</title>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id=outer><div id=inner></div></div>
<script>
test(function(){
let syntaxes = all_syntaxes().concat([
'foo',
'bar | <length>',
'<angle> | <length>'
]);
// Don't throw:
syntaxes.forEach(generate_property);
}, 'Default initial values of generated properties are valid (self-test).');
test(function(){
try {
let inherited = generate_property({ syntax: '<length>', inherits: true });
let non_inherited = generate_property({ syntax: '<length>', inherits: false, initialValue: '5px' });
outer.style = `${inherited}: 10px; ${non_inherited}: 11px;`;
assert_equals(getComputedStyle(outer).getPropertyValue(inherited), '10px');
assert_equals(getComputedStyle(outer).getPropertyValue(non_inherited), '11px');
assert_equals(getComputedStyle(inner).getPropertyValue(inherited), '10px');
assert_equals(getComputedStyle(inner).getPropertyValue(non_inherited), '5px');
} finally {
outer.style = '';
inner.style = '';
}
}, 'Generated properties respect inherits flag');
</script>

View file

@ -22,7 +22,7 @@ Now, run the tests using the `safari` product:
```
This will use the `safaridriver` found on the path, which will be stable Safari.
To run Safari Technology Preview instead, use the `--webdriver-binary` argument:
To run Safari Technology Preview instead, use the `--channel=preview` argument:
```
./wpt run --webdriver-binary "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" safari [test_list]
./wpt run --channel=preview safari [test_list]
```

View file

@ -21,7 +21,8 @@
}
promise_test(async t => {
const scope = SCOPE + "?q=aborted-not-intercepted";
const suffix = "?q=aborted-not-intercepted";
const scope = SCOPE + suffix;
await setupRegistration(t, scope);
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
@ -33,8 +34,13 @@
const nextData = new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', function once(event) {
w.navigator.serviceWorker.removeEventListener('message', once);
resolve(event.data);
// The message triggered by the iframe's document's fetch
// request cannot get dispatched by the time we add the event
// listener, so we have to guard against it.
if (!event.data.endsWith(suffix)) {
w.navigator.serviceWorker.removeEventListener('message', once);
resolve(event.data);
}
})
});

View file

@ -1,7 +1,8 @@
self.addEventListener('fetch', function(event) {
if (event.request.url.includes('dummy')) {
const url = event.request.url;
if (url.includes('dummy') && url.includes('?')) {
event.waitUntil(async function() {
let destination = new URL(event.request.url).searchParams.get("dest");
let destination = new URL(url).searchParams.get("dest");
var result = "FAIL";
if (event.request.destination == destination) {
result = "PASS";

View file

@ -40,8 +40,10 @@ test (t => {
'noOpenER',
' NOopener',
'=NOOPENER',
'noopener=NOOPENER', // => ('noopener', 'noopener')
'NOOPENER=noopener' // => ('noopener', 'noopener')
'noopener=1',
'NOOPENER=1',
'NOOPENER=yes',
'noopener=YES',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
@ -82,9 +84,9 @@ test (t => {
'noopener==,',
'noopener=\n ,',
'noopener = \t ,',
'noopener\n=\r noopener,', // => ('noopener', 'noopener')
'noopener\n=\r 1,', // => ('noopener', '1')
'noopener=,yes', // => ('noopener'), ('yes')
'noopener= foo=,', // => ('noopener', 'foo')
'noopener= yes=,', // => ('noopener', 'yes')
'noopener = \u000Cyes' // => ('noopener', 'yes')
];
featureVariants.forEach(feature => {
@ -96,14 +98,14 @@ test (t => {
test (t => {
// Tokenizing `value` should collect any non-separator code points until first separator
var featureVariants = [
'noopener=noopener', // => ('noopener', 'noopener')
'noopener=1', // => ('noopener', 'noopener')
'noopener=yes', // => ('noopener', 'yes')
'noopener = yes ,', // => ('noopener', 'yes')
'noopener=\nyes ,', // => ('noopener', 'yes')
'noopener=yes yes', // => ('noopener', 'yes'), ('yes', '')
'noopener=yes\ts', // => ('noopener', 'yes'), ('s', '')
'noopener==', // => ('noopener', '')
'noopener=0\n,', // => ('noopener', '0')
'noopener=1\n,', // => ('noopener', '1')
'==noopener===', // => ('noopener', '')
'noopener==\u000C' // => ('noopener', '')
];
@ -114,20 +116,30 @@ test (t => {
}, 'Tokenizing should read characters until first window feature separator as `value`');
test (t => {
// If tokenizedFeatures contains an entry with the key "noopener"...disown opener
// i.e. `value` should be irrelevant
var featureVariants = [
'noopener=false',
',noopener=0, ',
'foo=bar,noopener=noopener,',
'noopener=true',
'noopener=foo\nbar\t'
'noopener=1',
'noopener=2',
'noopener=12345',
'noopener=1.5',
'noopener=-1',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
});
}, '"noopener" should be based on name (key), not value');
}, 'Integer values other than 0 should activate the feature');
test (t => {
var featureVariants = [
'noopener=0',
'noopener=0.5',
'noopener=error',
];
featureVariants.forEach(feature => {
var win = window.open(windowURL, '', feature);
assert_not_equals(win, null, `"${feature}" should NOT activate feature "noopener"`);
});
}, 'Integer value of 0 should not activate the feature');
test (t => {
var invalidFeatureVariants = [

View file

@ -1,7 +1,7 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into reffy-reports
// (https://github.com/tidoust/reffy-reports)
// Source: Web Animations (https://w3c.github.io/web-animations/)
// Source: Web Animations (https://drafts.csswg.org/web-animations-1/)
[Exposed=Window]
interface AnimationTimeline {

View file

@ -1,7 +1,7 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into reffy-reports
// (https://github.com/tidoust/reffy-reports)
// Source: Web Share API (https://wicg.github.io/web-share/)
// Source: Web Share API - Level 1 (https://wicg.github.io/web-share/)
partial interface Navigator {
[SecureContext] Promise<void> share(optional ShareData data);

View file

@ -1,9 +1,3 @@
if (!('pictureInPictureEnabled' in document)) {
HTMLVideoElement.prototype.requestPictureInPicture = function() {
return Promise.reject('Picture-in-Picture API is not available');
}
}
function loadVideo(activeDocument, sourceUrl) {
return new Promise((resolve, reject) => {
const document = activeDocument || window.document;

View file

@ -16,15 +16,23 @@
function() {
// Scripts appended in JS to ensure setResourceTimingBufferSize is called before.
let counter = performance.getEntriesByType("resource").length;
function appendScript() {
const src = "resources/empty.js?" + counter;
const script = document.createElement('script');
script.type = 'text/javascript';
script.onload = function() { ++counter; appendScript()};
script.src = src;
document.body.appendChild(script);
function appendScripts() {
const documentFragment = document.createDocumentFragment();
// Add 100 elements at a time to avoid page reflow every time.
let numScriptsAccumulated = 0;
while (numScriptsAccumulated < 100) {
const src = "resources/empty.js?" + counter;
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
documentFragment.appendChild(script);
++counter;
++numScriptsAccumulated;
}
document.body.appendChild(documentFragment);
t.step_timeout(appendScripts, 20);
}
appendScript();
appendScripts();
});
</script>
</body>

View file

@ -51,4 +51,208 @@ promise_test(t => {
})
.then(e => { assert_equals(e.data, 'quit'); });
}, 'postMessage from ServiceWorker to Client.');
// This function creates a message listener that captures all messages
// sent to this window and matches them with corresponding requests.
// This frees test code from having to use clunky constructs just to
// avoid race conditions, since the relative order of message and
// request arrival doesn't matter.
function create_message_listener(t) {
const listener = {
messages: new Set(),
requests: new Set(),
waitFor: function(predicate) {
for (const event of this.messages) {
// If a message satisfying the predicate has already
// arrived, it gets matched to this request.
if (predicate(event)) {
this.messages.delete(event);
return Promise.resolve(event);
}
}
// If no match was found, the request is stored and a
// promise is returned.
const request = { predicate };
const promise = new Promise(resolve => request.resolve = resolve);
this.requests.add(request);
return promise;
}
};
window.onmessage = t.step_func(event => {
for (const request of listener.requests) {
// If the new message matches a stored request's
// predicate, the request's promise is resolved with this
// message.
if (request.predicate(event)) {
listener.requests.delete(request);
request.resolve(event);
return;
}
};
// No outstanding request for this message, store it in case
// it's requested later.
listener.messages.add(event);
});
return listener;
}
async function service_worker_register_and_activate(t, script, scope) {
const registration = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => registration.unregister());
const worker = registration.installing;
await wait_for_state(t, worker, 'activated');
return worker;
}
// Add an iframe (parent) whose document contains a nested iframe
// (child), then set the child's src attribute to child_url and return
// its Window (without waiting for it to finish loading).
async function with_nested_iframes(t, child_url) {
const parent = await with_iframe('resources/nested-iframe-parent.html?role=parent');
t.add_cleanup(() => parent.remove());
const child = parent.contentWindow.document.getElementById('child');
child.setAttribute('src', child_url);
return child.contentWindow;
}
// Returns a predicate matching a fetch message with the specified
// key.
function fetch_message(key) {
return event => event.data.type === 'fetch' && event.data.key === key;
}
// Returns a predicate matching a ping message with the specified
// payload.
function ping_message(data) {
return event => event.data.type === 'ping' && event.data.data === data;
}
// A client message queue test is a testharness.js test with some
// additional setup:
// 1. A listener (see create_message_listener)
// 2. An active service worker
// 3. Two nested iframes
// 4. A state transition function that controls the order of events
// during the test
function client_message_queue_test(url, test_function, description) {
promise_test(async t => {
t.listener = create_message_listener(t);
const script = 'resources/stalling-service-worker.js';
const scope = 'resources/';
t.service_worker = await service_worker_register_and_activate(t, script, scope);
// We create two nested iframes such that both are controlled by
// the newly installed service worker.
const child_url = url + '?role=child';
t.frame = await with_nested_iframes(t, child_url);
t.state_transition = async function(from, to, scripts) {
// A state transition begins with the child's parser
// fetching a script due to a <script> tag. The request
// arrives at the service worker, which notifies the
// parent, which in turn notifies the test. Note that the
// event loop keeps spinning while the parser is waiting.
const request = await this.listener.waitFor(fetch_message(to));
// The test instructs the service worker to send two ping
// messages through the Client interface: first to the
// child, then to the parent.
this.service_worker.postMessage(from);
// When the parent receives the ping message, it forwards
// it to the test. Assuming that messages to both child
// and parent are mapped to the same task queue (this is
// not [yet] required by the spec), receiving this message
// guarantees that the child has already dispatched its
// message if it was allowed to do so.
await this.listener.waitFor(ping_message(from));
// Finally, reply to the service worker's fetch
// notification with the script it should use as the fetch
// request's response. This is a defensive mechanism that
// ensures the child's parser really is blocked until the
// test is ready to continue.
request.ports[0].postMessage([`state = '${to}';`].concat(scripts));
};
await test_function(t);
}, description);
}
function client_message_queue_enable_test(
install_script,
start_script,
earliest_dispatch,
description)
{
function later_state(state1, state2) {
const states = ['init', 'install', 'start', 'finish', 'loaded'];
const index1 = states.indexOf(state1);
const index2 = states.indexOf(state2);
const max_index = Math.max(index1, index2);
return states[max_index];
}
client_message_queue_test('enable-client-message-queue.html', async t => {
// While parsing the child's document, the child transitions
// from the 'init' state all the way to the 'finish' state.
// Once parsing is finished it would enter the final 'loaded'
// state. All but the last transition require assitance from
// the test.
await t.state_transition('init', 'install', [install_script]);
await t.state_transition('install', 'start', [start_script]);
await t.state_transition('start', 'finish', []);
// Wait for all messages to get dispatched on the child's
// ServiceWorkerContainer and then verify that each message
// was dispatched while the child was in the correct state.
const report = await t.frame.report;
['init', 'install', 'start'].forEach(state => {
const dispatch = later_state(state, earliest_dispatch);
assert_equals(report[state], dispatch,
`Message sent in state '${state}' dispatched in state '${dispatch}'`);
});
}, description);
}
const empty_script = ``;
const add_event_listener =
`navigator.serviceWorker.addEventListener('message', handle_message);`;
const set_onmessage = `navigator.serviceWorker.onmessage = handle_message;`;
const start_messages = `navigator.serviceWorker.startMessages();`;
client_message_queue_enable_test(add_event_listener, empty_script, 'loaded',
'Messages from ServiceWorker to Client only received after DOMContentLoaded event.');
client_message_queue_enable_test(add_event_listener, start_messages, 'start',
'Messages from ServiceWorker to Client only received after calling startMessages().');
client_message_queue_enable_test(set_onmessage, empty_script, 'install',
'Messages from ServiceWorker to Client only received after setting onmessage.');
const resolve_manual_promise = `resolve_manual_promise();`
async function test_microtasks_when_client_message_queue_enabled(t, scripts) {
await t.state_transition('init', 'start', scripts.concat([resolve_manual_promise]));
let result = await t.frame.result;
assert_equals(result[0], 'microtask', 'The microtask was executed first.');
assert_equals(result[1], 'message', 'The message was dispatched.');
}
client_message_queue_test('message-vs-microtask.html', t => {
return test_microtasks_when_client_message_queue_enabled(t, [
add_event_listener,
start_messages,
]);
}, 'Microtasks run before dispatching messages after calling startMessages().');
client_message_queue_test('message-vs-microtask.html', t => {
return test_microtasks_when_client_message_queue_enabled(t, [set_onmessage]);
}, 'Microtasks run before dispatching messages after setting onmessage.');
</script>

View file

@ -41,6 +41,7 @@ if (win.location.href !== 'about:blank') {
});
}
});
win.navigator.serviceWorker.startMessages();
}
</script>
</body>

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<script>
// The state variable is used by handle_message to record the time
// at which a message was handled. It's updated by the scripts
// loaded by the <script> tags at the bottom of the file as well as
// by the event listener added here.
var state = 'init';
addEventListener('DOMContentLoaded', () => state = 'loaded');
// We expect to get three ping messages from the service worker.
const expected = ['init', 'install', 'start'];
let promises = {};
let resolvers = {};
expected.forEach(name => {
promises[name] = new Promise(resolve => resolvers[name] = resolve);
});
// Once all messages have been dispatched, the state in which each
// of them was dispatched is recorded in the draft. At that point
// the draft becomes the final report.
var draft = {};
var report = Promise.all(Object.values(promises)).then(() => window.draft);
// This message handler is installed by the 'install' script.
function handle_message(event) {
const data = event.data.data;
draft[data] = state;
resolvers[data]();
}
</script>
<!--
The controlling service worker will delay the response to these
fetch requests until the test instructs it how to reply. Note that
the event loop keeps spinning while the parser is blocked.
-->
<script src="empty.js?key=install"></script>
<script src="empty.js?key=start"></script>
<script src="empty.js?key=finish"></script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<script>
let draft = [];
var resolve_manual_promise;
let manual_promise =
new Promise(resolve => resolve_manual_promise = resolve).then(() => draft.push('microtask'));
let resolve_message_promise;
let message_promise = new Promise(resolve => resolve_message_promise = resolve);
function handle_message(event) {
draft.push('message');
resolve_message_promise();
}
var result = Promise.all([manual_promise, message_promise]).then(() => draft);
</script>
<script src="empty.js?key=start"></script>

View file

@ -0,0 +1,5 @@
<!DOCTYPE html>
<script>
navigator.serviceWorker.onmessage = event => parent.postMessage(event.data, '*', event.ports);
</script>
<iframe id='child'></iframe>

View file

@ -0,0 +1,54 @@
async function post_message_to_client(role, message, ports) {
(await clients.matchAll()).forEach(client => {
if (new URL(client.url).searchParams.get('role') === role) {
client.postMessage(message, ports);
}
});
}
async function post_message_to_child(message, ports) {
await post_message_to_client('child', message, ports);
}
function ping_message(data) {
return { type: 'ping', data };
}
self.onmessage = event => {
const message = ping_message(event.data);
post_message_to_child(message);
post_message_to_parent(message);
}
async function post_message_to_parent(message, ports) {
await post_message_to_client('parent', message, ports);
}
function fetch_message(key) {
return { type: 'fetch', key };
}
// Send a message to the parent along with a MessagePort to respond
// with.
function report_fetch_request(key) {
const channel = new MessageChannel();
const reply = new Promise(resolve => {
channel.port1.onmessage = resolve;
}).then(event => event.data);
return post_message_to_parent(fetch_message(key), [channel.port2]).then(() => reply);
}
function respond_with_script(script) {
return new Response(new Blob(script, { type: 'text/javascript' }));
}
// Whenever a controlled document requests a URL with a 'key' search
// parameter we report the request to the parent frame and wait for
// a response. The content of the response is then used to respond to
// the fetch request.
addEventListener('fetch', event => {
let key = new URL(event.request.url).searchParams.get('key');
if (key) {
event.respondWith(report_fetch_request(key).then(respond_with_script));
}
});

View file

@ -41,7 +41,7 @@ class Browser(object):
return NotImplemented
@abstractmethod
def find_webdriver(self):
def find_webdriver(self, channel=None):
"""Find the binary of the WebDriver."""
return NotImplemented
@ -211,7 +211,7 @@ class Firefox(Browser):
return None
return path
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("geckodriver")
def get_version_and_channel(self, binary):
@ -387,7 +387,7 @@ class Fennec(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
raise NotImplementedError
def install_webdriver(self, dest=None, channel=None):
@ -441,7 +441,7 @@ class Chrome(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("chromedriver")
def install_webdriver(self, dest=None, channel=None):
@ -489,7 +489,7 @@ class ChromeAndroid(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("chromedriver")
def install_webdriver(self, dest=None, channel=None):
@ -541,7 +541,7 @@ class Opera(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("operadriver")
def install_webdriver(self, dest=None, channel=None):
@ -584,7 +584,7 @@ class Edge(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("MicrosoftWebDriver")
def install_webdriver(self, dest=None, channel=None):
@ -610,7 +610,7 @@ class InternetExplorer(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
return find_executable("IEDriverServer.exe")
def install_webdriver(self, dest=None, channel=None):
@ -635,8 +635,11 @@ class Safari(Browser):
def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("safaridriver")
def find_webdriver(self, channel=None):
path = None
if channel == "preview":
path = "/Applications/Safari Technology Preview.app/Contents/MacOS"
return find_executable("safaridriver", path)
def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
@ -695,7 +698,7 @@ class Servo(Browser):
path = find_executable("servo")
return path
def find_webdriver(self):
def find_webdriver(self, channel=None):
return None
def install_webdriver(self, dest=None, channel=None):
@ -719,7 +722,7 @@ class Sauce(Browser):
def find_binary(self, venev_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
def find_webdriver(self, channel=None):
raise NotImplementedError
def install_webdriver(self, dest=None, channel=None):
@ -741,7 +744,7 @@ class WebKit(Browser):
def find_binary(self, venv_path=None, channel=None):
return None
def find_webdriver(self):
def find_webdriver(self, channel=None):
return None
def install_webdriver(self, dest=None, channel=None):

View file

@ -6,6 +6,8 @@ import sys
latest_channels = {
'firefox': 'nightly',
'chrome': 'dev',
'safari': 'preview',
'safari_webdriver': 'preview',
'servo': 'nightly'
}

View file

@ -371,7 +371,7 @@ class Safari(BrowserSetup):
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
webdriver_binary = self.browser.find_webdriver()
webdriver_binary = self.browser.find_webdriver(channel=kwargs["browser_channel"])
if webdriver_binary is None:
raise WptrunError("Unable to locate safaridriver binary")

View file

@ -1,5 +1,5 @@
html5lib == 1.0.1
mozinfo == 0.10
mozlog==3.8
mozlog==3.9
mozdebug == 0.1
urllib3[secure]==1.23

View file

@ -9,7 +9,7 @@ import unittest
from six.moves.urllib.parse import urlencode, urlunsplit
from six.moves.urllib.request import Request as BaseRequest
from six.moves.urllib.request import urlopen
from six import binary_type, iteritems
from six import binary_type, iteritems, PY3
from hyper import HTTP20Connection, tls
import ssl
@ -79,6 +79,11 @@ class TestUsingServer(unittest.TestCase):
return urlopen(req)
def assert_multiple_headers(self, resp, name, values):
if PY3:
assert resp.info().get_all(name) == values
else:
assert resp.info()[name] == ", ".join(values)
@pytest.mark.skipif(not wptserve.utils.http2_compatible(), reason="h2 server only works in python 2.7.15")
class TestUsingH2Server:

View file

@ -35,10 +35,9 @@ class TestHeader(TestUsingServer):
resp = self.request("/document.txt", query="pipe=header(Content-Type,FAIL)|header(Content-Type,text/html)")
self.assertEqual(resp.info()["Content-Type"], "text/html")
@pytest.mark.xfail(sys.version_info >= (3,), reason="wptserve only works on Py2")
def test_multiple_append(self):
resp = self.request("/document.txt", query="pipe=header(X-Test,1)|header(X-Test,2,True)")
self.assertEqual(resp.info()["X-Test"], "1, 2")
self.assert_multiple_headers(resp, "X-Test", ["1", "2"])
class TestSlice(TestUsingServer):
def test_both_bounds(self):

View file

@ -109,12 +109,16 @@ function test_tone_change_events(testFunc, toneChanges, desc) {
const now = Date.now();
const duration = now - lastEventTime;
assert_approx_equals(duration, expectedDuration, 400,
// We check that the delay is at least the expected one, but
// system load may cause random delay, so we do not put any
// realistic upper bound on the timing of the event.
assert_between_inclusive(duration, expectedDuration,
expectedDuration + 4000,
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} milliseconds`);
lastEventTime = now;
if(toneChanges.length === 0) {
if (toneChanges.length === 0) {
// Wait for same duration as last expected duration + 100ms
// before passing test in case there are new tone events fired,
// in which case the test should fail.

View file

@ -161,13 +161,7 @@
test_tone_change_events((t, dtmfSender) => {
dtmfSender.addEventListener('tonechange', ev => {
if(ev.tone === 'B') {
// Set a timeout to make sure the toneBuffer
// is changed after the tonechange event listener
// by test_tone_change_events is called.
// This is to correctly test the expected toneBuffer.
t.step_timeout(() => {
dtmfSender.insertDTMF('12', 100, 70);
}, 10);
dtmfSender.insertDTMF('12', 100, 70);
}
});
@ -189,10 +183,8 @@
test_tone_change_events((t, dtmfSender) => {
dtmfSender.addEventListener('tonechange', ev => {
if(ev.tone === 'B') {
t.step_timeout(() => {
dtmfSender.insertDTMF('12', 100, 70);
dtmfSender.insertDTMF('34', 100, 70);
}, 10);
dtmfSender.insertDTMF('12', 100, 70);
dtmfSender.insertDTMF('34', 100, 70);
}
});
@ -213,9 +205,7 @@
test_tone_change_events((t, dtmfSender) => {
dtmfSender.addEventListener('tonechange', ev => {
if(ev.tone === 'B') {
t.step_timeout(() => {
dtmfSender.insertDTMF('');
}, 10);
dtmfSender.insertDTMF('');
}
});