From fab05d125a619c9f86501ef23afc3a61cd9009f5 Mon Sep 17 00:00:00 2001
From: metcoder95 <10200776+metcoder95@users.noreply.github.com>
Date: Sat, 23 Aug 2025 01:39:52 +0000
Subject: [PATCH] chore: update WPT
---
test/fixtures/wpt/common/get-host-info.sub.js | 3 +
.../fixtures/wpt/eventsource/WEB_FEATURES.yml | 3 +
.../wpt/fetch/api/basic/WEB_FEATURES.yml | 4 +
.../wpt/fetch/api/body/mime-type.any.js | 2 +-
.../wpt/fetch/api/request/WEB_FEATURES.yml | 4 +
.../fetch/api/request/request-bad-port.any.js | 1 +
.../fetch/api/resources/keepalive-helper.js | 2 +-
.../fetch/api/response/response-clone.any.js | 4 +-
.../fetch/compression-dictionary/README.md | 3 +
...clear-site-data-cache.tentative.https.html | 2 +-
...ear-site-data-cookies.tentative.https.html | 2 +-
...ear-site-data-storage.tentative.https.html | 2 +-
...dictionary-compressed.tentative.https.html | 105 +++
...tionary-decompression.tentative.https.html | 2 +-
...tionary-fetch-no-cors.tentative.https.html | 42 +
...tch-with-link-element.tentative.https.html | 2 +-
...etch-with-link-header.tentative.https.html | 2 +-
...ctionary-registration.tentative.https.html | 54 +-
....js => compression-dictionary-util.sub.js} | 59 +-
.../resources/echo-headers.py | 13 +-
.../resources/echo-headers2.py | 7 +
.../resources/handler_utils.py | 16 +
.../resources/register-dictionary.py | 49 +-
.../br/bad-br-body.https.any.js | 5 +
.../gzip/bad-gzip-body.any.js | 1 +
.../content-encoding/zstd/WEB_FEATURES.yml | 3 +
.../zstd/bad-zstd-body.https.any.js | 1 +
...versized-payload.tentative.https.window.js | 4 +-
.../max-payload.tentative.https.window.js | 19 +-
...versized-payload.tentative.https.window.js | 20 +-
.../resources/fetch-later-helper.js | 5 +-
test/fixtures/wpt/fetch/http-cache/README.md | 2 +-
.../wpt/fetch/http-cache/heuristic.any.js | 27 +-
.../wpt/fetch/http-cache/http-cache.js | 26 +-
.../no-vary-search.tentative.any.js | 91 ++
.../pragma-no-cache-with-cache-control.html | 28 +
.../resources/cached_pragma_rand.py | 14 +
.../wpt/fetch/http-cache/split-cache.html | 2 +-
.../wpt/fetch/local-network-access/META.yml | 5 +
.../wpt/fetch/local-network-access/README.md | 11 +
.../fetch.tentative.https.html | 87 ++
.../iframe.tentative.https.window.js | 199 +++++
.../navigate.tentative.https.window.js | 151 ++++
.../navigate.tentative.window.js | 154 ++++
.../resources/fetch-local-http.html | 40 +
.../resources/fetch-local.html | 52 ++
...fetch-public-http-wrong-address-space.html | 42 +
.../resources/iframer.html | 35 +
.../resources/navigate.html | 9 +
.../resources/openee.html | 7 +
.../resources/support.sub.js | 254 ++++++
.../local-network-access/resources/target.py | 105 +++
...l => script-js-unlabeled-gzipped.sub.html} | 0
.../fetch/private-network-access/README.md | 3 +
...eflight-required.tentative.https.window.js | 91 --
...ubresource-fetch.tentative.https.window.js | 330 --------
.../fenced-frame.tentative.https.window.js | 150 ----
...ed-content-fetch.tentative.https.window.js | 278 -------
.../resources/support.sub.js | 4 +-
...ow-open-existing.tentative.https.window.js | 209 -----
test/fixtures/wpt/fetch/range/general.any.js | 5 +-
...markup-mitigation-allowed-apis.https.html} | 46 +-
test/fixtures/wpt/interfaces/CSP.idl | 26 +-
test/fixtures/wpt/interfaces/IndexedDB.idl | 23 +-
.../{cookie-store.idl => cookiestore.idl} | 8 +-
test/fixtures/wpt/interfaces/csp-next.idl | 14 +-
.../wpt/interfaces/css-conditional-5.idl | 4 +-
.../wpt/interfaces/css-highlight-api.idl | 7 +-
test/fixtures/wpt/interfaces/css-mixins.idl | 2 +-
test/fixtures/wpt/interfaces/css-typed-om.idl | 4 +-
test/fixtures/wpt/interfaces/cssom-view.idl | 1 +
test/fixtures/wpt/interfaces/cssom.idl | 4 +-
.../wpt/interfaces/deprecation-reporting.idl | 16 +-
.../wpt/interfaces/digital-credentials.idl | 21 +-
test/fixtures/wpt/interfaces/dom.idl | 15 +-
.../wpt/interfaces/element-timing.idl | 4 +-
test/fixtures/wpt/interfaces/fedcm.idl | 32 +-
test/fixtures/wpt/interfaces/fetch.idl | 13 +
test/fixtures/wpt/interfaces/fs.idl | 2 +-
test/fixtures/wpt/interfaces/html.idl | 707 ++++++++--------
.../fixtures/wpt/interfaces/image-capture.idl | 2 +-
.../interest-invokers.tentative.idl | 2 +-
.../wpt/interfaces/intervention-reporting.idl | 14 +-
.../interfaces/largest-contentful-paint.idl | 4 +-
.../wpt/interfaces/media-capabilities.idl | 4 +-
.../wpt/interfaces/mediacapture-streams.idl | 18 +-
.../wpt/interfaces/mediaqueries-5.idl | 8 +
.../wpt/interfaces/mediastream-recording.idl | 2 +-
.../fixtures/wpt/interfaces/notifications.idl | 3 +
.../wpt/interfaces/origin.tentative.idl | 16 +
test/fixtures/wpt/interfaces/paint-timing.idl | 4 +-
.../wpt/interfaces/permissions-policy.idl | 18 +-
.../wpt/interfaces/pointer-animations.idl | 23 +
test/fixtures/wpt/interfaces/ppa.idl | 65 --
.../privacy-preserving-attribution.idl | 75 ++
test/fixtures/wpt/interfaces/push-api.idl | 8 +-
test/fixtures/wpt/interfaces/reporting.idl | 14 +-
.../wpt/interfaces/resource-timing.idl | 1 +
.../wpt/interfaces/screen-capture.idl | 8 +
.../secure-payment-confirmation.idl | 40 +-
.../wpt/interfaces/service-workers.idl | 2 +-
.../wpt/interfaces/shared-storage.idl | 2 +-
test/fixtures/wpt/interfaces/speech-api.idl | 64 +-
test/fixtures/wpt/interfaces/sri.idl | 11 +
test/fixtures/wpt/interfaces/streams.idl | 2 +-
.../wpt/interfaces/translation-api.idl | 85 ++
test/fixtures/wpt/interfaces/turtledove.idl | 7 +
test/fixtures/wpt/interfaces/wai-aria.idl | 2 +-
.../wpt/interfaces/web-animations-2.idl | 6 +-
test/fixtures/wpt/interfaces/webaudio.idl | 3 +-
test/fixtures/wpt/interfaces/webauthn.idl | 52 ++
test/fixtures/wpt/interfaces/webcodecs.idl | 2 +-
.../{WebCryptoAPI.idl => webcrypto.idl} | 2 +-
test/fixtures/wpt/interfaces/webgpu.idl | 32 +-
test/fixtures/wpt/interfaces/webidl.idl | 13 +
test/fixtures/wpt/interfaces/webnn.idl | 202 +++--
.../interfaces/webrtc-encoded-transform.idl | 42 +-
.../wpt/interfaces/webrtc-identity.idl | 2 +-
test/fixtures/wpt/interfaces/webrtc-stats.idl | 15 +-
test/fixtures/wpt/interfaces/webrtc.idl | 19 +-
test/fixtures/wpt/interfaces/webtransport.idl | 6 +-
.../wpt/interfaces/webxr-depth-sensing.idl | 14 +
test/fixtures/wpt/interfaces/webxr.idl | 11 +-
test/fixtures/wpt/interfaces/webxrlayers.idl | 2 +
.../interfaces/writing-assistance-apis.idl | 193 +++++
.../fixtures/wpt/resources/check-layout-th.js | 2 +-
.../wpt/resources/chromium/webxr-test.js | 415 ++++++++--
test/fixtures/wpt/resources/idlharness.js | 9 +-
test/fixtures/wpt/resources/test/conftest.py | 3 +-
.../test/tests/functional/api-tests-1.html | 73 +-
.../resources/testdriver-actions.js.headers | 2 +
test/fixtures/wpt/resources/testdriver.js | 779 +++++++++++++++++-
test/fixtures/wpt/resources/testharness.js | 403 +++++++--
.../wpt/resources/web-bluetooth-bidi-test.js | 323 +++++++-
.../wpt/resources/webidl2/lib/VERSION.md | 2 +-
.../wpt/resources/webidl2/lib/webidl2.js | 588 ++++++++-----
.../service-worker/add-routes.https.html | 27 +
.../claim-using-registration.https.html | 2 +-
.../client-url-creation-url.https.html | 129 +++
.../intercepted-referrer.https.html | 51 ++
.../service-worker/resources/add-routes.js | 37 +
.../client-url-creation-url-iframe.html | 85 ++
.../resources/client-url-creation-url-sw.js | 24 +
.../resources/intercepted-referrer-sw.js | 35 +
.../resources/testharness-helpers.js | 2 +-
.../static-router-resource-timing.https.html | 15 +-
...er-immediately-before-installed.https.html | 4 +-
.../unregister-immediately.https.html | 2 +-
.../windowclient-navigate.https.html | 2 +-
...ket-quota-indexeddb.tentative.https.any.js | 8 +-
...e-details-indexeddb.https.tentative.any.js | 2 +-
...ge-details-caches.tentative.https.sub.html | 74 +-
...details-indexeddb.tentative.https.sub.html | 73 +-
...s-service-workers.tentative.https.sub.html | 74 ++
...ate-usage-details-caches-helper-frame.html | 25 +-
...-usage-details-indexeddb-helper-frame.html | 23 +
...-details-service-workers-helper-frame.html | 23 +
.../wpt/websockets/Create-blocked-port.any.js | 4 +
test/fixtures/wpt/websockets/WEB_FEATURES.yml | 3 +
.../stream/tentative/remote-close.any.js | 3 +-
.../websockets/stream/tentative/write.any.js | 111 +++
test/fixtures/wpt/xhr/WEB_FEATURES.yml | 3 +
test/fixtures/wpt/xhr/formdata/append.any.js | 4 +-
test/fixtures/wpt/xhr/resources/redirect.py | 5 +
test/fixtures/wpt/xhr/send-redirect.htm | 85 +-
.../xhr/setrequestheader-case-insensitive.htm | 38 +-
166 files changed, 6231 insertions(+), 2262 deletions(-)
create mode 100644 test/fixtures/wpt/eventsource/WEB_FEATURES.yml
create mode 100644 test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml
create mode 100644 test/fixtures/wpt/fetch/api/request/WEB_FEATURES.yml
create mode 100644 test/fixtures/wpt/fetch/compression-dictionary/README.md
create mode 100644 test/fixtures/wpt/fetch/compression-dictionary/dictionary-compressed.tentative.https.html
create mode 100644 test/fixtures/wpt/fetch/compression-dictionary/dictionary-fetch-no-cors.tentative.https.html
rename test/fixtures/wpt/fetch/compression-dictionary/resources/{compression-dictionary-util.js => compression-dictionary-util.sub.js} (69%)
create mode 100644 test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers2.py
create mode 100644 test/fixtures/wpt/fetch/compression-dictionary/resources/handler_utils.py
create mode 100644 test/fixtures/wpt/fetch/content-encoding/zstd/WEB_FEATURES.yml
create mode 100644 test/fixtures/wpt/fetch/http-cache/no-vary-search.tentative.any.js
create mode 100644 test/fixtures/wpt/fetch/http-cache/pragma-no-cache-with-cache-control.html
create mode 100644 test/fixtures/wpt/fetch/http-cache/resources/cached_pragma_rand.py
create mode 100644 test/fixtures/wpt/fetch/local-network-access/META.yml
create mode 100644 test/fixtures/wpt/fetch/local-network-access/README.md
create mode 100644 test/fixtures/wpt/fetch/local-network-access/fetch.tentative.https.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/iframe.tentative.https.window.js
create mode 100644 test/fixtures/wpt/fetch/local-network-access/navigate.tentative.https.window.js
create mode 100644 test/fixtures/wpt/fetch/local-network-access/navigate.tentative.window.js
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/fetch-local-http.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/fetch-local.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/iframer.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/navigate.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/openee.html
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/support.sub.js
create mode 100644 test/fixtures/wpt/fetch/local-network-access/resources/target.py
rename test/fixtures/wpt/fetch/orb/tentative/{script-js-unlabeled-gziped.sub.html => script-js-unlabeled-gzipped.sub.html} (100%)
delete mode 100644 test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js
delete mode 100644 test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js
delete mode 100644 test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js
delete mode 100644 test/fixtures/wpt/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js
delete mode 100644 test/fixtures/wpt/fetch/private-network-access/window-open-existing.tentative.https.window.js
rename test/fixtures/wpt/fetch/security/dangling-markup/{dangling-markup-mitigation-allowed-apis.tentative.https.html => dangling-markup-mitigation-allowed-apis.https.html} (62%)
rename test/fixtures/wpt/interfaces/{cookie-store.idl => cookiestore.idl} (93%)
create mode 100644 test/fixtures/wpt/interfaces/origin.tentative.idl
create mode 100644 test/fixtures/wpt/interfaces/pointer-animations.idl
delete mode 100644 test/fixtures/wpt/interfaces/ppa.idl
create mode 100644 test/fixtures/wpt/interfaces/privacy-preserving-attribution.idl
create mode 100644 test/fixtures/wpt/interfaces/sri.idl
create mode 100644 test/fixtures/wpt/interfaces/translation-api.idl
rename test/fixtures/wpt/interfaces/{WebCryptoAPI.idl => webcrypto.idl} (98%)
create mode 100644 test/fixtures/wpt/interfaces/writing-assistance-apis.idl
create mode 100644 test/fixtures/wpt/resources/testdriver-actions.js.headers
create mode 100644 test/fixtures/wpt/service-workers/service-worker/add-routes.https.html
create mode 100644 test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html
create mode 100644 test/fixtures/wpt/service-workers/service-worker/intercepted-referrer.https.html
create mode 100644 test/fixtures/wpt/service-workers/service-worker/resources/add-routes.js
create mode 100644 test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html
create mode 100644 test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js
create mode 100644 test/fixtures/wpt/service-workers/service-worker/resources/intercepted-referrer-sw.js
create mode 100644 test/fixtures/wpt/websockets/WEB_FEATURES.yml
create mode 100644 test/fixtures/wpt/websockets/stream/tentative/write.any.js
create mode 100644 test/fixtures/wpt/xhr/WEB_FEATURES.yml
diff --git a/test/fixtures/wpt/common/get-host-info.sub.js b/test/fixtures/wpt/common/get-host-info.sub.js
index 9b8c2b5de63..42369c7370b 100644
--- a/test/fixtures/wpt/common/get-host-info.sub.js
+++ b/test/fixtures/wpt/common/get-host-info.sub.js
@@ -20,6 +20,7 @@ function get_host_info() {
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST);
var OTHER_HOST = '{{domains[www2]}}';
var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('{{hosts[alt][]}}');
+ var OTHER_NOTSAMESITE_HOST = '{{hosts[alt][www2]}}';
return {
HTTP_PORT: HTTP_PORT,
@@ -30,6 +31,7 @@ function get_host_info() {
PORT2: PORT2,
ORIGINAL_HOST: ORIGINAL_HOST,
REMOTE_HOST: REMOTE_HOST,
+ NOTSAMESITE_HOST,
ORIGIN: PROTOCOL + "//" + ORIGINAL_HOST + PORT_ELIDED,
HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + HTTP_PORT_ELIDED,
@@ -44,6 +46,7 @@ function get_host_info() {
HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_OTHER_NOTSAMESITE_ORIGIN: 'https://' + OTHER_NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
};
diff --git a/test/fixtures/wpt/eventsource/WEB_FEATURES.yml b/test/fixtures/wpt/eventsource/WEB_FEATURES.yml
new file mode 100644
index 00000000000..3c883f82f76
--- /dev/null
+++ b/test/fixtures/wpt/eventsource/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: server-sent-events
+ files: "**"
diff --git a/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml b/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml
new file mode 100644
index 00000000000..d6cd4adaeff
--- /dev/null
+++ b/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: fetch-request-streams
+ files:
+ - request-upload*
diff --git a/test/fixtures/wpt/fetch/api/body/mime-type.any.js b/test/fixtures/wpt/fetch/api/body/mime-type.any.js
index 67c9af7da2d..ed19309bdb2 100644
--- a/test/fixtures/wpt/fetch/api/body/mime-type.any.js
+++ b/test/fixtures/wpt/fetch/api/body/mime-type.any.js
@@ -87,7 +87,7 @@
[
() => new Request("about:blank", { method: "POST", body: new Blob([""], { type: "Text/Plain" }), headers: [["Content-Type", "Text/Html"]] }),
- () => new Response(new Blob([""], { type: "Text/Plain" }, { headers: [["Content-Type", "Text/Html"]] }))
+ () => new Response(new Blob([""], { type: "Text/Plain" }), { headers: [["Content-Type", "Text/Html"]] })
].forEach(bodyContainerCreator => {
const bodyContainer = bodyContainerCreator();
const cloned = bodyContainer.clone();
diff --git a/test/fixtures/wpt/fetch/api/request/WEB_FEATURES.yml b/test/fixtures/wpt/fetch/api/request/WEB_FEATURES.yml
new file mode 100644
index 00000000000..69b2ea582a2
--- /dev/null
+++ b/test/fixtures/wpt/fetch/api/request/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+features:
+- name: fetch-priority
+ files:
+ - request-init-priority.any.js
diff --git a/test/fixtures/wpt/fetch/api/request/request-bad-port.any.js b/test/fixtures/wpt/fetch/api/request/request-bad-port.any.js
index 915063bab56..ff394095f64 100644
--- a/test/fixtures/wpt/fetch/api/request/request-bad-port.any.js
+++ b/test/fixtures/wpt/fetch/api/request/request-bad-port.any.js
@@ -3,6 +3,7 @@
// list of bad ports according to
// https://fetch.spec.whatwg.org/#port-blocking
var BLOCKED_PORTS_LIST = [
+ 0,
1, // tcpmux
7, // echo
9, // discard
diff --git a/test/fixtures/wpt/fetch/api/resources/keepalive-helper.js b/test/fixtures/wpt/fetch/api/resources/keepalive-helper.js
index 1e75c060aea..ad0e9bfa06c 100644
--- a/test/fixtures/wpt/fetch/api/resources/keepalive-helper.js
+++ b/test/fixtures/wpt/fetch/api/resources/keepalive-helper.js
@@ -117,7 +117,7 @@ function assertStashedTokenAsync(
*
* `unloadIframe` to unload the iframe before verifying stashed token to
* simulate the situation that unloads after fetching. Note that this test is
- * different from `keepaliveRedirectInUnloadTest()` in that the the latter
+ * different from `keepaliveRedirectInUnloadTest()` in that the latter
* performs fetch() call directly in `unload` event handler, while this test
* does it in `load`.
*/
diff --git a/test/fixtures/wpt/fetch/api/response/response-clone.any.js b/test/fixtures/wpt/fetch/api/response/response-clone.any.js
index c0c844948db..20ce01e9997 100644
--- a/test/fixtures/wpt/fetch/api/response/response-clone.any.js
+++ b/test/fixtures/wpt/fetch/api/response/response-clone.any.js
@@ -38,7 +38,7 @@ test(function() {
promise_test(function(test) {
return validateStreamFromString(response.body.getReader(), body);
-}, "Check orginal response's body after cloning");
+}, "Check original response's body after cloning");
promise_test(function(test) {
return validateStreamFromString(clonedResponse.body.getReader(), body);
@@ -104,7 +104,7 @@ function testReadableStreamClone(initialBuffer, bufferType)
}).then(function(data) {
assert_false(data.done);
if (initialBuffer instanceof ArrayBuffer) {
- assert_true(data.value instanceof ArrayBuffer, "Cloned buffer is ArrayBufer");
+ assert_true(data.value instanceof ArrayBuffer, "Cloned buffer is ArrayBuffer");
assert_equals(initialBuffer.byteLength, data.value.byteLength, "Length equal");
assert_array_equals(new Uint8Array(data.value), new Uint8Array(initialBuffer), "Cloned buffer chunks have the same content");
} else if (initialBuffer instanceof DataView) {
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/README.md b/test/fixtures/wpt/fetch/compression-dictionary/README.md
new file mode 100644
index 00000000000..c7da1b85968
--- /dev/null
+++ b/test/fixtures/wpt/fetch/compression-dictionary/README.md
@@ -0,0 +1,3 @@
+These are the tests for the [Compression Dictionary Transport](https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/) standard (currently in IETF draft state, approved for publication). The tests are marked as tentative, pending the publication of the RFC.
+
+The MDN reference is [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Compression_dictionary_transport).
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-clear-site-data-cache.tentative.https.html b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-clear-site-data-cache.tentative.https.html
index c8bcf7fdf12..b9764291bbb 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-clear-site-data-cache.tentative.https.html
+++ b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-clear-site-data-cache.tentative.https.html
@@ -4,7 +4,7 @@
-
+
-
+
-
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html
index 33aeb4466ba..0a661a013d1 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html
+++ b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-decompression.tentative.https.html
@@ -5,7 +5,7 @@
-
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html
index d465ceb3d85..2b49aae307b 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html
+++ b/test/fixtures/wpt/fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html
@@ -6,7 +6,7 @@
-
+
-
+
-
+
+
+
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.js b/test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.sub.js
similarity index 69%
rename from test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.js
rename to test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.sub.js
index 7d86f594a80..e36834733b8 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.js
+++ b/test/fixtures/wpt/fetch/compression-dictionary/resources/compression-dictionary-util.sub.js
@@ -1,3 +1,9 @@
+const SAME_ORIGIN = "https://{{host}}:{{ports[https][0]}}";
+const CROSS_ORIGIN = "https://{{hosts[alt][www]}}:{{ports[https][0]}}";
+
+const RESOURCES_PATH = "/fetch/compression-dictionary/resources";
+const SAME_ORIGIN_RESOURCES_URL = SAME_ORIGIN + RESOURCES_PATH;
+const CROSS_ORIGIN_RESOURCES_URL = CROSS_ORIGIN + RESOURCES_PATH;
const kDefaultDictionaryContent = 'This is a test dictionary.\n';
const kDefaultDictionaryHashBase64 =
@@ -6,8 +12,8 @@ const kRegisterDictionaryPath = './resources/register-dictionary.py';
const kCompressedDataPath = './resources/compressed-data.py';
const kExpectedCompressedData =
`This is compressed test data using a test dictionary`;
-const kCheckAvailableDictionaryHeaderMaxRetry = 10;
-const kCheckAvailableDictionaryHeaderRetryTimeout = 200;
+const kCheckHeaderMaxRetry = 10;
+const kCheckHeaderRetryTimeout = 200;
const kCheckPreviousRequestHeadersMaxRetry = 5;
const kCheckPreviousRequestHeadersRetryTimeout = 250;
@@ -30,41 +36,60 @@ async function calculateDictionaryHash(dictionary_text) {
}
// Checks the HTTP request headers which is sent to the server.
-async function checkHeaders(check_remote = false) {
- let url = './resources/echo-headers.py';
+async function checkHeaders({check_remote = false, use_alt_path = false}) {
+ let url = use_alt_path ? './resources/echo-headers2.py' :
+ './resources/echo-headers.py';
if (check_remote) {
url = getRemoteHostUrl(url);
}
return await (await fetch(url)).json();
}
-// Checks the "available-dictionary" header in the HTTP request headers.
-async function checkAvailableDictionaryHeader(check_remote = false) {
- return (await checkHeaders(check_remote))['available-dictionary'];
+// Checks the specified header in the HTTP request headers.
+async function checkHeader(header, {
+ check_remote = false,
+ use_alt_path = false}) {
+ return (await checkHeaders({check_remote: check_remote, use_alt_path: use_alt_path}))[header];
}
-// Waits until the "available-dictionary" header is available in the HTTP
+// Waits until the specified header is available in the HTTP
// request headers, and returns the header. If the header is not available after
// the specified number of retries, returns an error message. If the
// `expected_header` is specified, this method waits until the header is
// available and matches the `expected_header`.
-async function waitUntilAvailableDictionaryHeader(test, {
- max_retry = kCheckAvailableDictionaryHeaderMaxRetry,
+async function waitUntilHeader(test, header, {
+ max_retry = kCheckHeaderMaxRetry,
expected_header = undefined,
- check_remote = false
+ check_remote = false,
+ use_alt_path = false
}) {
for (let retry_count = 0; retry_count <= max_retry; retry_count++) {
- const header = await checkAvailableDictionaryHeader(check_remote);
- if (header) {
- if (expected_header === undefined || header == expected_header) {
- return header;
+ const response_header = await checkHeader(header, {check_remote: check_remote,
+ use_alt_path: use_alt_path});
+ if (response_header) {
+ if (expected_header === undefined || response_header == expected_header) {
+ return response_header;
}
}
await new Promise(
(resolve) => test.step_timeout(
- resolve, kCheckAvailableDictionaryHeaderRetryTimeout));
+ resolve, kCheckHeaderRetryTimeout));
}
- return '"available-dictionary" header is not available';
+ return `"${header}" header is not available`;
+}
+
+async function waitUntilAvailableDictionaryHeader(test, {
+ max_retry = kCheckHeaderMaxRetry,
+ expected_header = undefined,
+ check_remote = false,
+ use_alt_path = false
+}) {
+ return waitUntilHeader(test, 'available-dictionary', {
+ max_retry: max_retry,
+ expected_header: expected_header,
+ check_remote: check_remote,
+ use_alt_path: use_alt_path
+ });
}
// Checks the HTTP request headers which was sent to the server with `token`
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers.py b/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers.py
index aabd99eb101..657bd31c069 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers.py
+++ b/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers.py
@@ -1,10 +1,7 @@
-import json
+import importlib
+
+handler_utils = importlib.import_module(
+ "fetch.compression-dictionary.resources.handler_utils")
def main(request, response):
- response.headers.set(b"Access-Control-Allow-Origin", b"*")
- headers = {}
- for header in request.headers:
- key = header.decode('utf-8')
- value = request.headers.get(header).decode('utf-8')
- headers[key] = value
- return json.dumps(headers)
+ return handler_utils.create_echo_response(request, response)
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers2.py b/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers2.py
new file mode 100644
index 00000000000..657bd31c069
--- /dev/null
+++ b/test/fixtures/wpt/fetch/compression-dictionary/resources/echo-headers2.py
@@ -0,0 +1,7 @@
+import importlib
+
+handler_utils = importlib.import_module(
+ "fetch.compression-dictionary.resources.handler_utils")
+
+def main(request, response):
+ return handler_utils.create_echo_response(request, response)
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/resources/handler_utils.py b/test/fixtures/wpt/fetch/compression-dictionary/resources/handler_utils.py
new file mode 100644
index 00000000000..4078bd98419
--- /dev/null
+++ b/test/fixtures/wpt/fetch/compression-dictionary/resources/handler_utils.py
@@ -0,0 +1,16 @@
+import json
+
+def create_echo_response(request, response):
+ response.headers.set(b"Access-Control-Allow-Origin", b"*")
+ headers = {}
+ for header in request.headers:
+ key = header.decode('utf-8')
+ value = request.headers.get(header).decode('utf-8')
+ headers[key] = value
+ result = json.dumps(headers)
+ # If there is a callback, treat it as JSONP and wrap the result in the provided callback
+ if b'callback' in request.GET:
+ callback = request.GET.first(b"callback").decode('utf-8')
+ result = callback + '(' + result + ');'
+
+ return result
diff --git a/test/fixtures/wpt/fetch/compression-dictionary/resources/register-dictionary.py b/test/fixtures/wpt/fetch/compression-dictionary/resources/register-dictionary.py
index 0bd57225ef1..ea1fff9ad08 100644
--- a/test/fixtures/wpt/fetch/compression-dictionary/resources/register-dictionary.py
+++ b/test/fixtures/wpt/fetch/compression-dictionary/resources/register-dictionary.py
@@ -4,10 +4,13 @@ def main(request, response):
response.headers.set(b"Access-Control-Allow-Origin", b"*")
match = b"/fetch/compression-dictionary/resources/*"
content = b"This is a test dictionary.\n"
+ max_age = b"3600"
if b"match" in request.GET:
match = request.GET.first(b"match")
if b"content" in request.GET:
content = request.GET.first(b"content")
+ if b"max-age" in request.GET:
+ max_age = request.GET.first(b"max-age")
token = request.GET.first(b"save_header", None)
if token is not None:
@@ -33,5 +36,49 @@ def main(request, response):
if b"id" in request.GET:
options += b", id=\"" + request.GET.first(b"id") + b"\""
response.headers.set(b"Use-As-Dictionary", options)
- response.headers.set(b"Cache-Control", b"max-age=3600")
+ response.headers.set(b"Cache-Control", b"max-age=" + max_age)
+ if b"age" in request.GET:
+ response.headers.set(b"Age", request.GET.first(b"age"))
+ response.headers.set(b"Vary", b"available-dictionary,accept-encoding")
+
+ # Compressed responses are generated using the following commands:
+ #
+ # $ echo "This is a test dictionary." > /tmp/dict
+ # $ echo "This is a test dictionary." > /tmp/data
+ #
+ # $ gzip < /tmp/data > /tmp/out.gz
+ # $ xxd -p /tmp/out.gz | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ gzip_data = b"\x1f\x8b\x08\x00\x10\x31\x47\x68\x00\x03\x0b\xc9\xc8\x2c\x56\x00\xa2\x44\x85\x92\xd4\xe2\x12\x85\x94\xcc\xe4\x92\xcc\xfc\xbc\xc4\xa2\x4a\x3d\x2e\x00\x79\xf2\x36\x63\x1b\x00\x00\x00"
+ # $ brotli -o /tmp/out.br /tmp/data
+ # $ xxd -p /tmp/out.br | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ br_data = b"\xa1\xd0\x00\xc0\x6f\xa4\x74\xf3\x56\xb5\x02\x48\x18\x9d\x2a\x9b\xcb\x42\x14\x81\xa7\x14\xda\x89\x29\x93\x7b\xc8\x09"
+ # $ zstd -f -o /tmp/out.zstd /tmp/data
+ # $ xxd -p /tmp/out.zstd | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ zstd_data = b"\x28\xb5\x2f\xfd\x24\x1b\xd9\x00\x00\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x64\x69\x63\x74\x69\x6f\x6e\x61\x72\x79\x2e\x0a\x3f\x0d\x76\xa0"
+ # $ echo -en '\xffDCB' > /tmp/out.dcb
+ # $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb
+ # $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb
+ # $ xxd -p /tmp/out.dcb | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ dcb_data = b"\xff\x44\x43\x42\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\xa1\xd0\x00\xc0\x2f\x01\x10\xc4\x84\x0a\x05"
+ # $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz
+ # $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz
+ # $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data
+ # $ cat /tmp/tmp.zstd >> /tmp/out.dcz
+ # $ xxd -p /tmp/out.dcz | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ dcz_data = b"\x5e\x2a\x4d\x18\x20\x00\x00\x00\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\x28\xb5\x2f\xfd\x24\x1b\x35\x00\x00\x00\x01\x00\x1e\x4e\x20\x3f\x0d\x76\xa0"
+
+ if b'content_encoding' in request.GET:
+ content_encoding = request.GET.first(b"content_encoding")
+ response.headers.set(b"Content-Encoding", content_encoding)
+ if content_encoding == b"gzip":
+ content = gzip_data
+ elif content_encoding == b"br":
+ content = br_data
+ elif content_encoding == b"zstd":
+ content = zstd_data
+ elif content_encoding == b"dcb":
+ content = dcb_data
+ elif content_encoding == b"dcz":
+ content = dcz_data
+
return content
diff --git a/test/fixtures/wpt/fetch/content-encoding/br/bad-br-body.https.any.js b/test/fixtures/wpt/fetch/content-encoding/br/bad-br-body.https.any.js
index 43ea90a336c..af5df674da6 100644
--- a/test/fixtures/wpt/fetch/content-encoding/br/bad-br-body.https.any.js
+++ b/test/fixtures/wpt/fetch/content-encoding/br/bad-br-body.https.any.js
@@ -2,6 +2,11 @@
[
"arrayBuffer",
+ "blob",
+ "bytes",
+ "formData",
+ "json",
+ "text"
].forEach(method => {
promise_test(t => {
return fetch("resources/bad-br-body.py").then(res => {
diff --git a/test/fixtures/wpt/fetch/content-encoding/gzip/bad-gzip-body.any.js b/test/fixtures/wpt/fetch/content-encoding/gzip/bad-gzip-body.any.js
index 17bc1261a3f..77a183f408b 100644
--- a/test/fixtures/wpt/fetch/content-encoding/gzip/bad-gzip-body.any.js
+++ b/test/fixtures/wpt/fetch/content-encoding/gzip/bad-gzip-body.any.js
@@ -9,6 +9,7 @@ promise_test((test) => {
[
"arrayBuffer",
"blob",
+ "bytes",
"formData",
"json",
"text"
diff --git a/test/fixtures/wpt/fetch/content-encoding/zstd/WEB_FEATURES.yml b/test/fixtures/wpt/fetch/content-encoding/zstd/WEB_FEATURES.yml
new file mode 100644
index 00000000000..b5d970fdb14
--- /dev/null
+++ b/test/fixtures/wpt/fetch/content-encoding/zstd/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: zstd
+ files: "**"
diff --git a/test/fixtures/wpt/fetch/content-encoding/zstd/bad-zstd-body.https.any.js b/test/fixtures/wpt/fetch/content-encoding/zstd/bad-zstd-body.https.any.js
index 3f32e4dfba7..c59980c2c6f 100644
--- a/test/fixtures/wpt/fetch/content-encoding/zstd/bad-zstd-body.https.any.js
+++ b/test/fixtures/wpt/fetch/content-encoding/zstd/bad-zstd-body.https.any.js
@@ -9,6 +9,7 @@ promise_test((test) => {
[
"arrayBuffer",
"blob",
+ "bytes",
"formData",
"json",
"text"
diff --git a/test/fixtures/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js b/test/fixtures/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js
index 6439b392e2a..143546ff723 100644
--- a/test/fixtures/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js
+++ b/test/fixtures/wpt/fetch/fetch-later/quota/accumulated-oversized-payload.tentative.https.window.js
@@ -37,7 +37,7 @@ test(
// Makes the 2nd call (POST) to the same reporting origin that sends
// max bytes, which should be rejected.
- assert_throws_dom('QuotaExceededError', () => {
+ assert_throws_quotaexceedederror(() => {
fetchLater(requestUrl, {
method: 'POST',
signal: controller.signal,
@@ -45,7 +45,7 @@ test(
// Required, as the size of referrer also take up quota.
referrer: '',
});
- });
+ }, null, null);
// Makes the 3rd call (GET) to the same reporting origin, where its
// request size is len(requestUrl) + headers, which should be accepted.
diff --git a/test/fixtures/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js b/test/fixtures/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js
index 8457060797a..aa797f13557 100644
--- a/test/fixtures/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js
+++ b/test/fixtures/wpt/fetch/fetch-later/quota/max-payload.tentative.https.window.js
@@ -36,13 +36,14 @@ promise_test(async _ => {
test(_ => {
const uuid = token();
const requestUrl = generateSetBeaconURL(uuid, {host: HTTPS_ORIGIN});
- assert_throws_dom(
- 'QuotaExceededError',
- () => fetchLater(requestUrl, {
- activateAfter: 0,
- method: 'POST',
- body: generatePayload(
- getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,
- dataType),
- }));
+
+ assert_throws_quotaexceedederror(() => {
+ fetchLater(requestUrl, {
+ activateAfter: 0,
+ method: 'POST',
+ body: generatePayload(
+ getRemainingQuota(QUOTA_PER_ORIGIN, requestUrl, headers) + 1,
+ dataType),
+ });
+ }, null, null);
}, `fetchLater() rejects max+1 payload in a POST request body of ${dataType}.`);
diff --git a/test/fixtures/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js b/test/fixtures/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js
index 0036d040d8e..740f17ea24a 100644
--- a/test/fixtures/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js
+++ b/test/fixtures/wpt/fetch/fetch-later/quota/oversized-payload.tentative.https.window.js
@@ -9,16 +9,16 @@ const OVERSIZED_REQUEST_BODY_SIZE = QUOTA_PER_ORIGIN + 1;
for (const dataType in BeaconDataType) {
// Test making a POST request with oversized payload, which should be rejected
// by fetchLater API.
- test(
- () => assert_throws_dom(
- 'QuotaExceededError',
- () => fetchLater('/', {
- activateAfter: 0,
- method: 'POST',
- body: makeBeaconData(
- generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),
- })),
- `fetchLater() does not accept payload[size=${
+ test(() => {
+ assert_throws_quotaexceedederror(() => {
+ fetchLater('/', {
+ activateAfter: 0,
+ method: 'POST',
+ body: makeBeaconData(
+ generatePayload(OVERSIZED_REQUEST_BODY_SIZE), dataType),
+ });
+ }, null, null);
+ }, `fetchLater() does not accept payload[size=${
OVERSIZED_REQUEST_BODY_SIZE}] exceeding per-origin quota in a POST request body of ${
dataType}.`);
}
diff --git a/test/fixtures/wpt/fetch/fetch-later/resources/fetch-later-helper.js b/test/fixtures/wpt/fetch/fetch-later/resources/fetch-later-helper.js
index ef1d7090a8f..32220ae39e3 100644
--- a/test/fixtures/wpt/fetch/fetch-later/resources/fetch-later-helper.js
+++ b/test/fixtures/wpt/fetch/fetch-later/resources/fetch-later-helper.js
@@ -415,7 +415,10 @@ class FetchLaterIframeExpectation {
}
if (e.data.type === FetchLaterIframeMessageType.ERROR) {
const actual = e.data.error.name || e.data.error.type;
- if (e.data.error.constructor.name === 'DOMException' &&
+ if (this.expectedDomErrorName === 'QuotaExceededError') {
+ return actual == this.expectedDomErrorName;
+ } else if (
+ e.data.error.constructor.name === 'DOMException' &&
actual == this.expectedDomErrorName) {
return true;
}
diff --git a/test/fixtures/wpt/fetch/http-cache/README.md b/test/fixtures/wpt/fetch/http-cache/README.md
index 512c422e108..f3815aabfd9 100644
--- a/test/fixtures/wpt/fetch/http-cache/README.md
+++ b/test/fixtures/wpt/fetch/http-cache/README.md
@@ -62,6 +62,7 @@ Possible members of a request object:
- expected_response_headers - An array of `[header_name_string, header_value_string]` representing
headers to check the response for. See also response_headers.
- expected_response_text - A string to check the response body against. If not present, `response_body` will be checked if present and non-null; otherwise the response body will be checked for the test uuid (unless the status code disallows a body). Set to `null` to disable all response body checking.
+- url_params - A string of url parameters that will be appended to the end of the url, separated by "&" and without leading "&".
Some headers in `response_headers` are treated specially:
@@ -69,4 +70,3 @@ Some headers in `response_headers` are treated specially:
* For URL-carrying headers, the value will be appended as a query parameter for `target`.
See the source for exact details.
-
diff --git a/test/fixtures/wpt/fetch/http-cache/heuristic.any.js b/test/fixtures/wpt/fetch/http-cache/heuristic.any.js
index d8461318882..2bec1aa4c64 100644
--- a/test/fixtures/wpt/fetch/http-cache/heuristic.any.js
+++ b/test/fixtures/wpt/fetch/http-cache/heuristic.any.js
@@ -32,10 +32,33 @@ var tests = [
],
},
{
- expected_type: "not_cached"
+ expected_type: "not_cached",
}
]
- }
+ },
+ {
+ name: "HTTP cache does not reuse a redirected response with no max-age and no Last-Modified header",
+ requests: [
+ {
+ response_status: [301, "Moved Permanently"],
+ response_headers: [
+ ["Cache-Control", "private"],
+ ["Location", "redirect_target"]
+ ],
+ },
+ { skip: true}, // Response to first redirect
+ {
+ response_status: [301, "Moved Permanently"],
+ response_headers: [
+ ["Cache-Control", "private"],
+ ["Location", "redirect_target"]
+ ],
+ expected_type: "not_cached",
+ },
+ { skip: true}, // response to second redirect
+ ],
+ check_count: true,
+ },
];
function check_status(status) {
diff --git a/test/fixtures/wpt/fetch/http-cache/http-cache.js b/test/fixtures/wpt/fetch/http-cache/http-cache.js
index 19f1ca9b2bc..e2234736910 100644
--- a/test/fixtures/wpt/fetch/http-cache/http-cache.js
+++ b/test/fixtures/wpt/fetch/http-cache/http-cache.js
@@ -43,17 +43,25 @@ function makeTest (test) {
var uuid = token()
var requests = expandTemplates(test)
var fetchFunctions = makeFetchFunctions(requests, uuid)
- return runTest(fetchFunctions, requests, uuid)
+ return runTest(fetchFunctions, test, requests, uuid)
}
}
function makeFetchFunctions(requests, uuid) {
var fetchFunctions = []
for (let i = 0; i < requests.length; ++i) {
+ var config = requests[i];
+ if (config.skip) {
+ // Skip request are ones that we expect the browser to make in
+ // response to a redirect. We don't fetch them again, but
+ // the server needs them in the config to be able to respond to
+ // them.
+ continue;
+ }
fetchFunctions.push({
code: function (idx) {
var config = requests[idx]
- var url = makeTestUrl(uuid, config)
+ var url = makeTestUrl(uuid, config);
var init = fetchInit(requests, config)
return fetch(url, init)
.then(makeCheckResponse(idx, config))
@@ -71,7 +79,7 @@ function makeFetchFunctions(requests, uuid) {
return fetchFunctions
}
-function runTest(fetchFunctions, requests, uuid) {
+function runTest(fetchFunctions, test, requests, uuid) {
var idx = 0
function runNextStep () {
if (fetchFunctions.length) {
@@ -93,7 +101,7 @@ function runTest(fetchFunctions, requests, uuid) {
.then(function () {
return getServerState(uuid)
}).then(function (testState) {
- checkRequests(requests, testState)
+ checkRequests(test, requests, testState)
return Promise.resolve()
})
}
@@ -153,7 +161,7 @@ function makeCheckResponse (idx, config) {
if ('expected_status' in config) {
assert_equals(response.status, config.expected_status,
`Response ${reqNum} status is ${response.status}, not ${config.expected_status}`)
- } else if ('response_status' in config) {
+ } else if ('response_status' in config && config.response_status[0] != 301) {
assert_equals(response.status, config.response_status[0],
`Response ${reqNum} status is ${response.status}, not ${config.response_status[0]}`)
} else {
@@ -197,7 +205,7 @@ function makeCheckResponseBody (config, uuid) {
}
}
-function checkRequests (requests, testState) {
+function checkRequests (test, requests, testState) {
var testIdx = 0
for (let i = 0; i < requests.length; ++i) {
var expectedValidatingHeaders = []
@@ -225,6 +233,9 @@ function checkRequests (requests, testState) {
})
}
}
+ if (test?.check_count && testState) {
+ assert_equals(requests.length, testState.length);
+ }
}
function pause () {
@@ -244,6 +255,9 @@ function makeTestUrl (uuid, config) {
if ('query_arg' in config) {
arg = `&target=${config.query_arg}`
}
+ if ('url_params' in config) {
+ arg = `${arg}&${config.url_params}`
+ }
return `${base_url}resources/http-cache.py?dispatch=test&uuid=${uuid}${arg}`
}
diff --git a/test/fixtures/wpt/fetch/http-cache/no-vary-search.tentative.any.js b/test/fixtures/wpt/fetch/http-cache/no-vary-search.tentative.any.js
new file mode 100644
index 00000000000..6c5a714e287
--- /dev/null
+++ b/test/fixtures/wpt/fetch/http-cache/no-vary-search.tentative.any.js
@@ -0,0 +1,91 @@
+// META: global=window,worker
+// META: title=NoVarySearch HTTP Cache
+// META: timeout=long
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=http-cache.js
+/*
+NOTE for testing No-Vary-Search-Header:
+- If `params` is set to true, `expect=("dispatch" "uuid")` must be specified.
+ Otherwise:
+ - The same HTTP Cache will be used by other tests, which are supposed
+ to be distinguished by uuid.
+ - The test utility cannot get the server's states because UA will use the HTTP
+ Cache instead of sending a new request to server to ask for the latest state.
+- Do not test not_cached cases and cached cases within one test. Test infra
+ checks the number of requests and responses without considering if the
+ previous responses should be served from cache or not.
+*/
+var tests = [
+ {
+ name: "When params is set to true, URL differs only by their parameters (other than `dispatch` and `uuid`) should not be cached as different entries.",
+ requests: [
+ {
+ url_params: "a=1&b=2",
+ response_headers: [
+ ["Cache-Control", "max-age=10000"],
+ ["No-Vary-Search", "params, except=(\"dispatch\" \"uuid\")"],
+ ],
+ },
+ {
+ expected_type: "cached"
+ }
+ ]
+ },
+ {
+ name: "Ground truth: When key-order is not set, URLs should be compared in an order-sensitive way.",
+ requests: [
+ {
+ url_params: "a=1&b=2",
+ response_headers: [
+ ["Cache-Control", "max-age=10000"],
+ ],
+ },
+ {
+ url_params: "b=2&a=1",
+ expected_type: "not_cached"
+ }
+ ]
+ },
+ {
+ name: "When key-order is set , URLs should be compared in an order-insensitive way. Matched cases:",
+ requests: [
+ {
+ url_params: "a=1&b=2",
+ response_headers: [
+ ["Cache-Control", "max-age=10000"],
+ ["No-Vary-Search", "key-order"],
+ ],
+ },
+ {
+ url_params: "b=2&a=1",
+ expected_type: "cached"
+ }
+ ]
+ },
+ {
+ name: "When key-order is set , URLs should be compared in an order-insensitive way. Not matched cases",
+ requests: [
+ {
+ url_params: "a=1&b=2",
+ response_headers: [
+ ["Cache-Control", "max-age=10000"],
+ ["No-Vary-Search", "key-order"],
+ ],
+ },
+ {
+ url_params: "b=2",
+ expected_type: "not_cached"
+ },
+ {
+ url_params: "a=2&b=2",
+ expected_type: "not_cached"
+ },
+ {
+ url_params: "a=1&b=2&c=3",
+ expected_type: "not_cached"
+ }
+ ]
+ }
+];
+run_tests(tests);
diff --git a/test/fixtures/wpt/fetch/http-cache/pragma-no-cache-with-cache-control.html b/test/fixtures/wpt/fetch/http-cache/pragma-no-cache-with-cache-control.html
new file mode 100644
index 00000000000..19a80fe5edc
--- /dev/null
+++ b/test/fixtures/wpt/fetch/http-cache/pragma-no-cache-with-cache-control.html
@@ -0,0 +1,28 @@
+
+
+HTTP Cache: Cache-Control with Pragma: no-cache
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/http-cache/resources/cached_pragma_rand.py b/test/fixtures/wpt/fetch/http-cache/resources/cached_pragma_rand.py
new file mode 100644
index 00000000000..18c7d25159f
--- /dev/null
+++ b/test/fixtures/wpt/fetch/http-cache/resources/cached_pragma_rand.py
@@ -0,0 +1,14 @@
+def main(request, response):
+ # Disable non-standard XSS protection
+ response.headers.set(b"X-XSS-Protection", b"0")
+ response.headers.set(b"Content-Type", b"text/html")
+
+ # Set caching headers
+ # According to rfc9111 Pragma: no-cache is deprecated, so we expect
+ # Cache-Control to take precedence when there's a mismatch.
+ response.headers.set(b"Cache-Control", b"max-age=2592000, public")
+ response.headers.set(b"Pragma", b"no-cache")
+
+ # Include a timestamp to verify caching behavior
+ import time
+ response.content = f"Timestamp: {time.time()}".encode('utf-8')
diff --git a/test/fixtures/wpt/fetch/http-cache/split-cache.html b/test/fixtures/wpt/fetch/http-cache/split-cache.html
index fe93d2e3400..c822abba3ac 100644
--- a/test/fixtures/wpt/fetch/http-cache/split-cache.html
+++ b/test/fixtures/wpt/fetch/http-cache/split-cache.html
@@ -128,7 +128,7 @@
function check_server_info() {
return getServerState(uuid)
.then(function (testState) {
- checkRequests(local_requests, testState)
+ checkRequests(undefined, local_requests, testState)
return Promise.resolve()
})
}
diff --git a/test/fixtures/wpt/fetch/local-network-access/META.yml b/test/fixtures/wpt/fetch/local-network-access/META.yml
new file mode 100644
index 00000000000..4c5c6983ed0
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/META.yml
@@ -0,0 +1,5 @@
+spec: https://wicg.github.io/local-network-access/
+suggested_reviewers:
+ - cthomp
+ - camillelamy
+ - hchao
diff --git a/test/fixtures/wpt/fetch/local-network-access/README.md b/test/fixtures/wpt/fetch/local-network-access/README.md
new file mode 100644
index 00000000000..d4945a0bfb2
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/README.md
@@ -0,0 +1,11 @@
+# Local Network Access tests
+
+This directory contains tests for Local Network Access' integration with
+the Fetch specification.
+
+See also:
+
+* [Spec](https://wicg.github.io/local-network-access/)
+
+Local Network Access replaced [Private Network
+Access](https://wicg.github.io/private-network-access/).
diff --git a/test/fixtures/wpt/fetch/local-network-access/fetch.tentative.https.html b/test/fixtures/wpt/fetch/local-network-access/fetch.tentative.https.html
new file mode 100644
index 00000000000..b783269207b
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/fetch.tentative.https.html
@@ -0,0 +1,87 @@
+
+
+LNA Fetch tests: HTTPS
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/local-network-access/iframe.tentative.https.window.js b/test/fixtures/wpt/fetch/local-network-access/iframe.tentative.https.window.js
new file mode 100644
index 00000000000..d2b532aeae4
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/iframe.tentative.https.window.js
@@ -0,0 +1,199 @@
+// META: script=/common/subset-tests-by-key.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=resources/support.sub.js
+// META: timeout=long
+// META: variant=?include=from-loopback
+// META: variant=?include=from-local
+// META: variant=?include=from-public
+// META: variant=?include=from-treat-as-public
+//
+// Spec: https://wicg.github.io/local-network-access/#integration-fetch
+//
+// These tests verify that secure contexts can navigate iframes to less-public
+// address spaces iff the initiating document has been granted the LNA
+// permission.
+//
+// This file covers only those tests that must execute in a secure context.
+
+setup(() => {
+ assert_true(window.isSecureContext);
+});
+
+// Source: secure loopback context.
+//
+// All iframe navigations unaffected by Local Network Access.
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to local: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to public: no permission required.');
+
+// Source: local secure context.
+//
+// All iframe navigations unaffected by Local Network Access.
+
+// Requests from the `local` address space to the `loopback` address space
+// are not yet restricted by LNA.
+subsetTestByKey(
+ 'from-local', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to local: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => iframeTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to public: no permission required.');
+
+
+// Generates tests of permission behavior for a single (source, target) pair.
+//
+// Scenarios:
+//
+// - parent (source) navigates child (target):
+// - parent has been denied the LNA permission (failure)
+// - parent has been granted the LNA permission (success)
+//
+function makePermissionTests({
+ key,
+ sourceName,
+ sourceServer,
+ sourceTreatAsPublic,
+ targetName,
+ targetServer,
+}) {
+ const prefix = `${sourceName} to ${targetName}: `;
+
+ const source = {
+ server: sourceServer,
+ treatAsPublic: sourceTreatAsPublic,
+ };
+
+ promise_test(
+ t => iframeTest(t, {
+ source,
+ target: {
+ server: targetServer,
+ },
+ expected: NavigationTestResult.FAILURE,
+ permission: 'denied',
+ }),
+ prefix + 'permission denied.');
+
+ promise_test(
+ t => iframeTest(t, {
+ source,
+ target: {
+ server: targetServer,
+ },
+ expected: NavigationTestResult.SUCCESS,
+ permission: 'granted',
+ }),
+ prefix + 'success.');
+}
+
+
+// Source: public secure context.
+//
+// iframe navigations to the loopback and local address spaces require the LNA
+// permission.
+
+subsetTestByKey('from-public', makePermissionTests, {
+ sourceServer: Server.HTTPS_PUBLIC,
+ sourceName: 'public',
+ targetServer: Server.HTTPS_LOOPBACK,
+ targetName: 'loopback',
+});
+
+subsetTestByKey('from-public', makePermissionTests, {
+ sourceServer: Server.HTTPS_PUBLIC,
+ sourceName: 'public',
+ targetServer: Server.HTTPS_LOCAL,
+ targetName: 'local',
+});
+
+subsetTestByKey(
+ 'from-public', promise_test, t => iframeTest(t, {
+ source: Server.HTTPS_PUBLIC,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public: no permission required.');
+
+// The following tests verify that `CSP: treat-as-public-address` makes
+// documents behave as if they had been served from a public IP address.
+
+subsetTestByKey('from-treat-as-public', makePermissionTests, {
+ sourceServer: Server.HTTPS_LOOPBACK,
+ sourceTreatAsPublic: true,
+ sourceName: 'treat-as-public-address',
+ targetServer: Server.OTHER_HTTPS_LOOPBACK,
+ targetName: 'loopback',
+});
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => iframeTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to local (same-origin): no permission required.');
+
+subsetTestByKey('from-treat-as-public', makePermissionTests, {
+ sourceServer: Server.HTTPS_LOOPBACK,
+ sourceTreatAsPublic: true,
+ sourceName: 'treat-as-public-address',
+ targetServer: Server.HTTPS_LOCAL,
+ targetName: 'local',
+});
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => iframeTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to public: no permission required.');
diff --git a/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.https.window.js b/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.https.window.js
new file mode 100644
index 00000000000..abdefb8cd7c
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.https.window.js
@@ -0,0 +1,151 @@
+// META: script=/common/subset-tests-by-key.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/utils.js
+// META: script=resources/support.sub.js
+// META: timeout=long
+// META: variant=?include=from-loopback
+// META: variant=?include=from-local
+// META: variant=?include=from-public
+// META: variant=?include=from-treat-as-public
+//
+// These tests verify that secure contexts can make top-level navigations
+// to less-public address spaces. These are not restricted under LNA.
+
+setup(() => {
+ assert_true(window.isSecureContext);
+});
+
+// Source: secure loopback context.
+//
+// All top-level navigations unaffected by Local Network Access.
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOOPBACK,
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOOPBACK,
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to local: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOOPBACK,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to public: no preflight required.');
+
+// Source: secure local context.
+//
+// All top-level navigations unaffected by Local Network Access.
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOCAL,
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOCAL,
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to local: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_LOCAL,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to public: no permission required.');
+
+// Source: secure public context.
+//
+// All top-level navigations unaffected by Local Network Access
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_PUBLIC,
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_PUBLIC,
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to local: no permission required.');
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTPS_PUBLIC,
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public: no permission required.');
+
+// The following tests verify that `CSP: treat-as-public-address` makes
+// documents behave as if they had been served from a public IP address.
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.OTHER_HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTPS_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to loopback (same-origin): no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTPS_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to local: no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTPS_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTPS_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to public: no permission required.');
diff --git a/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.window.js b/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.window.js
new file mode 100644
index 00000000000..4186bad5899
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/navigate.tentative.window.js
@@ -0,0 +1,154 @@
+// META: script=/common/subset-tests-by-key.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/utils.js
+// META: script=resources/support.sub.js
+// META: timeout=long
+// META: variant=?include=from-loopback
+// META: variant=?include=from-local
+// META: variant=?include=from-public
+// META: variant=?include=from-treat-as-public
+//
+// These tests verify that nonsecure contexts can make top-level navigations
+// to less-public address spaces. These are not restricted under LNA.
+//
+// This file covers only those tests that must execute in a non secure context.
+// Other tests are defined in: navigate.tentative.https.window.js
+
+setup(() => {
+ assert_false(window.isSecureContext);
+});
+
+// Source: nonsecure loopback context.
+//
+// All top-level navigations unaffected by Local Network Access.
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTP_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTP_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to local: no permission required.');
+
+subsetTestByKey(
+ 'from-loopback', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOOPBACK,
+ target: Server.HTTP_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'loopback to public: no preflight required.');
+
+// Source: secure local context.
+//
+// All top-level navigations unaffected by Local Network Access.
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTP_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTP_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to local: no permission required.');
+
+subsetTestByKey(
+ 'from-local', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_LOCAL,
+ target: Server.HTTP_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'local to public: no permission required.');
+
+// Source: secure public context.
+//
+// All top-level navigations unaffected by Local Network Access
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_PUBLIC,
+ target: Server.HTTP_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_PUBLIC,
+ target: Server.HTTP_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to local: no permission required.');
+
+subsetTestByKey(
+ 'from-public', promise_test, t => navigateTest(t, {
+ source: Server.HTTP_PUBLIC,
+ target: Server.HTTP_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public: no permission required.');
+
+// The following tests verify that `CSP: treat-as-public-address` makes
+// documents behave as if they had been served from a public IP address.
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTP_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.OTHER_HTTP_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to loopback: no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTP_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTP_LOOPBACK,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to loopback (same-origin): no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTP_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTP_LOCAL,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to local: no permission required.');
+
+subsetTestByKey(
+ 'from-treat-as-public', promise_test,
+ t => navigateTest(t, {
+ source: {
+ server: Server.HTTP_LOOPBACK,
+ treatAsPublic: true,
+ },
+ target: Server.HTTP_PUBLIC,
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'treat-as-public-address to public: no permission required.');
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local-http.html b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local-http.html
new file mode 100644
index 00000000000..dcad775bfec
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local-http.html
@@ -0,0 +1,40 @@
+
+
+Fetch HTTP local with targetAddressSpace local
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local.html b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local.html
new file mode 100644
index 00000000000..bc12e2660bc
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-local.html
@@ -0,0 +1,52 @@
+
+
+Fetch Local resource
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html
new file mode 100644
index 00000000000..fb306f99d3c
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/fetch-public-http-wrong-address-space.html
@@ -0,0 +1,42 @@
+
+
+Fetch HTTP public targetAddress local resource
+
+
+
+
+
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/iframer.html b/test/fixtures/wpt/fetch/local-network-access/resources/iframer.html
new file mode 100644
index 00000000000..ede09bc6b0a
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/iframer.html
@@ -0,0 +1,35 @@
+
+
+Iframer
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/navigate.html b/test/fixtures/wpt/fetch/local-network-access/resources/navigate.html
new file mode 100644
index 00000000000..5796cb41be5
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/navigate.html
@@ -0,0 +1,9 @@
+
+
+Navigate
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/openee.html b/test/fixtures/wpt/fetch/local-network-access/resources/openee.html
new file mode 100644
index 00000000000..2e06a8d0328
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/openee.html
@@ -0,0 +1,7 @@
+
+
+Openee
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/support.sub.js b/test/fixtures/wpt/fetch/local-network-access/resources/support.sub.js
new file mode 100644
index 00000000000..157c2b40066
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/support.sub.js
@@ -0,0 +1,254 @@
+// Maps protocol (without the trailing colon) and address space to port.
+//
+// TODO(crbug.com/418737577): change keys to be consistent with new address
+// space names.
+const SERVER_PORTS = {
+ "http": {
+ "loopback": {{ports[http][0]}},
+ "other-loopback": {{ports[http][1]}},
+ "local": {{ports[http-local][0]}},
+ "public": {{ports[http-public][0]}},
+ },
+ "https": {
+ "loopback": {{ports[https][0]}},
+ "other-loopback": {{ports[https][1]}},
+ "local": {{ports[https-local][0]}},
+ "public": {{ports[https-public][0]}},
+ },
+ "ws": {
+ "loopback": {{ports[ws][0]}},
+ },
+ "wss": {
+ "loopback": {{ports[wss][0]}},
+ },
+};
+
+// A `Server` is a web server accessible by tests. It has the following shape:
+//
+// {
+// addressSpace: the IP address space of the server ("loopback", "local" or
+// "public"),
+// name: a human-readable name for the server,
+// port: the port on which the server listens for connections,
+// protocol: the protocol (including trailing colon) spoken by the server,
+// }
+//
+// Constants below define the available servers, which can also be accessed
+// programmatically with `get()`.
+class Server {
+ // Maps the given `protocol` (without a trailing colon) and `addressSpace` to
+ // a server. Returns null if no such server exists.
+ static get(protocol, addressSpace) {
+ const ports = SERVER_PORTS[protocol];
+ if (ports === undefined) {
+ return null;
+ }
+
+ const port = ports[addressSpace];
+ if (port === undefined) {
+ return null;
+ }
+
+ return {
+ addressSpace,
+ name: `${protocol}-${addressSpace}`,
+ port,
+ protocol: protocol + ':',
+ };
+ }
+
+ static HTTP_LOOPBACK = Server.get("http", "loopback");
+ static OTHER_HTTP_LOOPBACK = Server.get("http", "other-loopback");
+ static HTTP_LOCAL = Server.get("http", "local");
+ static HTTP_PUBLIC = Server.get("http", "public");
+ static HTTPS_LOOPBACK = Server.get("https", "loopback");
+ static OTHER_HTTPS_LOOPBACK = Server.get("https", "other-loopback");
+ static HTTPS_LOCAL = Server.get("https", "local");
+ static HTTPS_PUBLIC = Server.get("https", "public");
+ static WS_LOOPBACK = Server.get("ws", "loopback");
+ static WSS_LOOPBACK = Server.get("wss", "loopback");
+};
+
+// Resolves a URL relative to the current location, returning an absolute URL.
+//
+// `url` specifies the relative URL, e.g. "foo.html" or "http://foo.example".
+// `options`, if defined, should have the following shape:
+//
+// {
+// // Optional. Overrides the protocol of the returned URL.
+// protocol,
+//
+// // Optional. Overrides the port of the returned URL.
+// port,
+//
+// // Extra headers.
+// headers,
+//
+// // Extra search params.
+// searchParams,
+// }
+//
+function resolveUrl(url, options) {
+ const result = new URL(url, window.location);
+ if (options === undefined) {
+ return result;
+ }
+
+ const { port, protocol, headers, searchParams } = options;
+ if (port !== undefined) {
+ result.port = port;
+ }
+ if (protocol !== undefined) {
+ result.protocol = protocol;
+ }
+ if (headers !== undefined) {
+ const pipes = [];
+ for (key in headers) {
+ pipes.push(`header(${key},${headers[key]})`);
+ }
+ result.searchParams.append("pipe", pipes.join("|"));
+ }
+ if (searchParams !== undefined) {
+ for (key in searchParams) {
+ result.searchParams.append(key, searchParams[key]);
+ }
+ }
+
+ return result;
+}
+
+// Computes options to pass to `resolveUrl()` for a source document's URL.
+//
+// `server` identifies the server from which to load the document.
+// `treatAsPublic`, if set to true, specifies that the source document should
+// be artificially placed in the `public` address space using CSP.
+function sourceResolveOptions({ server, treatAsPublic }) {
+ const options = {...server};
+ if (treatAsPublic) {
+ options.headers = { "Content-Security-Policy": "treat-as-public-address" };
+ }
+ return options;
+}
+
+// Computes the URL of a target handler configured with the given options.
+//
+// `server` identifies the server from which to load the resource.
+// `behavior` specifies the behavior of the target server. It may contain:
+// - `response`: The result of calling one of `ResponseBehavior`'s methods.
+// - `redirect`: A URL to which the target should redirect GET requests.
+function resolveTargetUrl({ server, behavior }) {
+ if (server === undefined) {
+ throw new Error("no server specified.");
+ }
+ const options = {...server};
+ if (behavior) {
+ const { response, redirect } = behavior;
+ options.searchParams = {
+ ...response,
+ };
+ if (redirect !== undefined) {
+ options.searchParams.redirect = redirect;
+ }
+ }
+
+ return resolveUrl("target.py", options);
+}
+
+// Methods generate behavior specifications for how `resources/target.py`
+// should behave upon receiving a regular (non-preflight) request.
+const ResponseBehavior = {
+ // The response should succeed without CORS headers.
+ default: () => ({}),
+
+ // The response should succeed with CORS headers.
+ allowCrossOrigin: () => ({ "final-headers": "cors" }),
+};
+
+const FetchTestResult = {
+ SUCCESS: {
+ ok: true,
+ body: "success",
+ },
+ OPAQUE: {
+ ok: false,
+ type: "opaque",
+ body: "",
+ },
+ FAILURE: {
+ error: "TypeError: Failed to fetch",
+ },
+};
+
+// Helper function for checking results from fetch tests.
+function checkTestResult(actual, expected) {
+ assert_equals(actual.error, expected.error, "error mismatch");
+ assert_equals(actual.ok, expected.ok, "response ok mismatch");
+ assert_equals(actual.body, expected.body, "response body mismatch");
+
+ if (expected.type !== undefined) {
+ assert_equals(type, expected.type, "response type mismatch");
+ }
+}
+
+// Registers an event listener that will resolve this promise when this
+// window receives a message posted to it.
+function futureMessage(options) {
+ return new Promise(resolve => {
+ window.addEventListener('message', (e) => {
+ resolve(e.data);
+ });
+ });
+};
+
+const NavigationTestResult = {
+ SUCCESS: 'loaded',
+ FAILURE: 'timeout',
+};
+
+async function iframeTest(
+ t, {source, target, expected, permission = 'denied'}) {
+ const targetUrl =
+ resolveUrl('resources/openee.html', sourceResolveOptions(target));
+
+ const sourceUrl =
+ resolveUrl('resources/iframer.html', sourceResolveOptions(source));
+ sourceUrl.searchParams.set('permission', permission);
+ sourceUrl.searchParams.set('url', targetUrl);
+
+ const popup = window.open(sourceUrl);
+ t.add_cleanup(() => popup.close());
+
+ // The child frame posts a message iff it loads successfully.
+ // There exists no interoperable way to check whether an iframe failed to
+ // load, so we use a timeout.
+ // See: https://github.com/whatwg/html/issues/125
+ const result = await Promise.race([
+ futureMessage().then((data) => data.message),
+ new Promise((resolve) => {
+ t.step_timeout(() => resolve('timeout'), 2000 /* ms */);
+ }),
+ ]);
+
+ assert_equals(result, expected);
+}
+
+async function navigateTest(t, {source, target, expected}) {
+ const targetUrl =
+ resolveUrl('resources/openee.html', sourceResolveOptions(target));
+
+ const sourceUrl =
+ resolveUrl('resources/navigate.html', sourceResolveOptions(source));
+ sourceUrl.searchParams.set('url', targetUrl);
+
+ const popup = window.open(sourceUrl);
+ t.add_cleanup(() => popup.close());
+
+ const result = await Promise.race([
+ futureMessage().then((data) => data.message),
+ new Promise((resolve) => {
+ t.step_timeout(() => resolve('timeout'), 2000 /* ms */);
+ }),
+ ]);
+
+ assert_equals(result, expected);
+}
diff --git a/test/fixtures/wpt/fetch/local-network-access/resources/target.py b/test/fixtures/wpt/fetch/local-network-access/resources/target.py
new file mode 100644
index 00000000000..eabcdd47517
--- /dev/null
+++ b/test/fixtures/wpt/fetch/local-network-access/resources/target.py
@@ -0,0 +1,105 @@
+# This endpoint responds to requests for a target of a (possible) LNA request.
+#
+# Its behavior can be configured with various search/GET parameters, all of
+# which are optional:
+#
+# - final-headers: Valid values are:
+# - cors: this endpoint responds with valid CORS headers to CORS-enabled
+# non-preflight requests. These should be sufficient for non-preflighted
+# CORS-enabled requests to succeed.
+# - sw: this endpoint responds with a valid Service-Worker header to allow
+# for the request to serve as a Service worker script resource. This is
+# only valid in conjunction with the cors value above.
+# - unspecified: this endpoint responds with no CORS headers to non-preflight
+# requests. This should fail CORS-enabled requests, but be sufficient for
+# no-CORS requests.
+#
+# The following parameters only affect non-preflight responses:
+#
+# - redirect: If set, the response code is set to 301 and the `Location`
+# response header is set to this value.
+# - mime-type: If set, the `Content-Type` response header is set to this value.
+# - file: Specifies a path (relative to this file's directory) to a file. If
+# set, the response body is copied from this file.
+# - random-js-prefix: If set to any value, the response body is prefixed with
+# a Javascript comment line containing a random value. This is useful in
+# service worker tests, since service workers are only updated if the new
+# script is not byte-for-byte identical with the old script.
+# - body: If set and `file` is not, the response body is set to this value.
+#
+
+import os
+import random
+
+from wptserve.utils import isomorphic_encode
+
+_ACAO = ("Access-Control-Allow-Origin", "*")
+_ACAH = ("Access-Control-Allow-Headers", "Service-Worker")
+
+def _get_response_headers(method, mode, origin):
+ acam = ("Access-Control-Allow-Methods", method)
+
+ if mode == b"cors":
+ return [acam, _ACAO]
+
+ if mode == b"cors+sw":
+ return [acam, _ACAO, _ACAH]
+
+ if mode == b"navigation":
+ return [
+ acam,
+ ("Access-Control-Allow-Origin", origin),
+ ("Access-Control-Allow-Credentials", "true"),
+ ]
+
+ return []
+
+
+def _is_loaded_in_fenced_frame(request):
+ return request.GET.get(b"is-loaded-in-fenced-frame")
+
+def _final_response_body(request):
+ file_name = None
+ if file_name is None:
+ file_name = request.GET.get(b"file")
+ if file_name is None:
+ return request.GET.get(b"body") or "success"
+
+ prefix = b""
+ if request.GET.get(b"random-js-prefix"):
+ value = random.randint(0, 1000000000)
+ prefix = isomorphic_encode("// Random value: {}\n\n".format(value))
+
+ path = os.path.join(os.path.dirname(isomorphic_encode(__file__)), file_name)
+ with open(path, 'rb') as f:
+ contents = f.read()
+
+ return prefix + contents
+
+def _handle_final_request(request, response):
+ mode = request.GET.get(b"final-headers")
+ origin = request.headers.get("Origin")
+ headers = _get_response_headers(request.method, mode, origin)
+
+ redirect = request.GET.get(b"redirect")
+ if redirect is not None:
+ headers.append(("Location", redirect))
+ return (301, headers, b"")
+
+ mime_type = request.GET.get(b"mime-type")
+ if mime_type is not None:
+ headers.append(("Content-Type", mime_type),)
+
+ if _is_loaded_in_fenced_frame(request):
+ headers.append(("Supports-Loading-Mode", "fenced-frame"))
+
+ body = _final_response_body(request)
+ return (headers, body)
+
+
+def main(request, response):
+ try:
+ return _handle_final_request(request, response)
+ except BaseException as e:
+ # Surface exceptions to the client, where they show up as assertion errors.
+ return (500, [("X-exception", str(e))], "exception: {}".format(e))
diff --git a/test/fixtures/wpt/fetch/orb/tentative/script-js-unlabeled-gziped.sub.html b/test/fixtures/wpt/fetch/orb/tentative/script-js-unlabeled-gzipped.sub.html
similarity index 100%
rename from test/fixtures/wpt/fetch/orb/tentative/script-js-unlabeled-gziped.sub.html
rename to test/fixtures/wpt/fetch/orb/tentative/script-js-unlabeled-gzipped.sub.html
diff --git a/test/fixtures/wpt/fetch/private-network-access/README.md b/test/fixtures/wpt/fetch/private-network-access/README.md
index a69aab48723..cbb5b85b74d 100644
--- a/test/fixtures/wpt/fetch/private-network-access/README.md
+++ b/test/fixtures/wpt/fetch/private-network-access/README.md
@@ -8,3 +8,6 @@ See also:
* [The specification](https://wicg.github.io/private-network-access/)
* [The repository](https://github.com/WICG/private-network-access/)
* [Open issues](https://github.com/WICG/private-network-access/issues/)
+
+Private Network Access is deprecated and will eventually be replaced by [Local
+Network Access](https://github.com/explainers-by-googlers/local-network-access).
diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js
deleted file mode 100644
index 33e94d57f1a..00000000000
--- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/utils.js
-// META: script=resources/support.sub.js
-// META: script=/fenced-frame/resources/utils.js
-// META: timeout=long
-//
-// Spec: https://wicg.github.io/private-network-access/#integration-fetch
-//
-// These tests verify that contexts can navigate fenced frames to more-public or
-// same address spaces without private network access preflight request header.
-
-setup(() => {
- assert_true(window.isSecureContext);
-});
-
-// Source: secure local context.
-//
-// All fetches unaffected by Private Network Access.
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_LOCAL},
- expected: FrameTestResult.SUCCESS,
- }),
- 'local to local: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_PRIVATE},
- expected: FrameTestResult.SUCCESS,
- }),
- 'local to private: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_PUBLIC},
- expected: FrameTestResult.SUCCESS,
- }),
- 'local to public: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {server: Server.HTTPS_PRIVATE},
- expected: FrameTestResult.SUCCESS,
- }),
- 'private to private: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {server: Server.HTTPS_PUBLIC},
- expected: FrameTestResult.SUCCESS,
- }),
- 'private to public: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {server: Server.HTTPS_PUBLIC},
- target: {server: Server.HTTPS_PUBLIC},
- expected: FrameTestResult.SUCCESS,
- }),
- 'public to public: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {server: Server.HTTPS_PUBLIC},
- expected: FrameTestResult.SUCCESS,
- }),
- 'treat-as-public-address to public: no preflight required.');
-
-promise_test(
- t => fencedFrameTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {
- server: Server.HTTPS_PUBLIC,
- behavior: {preflight: PreflightBehavior.optionalSuccess(token())}
- },
- expected: FrameTestResult.SUCCESS,
- }),
- 'treat-as-public-address to local: optional preflight');
diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js
deleted file mode 100644
index 2dff325e3e1..00000000000
--- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js
+++ /dev/null
@@ -1,330 +0,0 @@
-// META: script=/common/subset-tests-by-key.js
-// META: script=/common/utils.js
-// META: script=resources/support.sub.js
-// META: script=/fenced-frame/resources/utils.js
-// META: variant=?include=baseline
-// META: variant=?include=from-local
-// META: variant=?include=from-private
-// META: variant=?include=from-public
-// META: timeout=long
-//
-// Spec: https://wicg.github.io/private-network-access/#integration-fetch
-//
-// These tests verify that secure contexts can fetch subresources in fenced
-// frames from all address spaces, provided that the target server, if more
-// private than the initiator, respond affirmatively to preflight requests.
-//
-
-setup(() => {
- // Making sure we are in a secure context, as expected.
- assert_true(window.isSecureContext);
-});
-
-// Source: secure local context.
-//
-// All fetches unaffected by Private Network Access.
-
-subsetTestByKey(
- 'from-local', promise_test, t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_LOCAL},
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'local to local: no preflight required.');
-
-subsetTestByKey(
- 'from-local', promise_test,
- t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {
- server: Server.HTTPS_PRIVATE,
- behavior: {response: ResponseBehavior.allowCrossOrigin()},
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'local to private: no preflight required.');
-
-
-subsetTestByKey(
- 'from-local', promise_test,
- t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {
- server: Server.HTTPS_PUBLIC,
- behavior: {response: ResponseBehavior.allowCrossOrigin()},
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'local to public: no preflight required.');
-
-// Strictly speaking, the following two tests do not exercise PNA-specific
-// logic, but they serve as a baseline for comparison, ensuring that non-PNA
-// preflight requests are sent and handled as expected.
-
-subsetTestByKey(
- 'baseline', promise_test,
- t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {
- server: Server.HTTPS_PUBLIC,
- behavior: {
- preflight: PreflightBehavior.failure(),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'PUT', mode: 'cors'},
- expected: FetchTestResult.FAILURE,
- }),
- 'local to public: PUT preflight failure.');
-
-subsetTestByKey(
- 'baseline', promise_test,
- t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {
- server: Server.HTTPS_PUBLIC,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- }
- },
- fetchOptions: {method: 'PUT', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'local to public: PUT preflight success.');
-
-// Generates tests of preflight behavior for a single (source, target) pair.
-//
-// Scenarios:
-//
-// - cors mode:
-// - preflight response has non-2xx HTTP code
-// - preflight response is missing CORS headers
-// - preflight response is missing the PNA-specific `Access-Control` header
-// - final response is missing CORS headers
-// - success
-// - success with PUT method (non-"simple" request)
-// - no-cors mode:
-// - preflight response has non-2xx HTTP code
-// - preflight response is missing CORS headers
-// - preflight response is missing the PNA-specific `Access-Control` header
-// - success
-//
-function makePreflightTests({
- subsetKey,
- source,
- sourceDescription,
- targetServer,
- targetDescription,
-}) {
- const prefix = `${sourceDescription} to ${targetDescription}: `;
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.failure(),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'failed preflight.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.noCorsHeader(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'missing CORS headers on preflight response.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.noPnaHeader(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'missing PNA header on preflight response.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.success(token())},
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'missing CORS headers on final response.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- prefix + 'success.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: {method: 'PUT', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- prefix + 'PUT success.');
-
- subsetTestByKey(
- subsetKey, promise_test, t => fencedFrameFetchTest(t, {
- source,
- target: {server: targetServer},
- fetchOptions: {method: 'GET', mode: 'no-cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'no-CORS mode failed preflight.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.noCorsHeader(token())},
- },
- fetchOptions: {method: 'GET', mode: 'no-cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'no-CORS mode missing CORS headers on preflight response.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.noPnaHeader(token())},
- },
- fetchOptions: {method: 'GET', mode: 'no-cors'},
- expected: FetchTestResult.FAILURE,
- }),
- prefix + 'no-CORS mode missing PNA header on preflight response.');
-
- subsetTestByKey(
- subsetKey, promise_test,
- t => fencedFrameFetchTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.success(token())},
- },
- fetchOptions: {method: 'GET', mode: 'no-cors'},
- expected: FetchTestResult.OPAQUE,
- }),
- prefix + 'no-CORS mode success.');
-}
-
-// Source: private secure context.
-//
-// Fetches to the local address space require a successful preflight response
-// carrying a PNA-specific header.
-
-makePreflightTests({
- subsetKey: 'from-private',
- source: {server: Server.HTTPS_PRIVATE},
- sourceDescription: 'private',
- targetServer: Server.HTTPS_LOCAL,
- targetDescription: 'local',
-});
-
-subsetTestByKey(
- 'from-private', promise_test, t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {server: Server.HTTPS_PRIVATE},
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'private to private: no preflight required.');
-
-subsetTestByKey(
- 'from-private', promise_test,
- t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {
- server: Server.HTTPS_PRIVATE,
- behavior: {response: ResponseBehavior.allowCrossOrigin()},
- },
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'private to public: no preflight required.');
-
-// Source: public secure context.
-//
-// Fetches to the local and private address spaces require a successful
-// preflight response carrying a PNA-specific header.
-
-makePreflightTests({
- subsetKey: 'from-public',
- source: {server: Server.HTTPS_PUBLIC},
- sourceDescription: 'public',
- targetServer: Server.HTTPS_LOCAL,
- targetDescription: 'local',
-});
-
-makePreflightTests({
- subsetKey: 'from-public',
- source: {server: Server.HTTPS_PUBLIC},
- sourceDescription: 'public',
- targetServer: Server.HTTPS_PRIVATE,
- targetDescription: 'private',
-});
-
-subsetTestByKey(
- 'from-public', promise_test, t => fencedFrameFetchTest(t, {
- source: {server: Server.HTTPS_PUBLIC},
- target: {server: Server.HTTPS_PUBLIC},
- fetchOptions: {method: 'GET', mode: 'cors'},
- expected: FetchTestResult.SUCCESS,
- }),
- 'public to public: no preflight required.');
diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js
deleted file mode 100644
index 370cc9fbe9d..00000000000
--- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/utils.js
-// META: script=resources/support.sub.js
-// META: script=/fenced-frame/resources/utils.js
-// META: timeout=long
-//
-// Spec: https://wicg.github.io/private-network-access/#integration-fetch
-//
-// These tests verify that contexts can navigate fenced frames to less-public
-// address spaces iff the target server responds affirmatively to preflight
-// requests.
-
-setup(() => {
- assert_true(window.isSecureContext);
-});
-
-// Generates tests of preflight behavior for a single (source, target) pair.
-//
-// Scenarios:
-//
-// - parent navigates child:
-// - preflight response has non-2xx HTTP code
-// - preflight response is missing CORS headers
-// - preflight response is missing the PNA-specific `Access-Control` header
-// - preflight response has the required PNA related headers, but still fails
-// because of the limitation of fenced frame that subjects to PNA checks.
-//
-function makePreflightTests({
- sourceName,
- sourceServer,
- sourceTreatAsPublic,
- targetName,
- targetServer,
-}) {
- const prefix = `${sourceName} to ${targetName}: `;
-
- const source = {
- server: sourceServer,
- treatAsPublic: sourceTreatAsPublic,
- };
-
- promise_test_parallel(
- t => fencedFrameTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.failure()},
- },
- expected: FrameTestResult.FAILURE,
- }),
- prefix + 'failed preflight.');
-
- promise_test_parallel(
- t => fencedFrameTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.noCorsHeader(token())},
- },
- expected: FrameTestResult.FAILURE,
- }),
- prefix + 'missing CORS headers.');
-
- promise_test_parallel(
- t => fencedFrameTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {preflight: PreflightBehavior.noPnaHeader(token())},
- },
- expected: FrameTestResult.FAILURE,
- }),
- prefix + 'missing PNA header.');
-
- promise_test_parallel(
- t => fencedFrameTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin()
- },
- },
- expected: FrameTestResult.FAILURE,
- }),
- prefix + 'failed because fenced frames are incompatible with PNA.');
-}
-
-// Source: private secure context.
-//
-// Fetches to the local address space require a successful preflight response
-// carrying a PNA-specific header.
-
-makePreflightTests({
- sourceServer: Server.HTTPS_PRIVATE,
- sourceName: 'private',
- targetServer: Server.HTTPS_LOCAL,
- targetName: 'local',
-});
-
-// Source: public secure context.
-//
-// Fetches to the local and private address spaces require a successful
-// preflight response carrying a PNA-specific header.
-
-makePreflightTests({
- sourceServer: Server.HTTPS_PUBLIC,
- sourceName: 'public',
- targetServer: Server.HTTPS_LOCAL,
- targetName: 'local',
-});
-
-makePreflightTests({
- sourceServer: Server.HTTPS_PUBLIC,
- sourceName: 'public',
- targetServer: Server.HTTPS_PRIVATE,
- targetName: 'private',
-});
-
-// The following tests verify that `CSP: treat-as-public-address` makes
-// documents behave as if they had been served from a public IP address.
-
-makePreflightTests({
- sourceServer: Server.HTTPS_LOCAL,
- sourceTreatAsPublic: true,
- sourceName: 'treat-as-public-address',
- targetServer: Server.OTHER_HTTPS_LOCAL,
- targetName: 'local',
-});
-
-promise_test_parallel(
- t => fencedFrameTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {server: Server.HTTPS_LOCAL},
- expected: FrameTestResult.FAILURE,
- }),
- 'treat-as-public-address to local (same-origin): fenced frame embedder ' +
- 'initiated navigation has opaque origin.');
-
-makePreflightTests({
- sourceServer: Server.HTTPS_LOCAL,
- sourceTreatAsPublic: true,
- sourceName: 'treat-as-public-address',
- targetServer: Server.HTTPS_PRIVATE,
- targetName: 'private',
-});
diff --git a/test/fixtures/wpt/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js
deleted file mode 100644
index dbae5193b5c..00000000000
--- a/test/fixtures/wpt/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js
+++ /dev/null
@@ -1,278 +0,0 @@
-// META: script=/common/utils.js
-// META: script=resources/support.sub.js
-// META: timeout=long
-//
-// Spec: https://wicg.github.io/private-network-access
-//
-// These tests verify that secure contexts can fetch non-secure subresources
-// from more private address spaces, avoiding mixed context checks, as long as
-// they specify a valid `targetAddressSpace` fetch option that matches the
-// target server's address space.
-
-setup(() => {
- // Making sure we are in a secure context, as expected.
- assert_true(window.isSecureContext);
-});
-
-// Given `addressSpace`, returns the other three possible IP address spaces.
-function otherAddressSpaces(addressSpace) {
- switch (addressSpace) {
- case "local": return ["unknown", "private", "public"];
- case "private": return ["unknown", "local", "public"];
- case "public": return ["unknown", "local", "private"];
- }
-}
-
-// Generates tests of `targetAddressSpace` for the given (source, target)
-// address space pair, expecting fetches to succeed iff `targetAddressSpace` is
-// correct.
-//
-// Scenarios exercised:
-//
-// - cors mode:
-// - missing targetAddressSpace option
-// - incorrect targetAddressSpace option (x3, see `otherAddressSpaces()`)
-// - failed preflight
-// - success
-// - success with PUT method (non-"simple" request)
-// - no-cors mode:
-// - success
-//
-function makeTests({ source, target }) {
- const sourceServer = Server.get("https", source);
- const targetServer = Server.get("http", target);
-
- const makeTest = ({
- fetchOptions,
- targetBehavior,
- name,
- expected
- }) => {
- promise_test_parallel(t => fetchTest(t, {
- source: { server: sourceServer },
- target: {
- server: targetServer,
- behavior: targetBehavior,
- },
- fetchOptions,
- expected,
- }), `${sourceServer.name} to ${targetServer.name}: ${name}.`);
- };
-
- makeTest({
- name: "missing targetAddressSpace",
- targetBehavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- expected: FetchTestResult.FAILURE,
- });
-
- const correctAddressSpace = targetServer.addressSpace;
-
- for (const targetAddressSpace of otherAddressSpaces(correctAddressSpace)) {
- makeTest({
- name: `wrong targetAddressSpace "${targetAddressSpace}"`,
- targetBehavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- fetchOptions: { targetAddressSpace },
- expected: FetchTestResult.FAILURE,
- });
- }
-
- makeTest({
- name: "failed preflight",
- targetBehavior: {
- preflight: PreflightBehavior.failure(),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- fetchOptions: { targetAddressSpace: correctAddressSpace },
- expected: FetchTestResult.FAILURE,
- });
-
- makeTest({
- name: "success",
- targetBehavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- fetchOptions: { targetAddressSpace: correctAddressSpace },
- expected: FetchTestResult.SUCCESS,
- });
-
- makeTest({
- name: "PUT success",
- targetBehavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- fetchOptions: {
- targetAddressSpace: correctAddressSpace,
- method: "PUT",
- },
- expected: FetchTestResult.SUCCESS,
- });
-
- makeTest({
- name: "no-cors success",
- targetBehavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- fetchOptions: {
- targetAddressSpace: correctAddressSpace,
- mode: "no-cors",
- },
- expected: FetchTestResult.OPAQUE,
- });
-}
-
-// Generates tests for the given (source, target) address space pair expecting
-// that `targetAddressSpace` cannot be used to bypass mixed content.
-//
-// Scenarios exercised:
-//
-// - wrong `targetAddressSpace` (x3, see `otherAddressSpaces()`)
-// - correct `targetAddressSpace`
-//
-function makeNoBypassTests({ source, target }) {
- const sourceServer = Server.get("https", source);
- const targetServer = Server.get("http", target);
-
- const prefix = `${sourceServer.name} to ${targetServer.name}: `;
-
- const correctAddressSpace = targetServer.addressSpace;
- for (const targetAddressSpace of otherAddressSpaces(correctAddressSpace)) {
- promise_test_parallel(t => fetchTest(t, {
- source: { server: sourceServer },
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace },
- expected: FetchTestResult.FAILURE,
- }), prefix + `wrong targetAddressSpace "${targetAddressSpace}".`);
- }
-
- promise_test_parallel(t => fetchTest(t, {
- source: { server: sourceServer },
- target: {
- server: targetServer,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace: correctAddressSpace },
- expected: FetchTestResult.FAILURE,
- }), prefix + 'not a private network request.');
-}
-
-// Source: local secure context.
-//
-// Fetches to the local and private address spaces cannot use
-// `targetAddressSpace` to bypass mixed content, as they are not otherwise
-// blocked by Private Network Access.
-
-makeNoBypassTests({ source: "local", target: "local" });
-makeNoBypassTests({ source: "local", target: "private" });
-makeNoBypassTests({ source: "local", target: "public" });
-
-// Source: private secure context.
-//
-// Fetches to the local address space requires the right `targetAddressSpace`
-// option, as well as a successful preflight response carrying a PNA-specific
-// header.
-//
-// Fetches to the private address space cannot use `targetAddressSpace` to
-// bypass mixed content, as they are not otherwise blocked by Private Network
-// Access.
-
-makeTests({ source: "private", target: "local" });
-
-makeNoBypassTests({ source: "private", target: "private" });
-makeNoBypassTests({ source: "private", target: "public" });
-
-// Source: public secure context.
-//
-// Fetches to the local and private address spaces require the right
-// `targetAddressSpace` option, as well as a successful preflight response
-// carrying a PNA-specific header.
-
-makeTests({ source: "public", target: "local" });
-makeTests({ source: "public", target: "private" });
-
-makeNoBypassTests({ source: "public", target: "public" });
-
-// These tests verify that documents fetched from the `local` address space yet
-// carrying the `treat-as-public-address` CSP directive are treated as if they
-// had been fetched from the `public` address space.
-
-promise_test_parallel(t => fetchTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {
- server: Server.HTTP_LOCAL,
- behavior: {
- preflight: PreflightBehavior.optionalSuccess(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace: "private" },
- expected: FetchTestResult.FAILURE,
-}), 'https-treat-as-public to http-local: wrong targetAddressSpace "private".');
-
-promise_test_parallel(t => fetchTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {
- server: Server.HTTP_LOCAL,
- behavior: {
- preflight: PreflightBehavior.optionalSuccess(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace: "local" },
- expected: FetchTestResult.SUCCESS,
-}), "https-treat-as-public to http-local: success.");
-
-promise_test_parallel(t => fetchTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {
- server: Server.HTTP_PRIVATE,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace: "local" },
- expected: FetchTestResult.FAILURE,
-}), 'https-treat-as-public to http-private: wrong targetAddressSpace "local".');
-
-promise_test_parallel(t => fetchTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {
- server: Server.HTTP_PRIVATE,
- behavior: {
- preflight: PreflightBehavior.success(token()),
- response: ResponseBehavior.allowCrossOrigin(),
- },
- },
- fetchOptions: { targetAddressSpace: "private" },
- expected: FetchTestResult.SUCCESS,
-}), "https-treat-as-public to http-private: success.");
diff --git a/test/fixtures/wpt/fetch/private-network-access/resources/support.sub.js b/test/fixtures/wpt/fetch/private-network-access/resources/support.sub.js
index 7d133b02889..6d0743e0f8f 100644
--- a/test/fixtures/wpt/fetch/private-network-access/resources/support.sub.js
+++ b/test/fixtures/wpt/fetch/private-network-access/resources/support.sub.js
@@ -76,13 +76,13 @@ async function postMessageAndAwaitReply(target, message) {
const SERVER_PORTS = {
"http": {
"local": {{ports[http][0]}},
- "private": {{ports[http-private][0]}},
+ "private": {{ports[http-local][0]}},
"public": {{ports[http-public][0]}},
},
"https": {
"local": {{ports[https][0]}},
"other-local": {{ports[https][1]}},
- "private": {{ports[https-private][0]}},
+ "private": {{ports[https-local][0]}},
"public": {{ports[https-public][0]}},
},
"ws": {
diff --git a/test/fixtures/wpt/fetch/private-network-access/window-open-existing.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/window-open-existing.tentative.https.window.js
deleted file mode 100644
index 6a2a624fc80..00000000000
--- a/test/fixtures/wpt/fetch/private-network-access/window-open-existing.tentative.https.window.js
+++ /dev/null
@@ -1,209 +0,0 @@
-// META: script=/common/subset-tests-by-key.js
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/utils.js
-// META: script=resources/support.sub.js
-// META: timeout=long
-// META: variant=?include=from-local
-// META: variant=?include=from-private
-// META: variant=?include=from-public
-// META: variant=?include=from-treat-as-public
-//
-// These tests verify that secure contexts can navigate to less-public address
-// spaces via window.open to an existing window iff the target server responds
-// affirmatively to preflight requests.
-
-setup(() => {
- assert_true(window.isSecureContext);
-});
-
-// Source: secure local context.
-//
-// All fetches unaffected by Private Network Access.
-
-subsetTestByKey(
- 'from-local', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_LOCAL},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'local to local: no preflight required.');
-
-subsetTestByKey(
- 'from-local', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_PRIVATE},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'local to private: no preflight required.');
-
-subsetTestByKey(
- 'from-local', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_LOCAL},
- target: {server: Server.HTTPS_PUBLIC},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'local to public: no preflight required.');
-
-// Generates tests of preflight behavior for a single (source, target) pair.
-//
-// Scenarios:
-//
-// - preflight response has non-2xx HTTP code
-// - preflight response is missing CORS headers
-// - preflight response is missing the PNA-specific `Access-Control` header
-// - success
-//
-function makePreflightTests({
- key,
- sourceName,
- sourceServer,
- sourceTreatAsPublic,
- targetName,
- targetServer,
-}) {
- const prefix =
- `${sourceName} to ${targetName}: `;
-
- const source = {
- server: sourceServer,
- treatAsPublic: sourceTreatAsPublic,
- };
-
- promise_test_parallel(t => windowOpenExistingTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: { preflight: PreflightBehavior.failure() },
- },
- expected: NavigationTestResult.FAILURE,
- }), prefix + "failed preflight.");
-
- promise_test_parallel(t => windowOpenExistingTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: { preflight: PreflightBehavior.noCorsHeader(token()) },
- },
- expected: NavigationTestResult.FAILURE,
- }), prefix + "missing CORS headers.");
-
- promise_test_parallel(t => windowOpenExistingTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: { preflight: PreflightBehavior.noPnaHeader(token()) },
- },
- expected: NavigationTestResult.FAILURE,
- }), prefix + "missing PNA header.");
-
- promise_test_parallel(t => windowOpenExistingTest(t, {
- source,
- target: {
- server: targetServer,
- behavior: { preflight: PreflightBehavior.navigation(token()) },
- },
- expected: NavigationTestResult.SUCCESS,
- }), prefix + "success.");
-}
-
-// Source: private secure context.
-//
-// Navigating to the local address space require a successful preflight response
-// carrying a PNA-specific header.
-
-subsetTestByKey('from-private', makePreflightTests, {
- sourceServer: Server.HTTPS_PRIVATE,
- sourceName: 'private',
- targetServer: Server.HTTPS_LOCAL,
- targetName: 'local',
-});
-
-subsetTestByKey(
- 'from-private', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {server: Server.HTTPS_PRIVATE},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'private to private: no preflight required.');
-
-subsetTestByKey(
- 'from-private', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_PRIVATE},
- target: {server: Server.HTTPS_PUBLIC},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'private to public: no preflight required.');
-
-// Source: public secure context.
-//
-// Navigating to the local and private address spaces require a successful
-// preflight response carrying a PNA-specific header.
-
-subsetTestByKey('from-public', makePreflightTests, {
- sourceServer: Server.HTTPS_PUBLIC,
- sourceName: "public",
- targetServer: Server.HTTPS_LOCAL,
- targetName: "local",
-});
-
-subsetTestByKey('from-public', makePreflightTests, {
- sourceServer: Server.HTTPS_PUBLIC,
- sourceName: "public",
- targetServer: Server.HTTPS_PRIVATE,
- targetName: "private",
-});
-
-subsetTestByKey(
- 'from-public', promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {server: Server.HTTPS_PUBLIC},
- target: {server: Server.HTTPS_PUBLIC},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'public to public: no preflight required.');
-
-// The following tests verify that `CSP: treat-as-public-address` makes
-// documents behave as if they had been served from a public IP address.
-
-subsetTestByKey('from-treat-as-public', makePreflightTests, {
- sourceServer: Server.HTTPS_LOCAL,
- sourceTreatAsPublic: true,
- sourceName: "treat-as-public-address",
- targetServer: Server.OTHER_HTTPS_LOCAL,
- targetName: "local",
-});
-
-subsetTestByKey("from-treat-as-public", promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {server: Server.HTTPS_LOCAL},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'treat-as-public-address to local (same-origin): no preflight required.');
-
-subsetTestByKey('from-treat-as-public', makePreflightTests, {
- sourceServer: Server.HTTPS_LOCAL,
- sourceTreatAsPublic: true,
- sourceName: 'treat-as-public-address',
- targetServer: Server.HTTPS_PRIVATE,
- targetName: 'private',
-});
-
-subsetTestByKey("from-treat-as-public", promise_test_parallel,
- t => windowOpenExistingTest(t, {
- source: {
- server: Server.HTTPS_LOCAL,
- treatAsPublic: true,
- },
- target: {server: Server.HTTPS_PUBLIC},
- expected: NavigationTestResult.SUCCESS,
- }),
- 'treat-as-public-address to public: no preflight required.');
diff --git a/test/fixtures/wpt/fetch/range/general.any.js b/test/fixtures/wpt/fetch/range/general.any.js
index 64b225a60bd..273e5ec79d1 100644
--- a/test/fixtures/wpt/fetch/range/general.any.js
+++ b/test/fixtures/wpt/fetch/range/general.any.js
@@ -88,10 +88,7 @@ promise_test(async () => {
});
const response = await fetch(stashTakeURL);
-
- assert_regexp_match(await response.json(),
- /.*\bidentity\b.*/,
- `Expect identity accept-encoding if range header is ${JSON.stringify(rangeHeader)}`);
+ assert_equals(await response.json(), 'identity', `Expect identity accept-encoding if range header is ${JSON.stringify(rangeHeader)}`);
}
}, `Fetch with range header will be sent with Accept-Encoding: identity`);
diff --git a/test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.tentative.https.html b/test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.https.html
similarity index 62%
rename from test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.tentative.https.html
rename to test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.https.html
index 428decfc583..62804283075 100644
--- a/test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.tentative.https.html
+++ b/test/fixtures/wpt/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.https.html
@@ -11,13 +11,18 @@
`location.replace(\`${dangling_url}\`)`,
];
- function get_requests(worker, expected) {
- return new Promise(resolve => {
+ function get_requests(test, worker, expected) {
+ return new Promise((resolve, reject) => {
+ let didTimeout = false;
+ test.step_timeout(() => {
+ didTimeout = true;
+ reject("get_requests timed out");
+ }, 1000);
navigator.serviceWorker.addEventListener('message', function onMsg(evt) {
if (evt.data.size >= expected) {
navigator.serviceWorker.removeEventListener('message', onMsg);
resolve(evt.data);
- } else {
+ } else if (!didTimeout) {
worker.postMessage("");
}
});
@@ -40,6 +45,7 @@
});
const dangling_resource = "404?type=text/javascript&\n<"
+ const dangling_resource_expected = "404?type=text/javascript&%3C"
const api_calls = [
[`const xhr = new XMLHttpRequest();
xhr.open("GET", \`${"xhr" + dangling_resource}\`);
@@ -54,22 +60,30 @@
];
- navigator.serviceWorker.register('service-worker.js');
- const iframe = document.createElement('iframe');
- iframe.src = "resources/empty.html";
- document.body.appendChild(iframe);
+ let iframe, registration;
+ promise_test(async t => {
+ iframe = document.createElement('iframe');
+ iframe.src = "resources/empty.html";
+ document.body.appendChild(iframe);
+ await new Promise(resolve => iframe.onload = resolve);
+ registration = await navigator.serviceWorker.register('service-worker.js');
+ if (!iframe.contentWindow.navigator.serviceWorker.controller)
+ await new Promise(resolve => iframe.contentWindow.navigator.serviceWorker.oncontrollerchange = resolve);
+ }, "Setup controlled frame");
+
+ let number_api_calls = 0;
api_calls.forEach(call => {
- promise_test(t => {
- return new Promise(resolve => {
- navigator.serviceWorker.ready.then(t.step_func(registration => {
- iframe.contentWindow.eval(call[0]);
- get_requests(registration.active, 0).then(t.step_func(requests => {
- resolve(assert_true(requests.has(call[1] + dangling_resource)));
- }));
- }));
- });
+ promise_test(async t => {
+ iframe.contentWindow.eval(call[0]);
+ const requests = await get_requests(t, registration.active, number_api_calls + 1);
+ assert_equals(Array.from(requests)[number_api_calls], call[1] + dangling_resource_expected);
+ number_api_calls++;
}, `Does not block ${call[1]}`);
});
+ promise_test(async () => {
+ iframe.remove();
+ registration.unregister();
+ }, "Clean up iframe");
async_test(t => {
let url = new URL(location.origin + "/" + dangling_url);
diff --git a/test/fixtures/wpt/interfaces/CSP.idl b/test/fixtures/wpt/interfaces/CSP.idl
index d4a6377ebb3..cee3015c7ed 100644
--- a/test/fixtures/wpt/interfaces/CSP.idl
+++ b/test/fixtures/wpt/interfaces/CSP.idl
@@ -3,20 +3,18 @@
// (https://github.com/w3c/webref)
// Source: Content Security Policy Level 3 (https://w3c.github.io/webappsec-csp/)
-[Exposed=Window]
-interface CSPViolationReportBody : ReportBody {
- [Default] object toJSON();
- readonly attribute USVString documentURL;
- readonly attribute USVString? referrer;
- readonly attribute USVString? blockedURL;
- readonly attribute DOMString effectiveDirective;
- readonly attribute DOMString originalPolicy;
- readonly attribute USVString? sourceFile;
- readonly attribute DOMString? sample;
- readonly attribute SecurityPolicyViolationEventDisposition disposition;
- readonly attribute unsigned short statusCode;
- readonly attribute unsigned long? lineNumber;
- readonly attribute unsigned long? columnNumber;
+dictionary CSPViolationReportBody : ReportBody {
+ USVString documentURL;
+ USVString? referrer;
+ USVString? blockedURL;
+ DOMString effectiveDirective;
+ DOMString originalPolicy;
+ USVString? sourceFile;
+ DOMString? sample;
+ SecurityPolicyViolationEventDisposition disposition;
+ unsigned short statusCode;
+ unsigned long? lineNumber;
+ unsigned long? columnNumber;
};
enum SecurityPolicyViolationEventDisposition {
diff --git a/test/fixtures/wpt/interfaces/IndexedDB.idl b/test/fixtures/wpt/interfaces/IndexedDB.idl
index d82391da7e6..7c381fe0453 100644
--- a/test/fixtures/wpt/interfaces/IndexedDB.idl
+++ b/test/fixtures/wpt/interfaces/IndexedDB.idl
@@ -108,10 +108,11 @@ interface IDBObjectStore {
[NewObject] IDBRequest clear();
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
- [NewObject] IDBRequest getAll(optional any query,
+ [NewObject] IDBRequest getAll(optional any queryOrOptions,
optional [EnforceRange] unsigned long count);
- [NewObject] IDBRequest getAllKeys(optional any query,
+ [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
optional [EnforceRange] unsigned long count);
+ [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
@@ -132,6 +133,12 @@ dictionary IDBIndexParameters {
boolean multiEntry = false;
};
+dictionary IDBGetAllOptions {
+ any query = null;
+ [EnforceRange] unsigned long count;
+ IDBCursorDirection direction = "next";
+};
+
[Exposed=(Window,Worker)]
interface IDBIndex {
attribute DOMString name;
@@ -142,10 +149,11 @@ interface IDBIndex {
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
- [NewObject] IDBRequest getAll(optional any query,
+ [NewObject] IDBRequest getAll(optional any queryOrOptions,
optional [EnforceRange] unsigned long count);
- [NewObject] IDBRequest getAllKeys(optional any query,
+ [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
optional [EnforceRange] unsigned long count);
+ [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
@@ -173,6 +181,13 @@ interface IDBKeyRange {
boolean includes(any key);
};
+[Exposed=(Window,Worker)]
+interface IDBRecord {
+ readonly attribute any key;
+ readonly attribute any primaryKey;
+ readonly attribute any value;
+};
+
[Exposed=(Window,Worker)]
interface IDBCursor {
readonly attribute (IDBObjectStore or IDBIndex) source;
diff --git a/test/fixtures/wpt/interfaces/cookie-store.idl b/test/fixtures/wpt/interfaces/cookiestore.idl
similarity index 93%
rename from test/fixtures/wpt/interfaces/cookie-store.idl
rename to test/fixtures/wpt/interfaces/cookiestore.idl
index 8a000cac0b2..cbcf0712546 100644
--- a/test/fixtures/wpt/interfaces/cookie-store.idl
+++ b/test/fixtures/wpt/interfaces/cookiestore.idl
@@ -1,7 +1,7 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into webref
// (https://github.com/w3c/webref)
-// Source: Cookie Store API (https://wicg.github.io/cookie-store/)
+// Source: Cookie Store API Standard (https://cookiestore.spec.whatwg.org/)
[Exposed=(ServiceWorker,Window),
SecureContext]
@@ -53,12 +53,6 @@ dictionary CookieStoreDeleteOptions {
dictionary CookieListItem {
USVString name;
USVString value;
- USVString? domain;
- USVString path;
- DOMHighResTimeStamp? expires;
- boolean secure;
- CookieSameSite sameSite;
- boolean partitioned;
};
typedef sequence CookieList;
diff --git a/test/fixtures/wpt/interfaces/csp-next.idl b/test/fixtures/wpt/interfaces/csp-next.idl
index d94b36cf885..f17c4b3a5f2 100644
--- a/test/fixtures/wpt/interfaces/csp-next.idl
+++ b/test/fixtures/wpt/interfaces/csp-next.idl
@@ -10,12 +10,10 @@ enum ScriptingPolicyViolationType {
"eval"
};
-[Exposed=(Window,Worker), SecureContext]
-interface ScriptingPolicyReportBody : ReportBody {
- [Default] object toJSON();
- readonly attribute DOMString violationType;
- readonly attribute USVString? violationURL;
- readonly attribute USVString? violationSample;
- readonly attribute unsigned long lineno;
- readonly attribute unsigned long colno;
+dictionary ScriptingPolicyReportBody : ReportBody {
+ DOMString violationType;
+ USVString? violationURL;
+ USVString? violationSample;
+ unsigned long lineno;
+ unsigned long colno;
};
diff --git a/test/fixtures/wpt/interfaces/css-conditional-5.idl b/test/fixtures/wpt/interfaces/css-conditional-5.idl
index b1919213ebc..1f3f3788109 100644
--- a/test/fixtures/wpt/interfaces/css-conditional-5.idl
+++ b/test/fixtures/wpt/interfaces/css-conditional-5.idl
@@ -5,6 +5,6 @@
[Exposed=Window]
interface CSSContainerRule : CSSConditionRule {
- readonly attribute CSSOMString containerName;
- readonly attribute CSSOMString containerQuery;
+ readonly attribute CSSOMString containerName;
+ readonly attribute CSSOMString containerQuery;
};
diff --git a/test/fixtures/wpt/interfaces/css-highlight-api.idl b/test/fixtures/wpt/interfaces/css-highlight-api.idl
index 61bf6d4caba..8d98b1230f1 100644
--- a/test/fixtures/wpt/interfaces/css-highlight-api.idl
+++ b/test/fixtures/wpt/interfaces/css-highlight-api.idl
@@ -27,7 +27,12 @@ interface HighlightRegistry {
};
partial interface HighlightRegistry {
- sequence highlightsFromPoint(float x, float y, optional HighlightsFromPointOptions options = {});
+ sequence highlightsFromPoint(float x, float y, optional HighlightsFromPointOptions options = {});
+};
+
+dictionary HighlightHitResult {
+ Highlight highlight;
+ sequence ranges;
};
dictionary HighlightsFromPointOptions {
diff --git a/test/fixtures/wpt/interfaces/css-mixins.idl b/test/fixtures/wpt/interfaces/css-mixins.idl
index 86015e7dd0e..12cd64ee5e6 100644
--- a/test/fixtures/wpt/interfaces/css-mixins.idl
+++ b/test/fixtures/wpt/interfaces/css-mixins.idl
@@ -1,7 +1,7 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into webref
// (https://github.com/w3c/webref)
-// Source: CSS Functions and Mixins Module (https://drafts.csswg.org/css-mixins-1/)
+// Source: CSS Custom Functions and Mixins Module Level 1 (https://drafts.csswg.org/css-mixins-1/)
[Exposed=Window]
interface CSSFunctionRule : CSSGroupingRule {
diff --git a/test/fixtures/wpt/interfaces/css-typed-om.idl b/test/fixtures/wpt/interfaces/css-typed-om.idl
index b0f26ea83c7..0eab6bc7542 100644
--- a/test/fixtures/wpt/interfaces/css-typed-om.idl
+++ b/test/fixtures/wpt/interfaces/css-typed-om.idl
@@ -45,7 +45,7 @@ interface CSSUnparsedValue : CSSStyleValue {
iterable;
readonly attribute unsigned long length;
getter CSSUnparsedSegment (unsigned long index);
- setter CSSUnparsedSegment (unsigned long index, CSSUnparsedSegment val);
+ setter undefined (unsigned long index, CSSUnparsedSegment val);
};
typedef (USVString or CSSVariableReferenceValue) CSSUnparsedSegment;
@@ -263,7 +263,7 @@ interface CSSTransformValue : CSSStyleValue {
iterable;
readonly attribute unsigned long length;
getter CSSTransformComponent (unsigned long index);
- setter CSSTransformComponent (unsigned long index, CSSTransformComponent val);
+ setter undefined (unsigned long index, CSSTransformComponent val);
readonly attribute boolean is2D;
DOMMatrix toMatrix();
diff --git a/test/fixtures/wpt/interfaces/cssom-view.idl b/test/fixtures/wpt/interfaces/cssom-view.idl
index 88abb078485..160c27ca050 100644
--- a/test/fixtures/wpt/interfaces/cssom-view.idl
+++ b/test/fixtures/wpt/interfaces/cssom-view.idl
@@ -141,6 +141,7 @@ partial interface Element {
};
partial interface HTMLElement {
+ readonly attribute Element? scrollParent;
readonly attribute Element? offsetParent;
readonly attribute long offsetTop;
readonly attribute long offsetLeft;
diff --git a/test/fixtures/wpt/interfaces/cssom.idl b/test/fixtures/wpt/interfaces/cssom.idl
index 7f9aefdb97e..08c667efdf7 100644
--- a/test/fixtures/wpt/interfaces/cssom.idl
+++ b/test/fixtures/wpt/interfaces/cssom.idl
@@ -172,7 +172,7 @@ interface CSSStyleProperties : CSSStyleDeclaration {
};
interface mixin ElementCSSInlineStyle {
- [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
+ [SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
};
HTMLElement includes ElementCSSInlineStyle;
@@ -182,7 +182,7 @@ SVGElement includes ElementCSSInlineStyle;
MathMLElement includes ElementCSSInlineStyle;
partial interface Window {
- [NewObject] CSSStyleDeclaration getComputedStyle(Element elt, optional CSSOMString? pseudoElt);
+ [NewObject] CSSStyleProperties getComputedStyle(Element elt, optional CSSOMString? pseudoElt);
};
[Exposed=Window]
diff --git a/test/fixtures/wpt/interfaces/deprecation-reporting.idl b/test/fixtures/wpt/interfaces/deprecation-reporting.idl
index 4cf76ba8114..8f6e963918f 100644
--- a/test/fixtures/wpt/interfaces/deprecation-reporting.idl
+++ b/test/fixtures/wpt/interfaces/deprecation-reporting.idl
@@ -3,13 +3,11 @@
// (https://github.com/w3c/webref)
// Source: Deprecation Reporting (https://wicg.github.io/deprecation-reporting/)
-[Exposed=(Window,Worker)]
-interface DeprecationReportBody : ReportBody {
- [Default] object toJSON();
- readonly attribute DOMString id;
- readonly attribute object? anticipatedRemoval;
- readonly attribute DOMString message;
- readonly attribute DOMString? sourceFile;
- readonly attribute unsigned long? lineNumber;
- readonly attribute unsigned long? columnNumber;
+dictionary DeprecationReportBody : ReportBody {
+ DOMString id;
+ object? anticipatedRemoval;
+ DOMString message;
+ DOMString? sourceFile;
+ unsigned long? lineNumber;
+ unsigned long? columnNumber;
};
diff --git a/test/fixtures/wpt/interfaces/digital-credentials.idl b/test/fixtures/wpt/interfaces/digital-credentials.idl
index e4ebb3b3e86..a82414dea1f 100644
--- a/test/fixtures/wpt/interfaces/digital-credentials.idl
+++ b/test/fixtures/wpt/interfaces/digital-credentials.idl
@@ -1,23 +1,38 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into webref
// (https://github.com/w3c/webref)
-// Source: Digital Credentials (https://wicg.github.io/digital-credentials/)
+// Source: Digital Credentials (https://w3c-fedid.github.io/digital-credentials/)
partial dictionary CredentialRequestOptions {
DigitalCredentialRequestOptions digital;
};
dictionary DigitalCredentialRequestOptions {
- sequence requests;
+ required sequence requests;
};
-dictionary DigitalCredentialRequest {
+dictionary DigitalCredentialGetRequest {
+ required DOMString protocol;
+ required object data;
+};
+
+partial dictionary CredentialCreationOptions {
+ DigitalCredentialCreationOptions digital;
+};
+
+dictionary DigitalCredentialCreationOptions {
+ sequence requests;
+};
+
+dictionary DigitalCredentialCreateRequest {
required DOMString protocol;
required object data;
};
[Exposed=Window, SecureContext]
interface DigitalCredential : Credential {
+ [Default] object toJSON();
readonly attribute DOMString protocol;
[SameObject] readonly attribute object data;
+ static boolean userAgentAllowsProtocol(DOMString protocol);
};
diff --git a/test/fixtures/wpt/interfaces/dom.idl b/test/fixtures/wpt/interfaces/dom.idl
index 7b4fcb920e2..955569ad68d 100644
--- a/test/fixtures/wpt/interfaces/dom.idl
+++ b/test/fixtures/wpt/interfaces/dom.idl
@@ -110,6 +110,7 @@ Document includes NonElementParentNode;
DocumentFragment includes NonElementParentNode;
interface mixin DocumentOrShadowRoot {
+ readonly attribute CustomElementRegistry? customElementRegistry;
};
Document includes DocumentOrShadowRoot;
ShadowRoot includes DocumentOrShadowRoot;
@@ -293,7 +294,7 @@ interface Document : Node {
[NewObject] Comment createComment(DOMString data);
[NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
- [CEReactions, NewObject] Node importNode(Node node, optional boolean subtree = false);
+ [CEReactions, NewObject] Node importNode(Node node, optional (boolean or ImportNodeOptions) options = false);
[CEReactions] Node adoptNode(Node node);
[NewObject] Attr createAttribute(DOMString localName);
@@ -312,12 +313,18 @@ interface Document : Node {
interface XMLDocument : Document {};
dictionary ElementCreationOptions {
+ CustomElementRegistry customElementRegistry;
DOMString is;
};
+dictionary ImportNodeOptions {
+ CustomElementRegistry customElementRegistry;
+ boolean selfOnly = false;
+};
+
[Exposed=Window]
interface DOMImplementation {
- [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId);
+ [NewObject] DocumentType createDocumentType(DOMString name, DOMString publicId, DOMString systemId);
[NewObject] XMLDocument createDocument(DOMString? namespace, [LegacyNullToEmptyString] DOMString qualifiedName, optional DocumentType? doctype = null);
[NewObject] Document createHTMLDocument(optional DOMString title);
@@ -344,6 +351,7 @@ interface ShadowRoot : DocumentFragment {
readonly attribute boolean clonable;
readonly attribute boolean serializable;
readonly attribute Element host;
+
attribute EventHandler onslotchange;
};
@@ -384,6 +392,8 @@ interface Element : Node {
ShadowRoot attachShadow(ShadowRootInit init);
readonly attribute ShadowRoot? shadowRoot;
+ readonly attribute CustomElementRegistry? customElementRegistry;
+
Element? closest(DOMString selectors);
boolean matches(DOMString selectors);
boolean webkitMatchesSelector(DOMString selectors); // legacy alias of .matches
@@ -402,6 +412,7 @@ dictionary ShadowRootInit {
SlotAssignmentMode slotAssignment = "named";
boolean clonable = false;
boolean serializable = false;
+ CustomElementRegistry? customElementRegistry = null;
};
[Exposed=Window,
diff --git a/test/fixtures/wpt/interfaces/element-timing.idl b/test/fixtures/wpt/interfaces/element-timing.idl
index ef73ca6c0f6..4b556e82779 100644
--- a/test/fixtures/wpt/interfaces/element-timing.idl
+++ b/test/fixtures/wpt/interfaces/element-timing.idl
@@ -13,12 +13,12 @@ interface PerformanceElementTiming : PerformanceEntry {
readonly attribute unsigned long naturalHeight;
readonly attribute DOMString id;
readonly attribute Element? element;
- readonly attribute DOMString url;
+ readonly attribute USVString url;
[Default] object toJSON();
};
PerformanceElementTiming includes PaintTimingMixin;
partial interface Element {
- [CEReactions] attribute DOMString elementTiming;
+ [CEReactions, Reflect] attribute DOMString elementTiming;
};
diff --git a/test/fixtures/wpt/interfaces/fedcm.idl b/test/fixtures/wpt/interfaces/fedcm.idl
index f7038a6fee1..be3bc1b2bd3 100644
--- a/test/fixtures/wpt/interfaces/fedcm.idl
+++ b/test/fixtures/wpt/interfaces/fedcm.idl
@@ -10,14 +10,27 @@ dictionary IdentityCredentialDisconnectOptions : IdentityProviderConfig {
[Exposed=Window, SecureContext]
interface IdentityCredential : Credential {
static Promise disconnect(IdentityCredentialDisconnectOptions options);
- readonly attribute USVString? token;
+ readonly attribute any token;
readonly attribute boolean isAutoSelected;
+ readonly attribute USVString configURL;
};
dictionary DisconnectedAccount {
required USVString account_id;
};
+dictionary IdentityCredentialErrorInit {
+ DOMString error;
+ USVString url;
+};
+
+[Exposed=Window, SecureContext]
+interface IdentityCredentialError : DOMException {
+ constructor(optional DOMString message = "", optional IdentityCredentialErrorInit options = {});
+ readonly attribute DOMString error;
+ readonly attribute USVString url;
+};
+
partial dictionary CredentialRequestOptions {
IdentityCredentialRequestOptions identity;
};
@@ -46,7 +59,6 @@ dictionary IdentityProviderConfig {
};
dictionary IdentityProviderRequestOptions : IdentityProviderConfig {
- USVString nonce;
DOMString loginHint;
DOMString domainHint;
sequence fields;
@@ -73,30 +85,36 @@ dictionary IdentityProviderBranding {
dictionary IdentityProviderAPIConfig {
required USVString accounts_endpoint;
- required USVString client_metadata_endpoint;
+ USVString client_metadata_endpoint;
required USVString id_assertion_endpoint;
required USVString login_url;
USVString disconnect_endpoint;
IdentityProviderBranding branding;
+ boolean supports_use_other_account = false;
+ USVString account_label;
};
dictionary IdentityProviderAccount {
required USVString id;
- required USVString name;
- required USVString email;
+ USVString name;
+ USVString email;
+ USVString tel;
+ USVString username;
USVString given_name;
USVString picture;
sequence approved_clients;
sequence login_hints;
sequence domain_hints;
+ sequence label_hints;
};
dictionary IdentityProviderAccountList {
sequence accounts;
};
dictionary IdentityAssertionResponse {
- USVString token;
+ any token;
USVString continue_on;
+ IdentityCredentialErrorInit error;
};
dictionary IdentityProviderClientMetadata {
@@ -117,6 +135,6 @@ dictionary IdentityResolveOptions {
[Exposed=Window, SecureContext] interface IdentityProvider {
static undefined close();
- static undefined resolve(DOMString token, optional IdentityResolveOptions options = {});
+ static Promise resolve(any token, optional IdentityResolveOptions options = {});
static Promise> getUserInfo(IdentityProviderConfig config);
};
diff --git a/test/fixtures/wpt/interfaces/fetch.idl b/test/fixtures/wpt/interfaces/fetch.idl
index 965a82d13f5..48149ece73d 100644
--- a/test/fixtures/wpt/interfaces/fetch.idl
+++ b/test/fixtures/wpt/interfaces/fetch.idl
@@ -116,3 +116,16 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredire
partial interface mixin WindowOrWorkerGlobalScope {
[NewObject] Promise fetch(RequestInfo input, optional RequestInit init = {});
};
+
+dictionary DeferredRequestInit : RequestInit {
+ DOMHighResTimeStamp activateAfter;
+};
+
+[Exposed=Window]
+interface FetchLaterResult {
+ readonly attribute boolean activated;
+};
+
+partial interface Window {
+ [NewObject] FetchLaterResult fetchLater(RequestInfo input, optional DeferredRequestInit init = {});
+};
diff --git a/test/fixtures/wpt/interfaces/fs.idl b/test/fixtures/wpt/interfaces/fs.idl
index 46a59dd1acd..156e9726739 100644
--- a/test/fixtures/wpt/interfaces/fs.idl
+++ b/test/fixtures/wpt/interfaces/fs.idl
@@ -42,7 +42,7 @@ dictionary FileSystemRemoveOptions {
[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemDirectoryHandle : FileSystemHandle {
- async iterable;
+ async_iterable;
Promise getFileHandle(USVString name, optional FileSystemGetFileOptions options = {});
Promise getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});
diff --git a/test/fixtures/wpt/interfaces/html.idl b/test/fixtures/wpt/interfaces/html.idl
index 97fabdf80fa..6a6b85335f2 100644
--- a/test/fixtures/wpt/interfaces/html.idl
+++ b/test/fixtures/wpt/interfaces/html.idl
@@ -110,21 +110,21 @@ interface HTMLElement : Element {
[HTMLConstructor] constructor();
// metadata attributes
- [CEReactions] attribute DOMString title;
- [CEReactions] attribute DOMString lang;
+ [CEReactions, Reflect] attribute DOMString title;
+ [CEReactions, Reflect] attribute DOMString lang;
[CEReactions] attribute boolean translate;
[CEReactions] attribute DOMString dir;
// user interaction
[CEReactions] attribute (boolean or unrestricted double or DOMString)? hidden;
- [CEReactions] attribute boolean inert;
+ [CEReactions, Reflect] attribute boolean inert;
undefined click();
- [CEReactions] attribute DOMString accessKey;
+ [CEReactions, Reflect] attribute DOMString accessKey;
readonly attribute DOMString accessKeyLabel;
[CEReactions] attribute boolean draggable;
[CEReactions] attribute boolean spellcheck;
- [CEReactions] attribute DOMString writingSuggestions;
- [CEReactions] attribute DOMString autocapitalize;
+ [CEReactions, ReflectSetter] attribute DOMString writingSuggestions;
+ [CEReactions, ReflectSetter] attribute DOMString autocapitalize;
[CEReactions] attribute boolean autocorrect;
[CEReactions] attribute [LegacyNullToEmptyString] DOMString innerText;
@@ -160,8 +160,8 @@ interface mixin HTMLOrSVGElement {
[SameObject] readonly attribute DOMStringMap dataset;
attribute DOMString nonce; // intentionally no [CEReactions]
- [CEReactions] attribute boolean autofocus;
- [CEReactions] attribute long tabIndex;
+ [CEReactions, Reflect] attribute boolean autofocus;
+ [CEReactions, ReflectSetter] attribute long tabIndex;
undefined focus(optional FocusOptions options = {});
undefined blur();
};
@@ -197,29 +197,29 @@ interface HTMLTitleElement : HTMLElement {
interface HTMLBaseElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString href;
- [CEReactions] attribute DOMString target;
+ [CEReactions, ReflectSetter] attribute USVString href;
+ [CEReactions, Reflect] attribute DOMString target;
};
[Exposed=Window]
interface HTMLLinkElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString href;
+ [CEReactions, ReflectURL] attribute USVString href;
[CEReactions] attribute DOMString? crossOrigin;
- [CEReactions] attribute DOMString rel;
+ [CEReactions, Reflect] attribute DOMString rel;
[CEReactions] attribute DOMString as;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
- [CEReactions] attribute DOMString media;
- [CEReactions] attribute DOMString integrity;
- [CEReactions] attribute DOMString hreflang;
- [CEReactions] attribute DOMString type;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList sizes;
- [CEReactions] attribute USVString imageSrcset;
- [CEReactions] attribute DOMString imageSizes;
+ [SameObject, PutForwards=value, Reflect="rel"] readonly attribute DOMTokenList relList;
+ [CEReactions, Reflect] attribute DOMString media;
+ [CEReactions, Reflect] attribute DOMString integrity;
+ [CEReactions, Reflect] attribute DOMString hreflang;
+ [CEReactions, Reflect] attribute DOMString type;
+ [SameObject, PutForwards=value, Reflect] readonly attribute DOMTokenList sizes;
+ [CEReactions, Reflect] attribute USVString imageSrcset;
+ [CEReactions, Reflect] attribute DOMString imageSizes;
[CEReactions] attribute DOMString referrerPolicy;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking;
- [CEReactions] attribute boolean disabled;
+ [SameObject, PutForwards=value, Reflect] readonly attribute DOMTokenList blocking;
+ [CEReactions, Reflect] attribute boolean disabled;
[CEReactions] attribute DOMString fetchPriority;
// also has obsolete members
@@ -230,10 +230,10 @@ HTMLLinkElement includes LinkStyle;
interface HTMLMetaElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString httpEquiv;
- [CEReactions] attribute DOMString content;
- [CEReactions] attribute DOMString media;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect="http-equiv"] attribute DOMString httpEquiv;
+ [CEReactions, Reflect] attribute DOMString content;
+ [CEReactions, Reflect] attribute DOMString media;
// also has obsolete members
};
@@ -243,8 +243,8 @@ interface HTMLStyleElement : HTMLElement {
[HTMLConstructor] constructor();
attribute boolean disabled;
- [CEReactions] attribute DOMString media;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking;
+ [CEReactions, Reflect] attribute DOMString media;
+ [SameObject, PutForwards=value, Reflect] readonly attribute DOMTokenList blocking;
// also has obsolete members
};
@@ -291,16 +291,16 @@ interface HTMLPreElement : HTMLElement {
interface HTMLQuoteElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString cite;
+ [CEReactions, ReflectURL] attribute USVString cite;
};
[Exposed=Window]
interface HTMLOListElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean reversed;
- [CEReactions] attribute long start;
- [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect] attribute boolean reversed;
+ [CEReactions, Reflect, ReflectDefault=1] attribute long start;
+ [CEReactions, Reflect] attribute DOMString type;
// also has obsolete members
};
@@ -323,7 +323,7 @@ interface HTMLMenuElement : HTMLElement {
interface HTMLLIElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute long value;
+ [CEReactions, Reflect] attribute long value;
// also has obsolete members
};
@@ -346,13 +346,13 @@ interface HTMLDivElement : HTMLElement {
interface HTMLAnchorElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString target;
- [CEReactions] attribute DOMString download;
- [CEReactions] attribute USVString ping;
- [CEReactions] attribute DOMString rel;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
- [CEReactions] attribute DOMString hreflang;
- [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString target;
+ [CEReactions, Reflect] attribute DOMString download;
+ [CEReactions, Reflect] attribute USVString ping;
+ [CEReactions, Reflect] attribute DOMString rel;
+ [SameObject, PutForwards=value, Reflect="rel"] readonly attribute DOMTokenList relList;
+ [CEReactions, Reflect] attribute DOMString hreflang;
+ [CEReactions, Reflect] attribute DOMString type;
[CEReactions] attribute DOMString text;
@@ -366,14 +366,14 @@ HTMLAnchorElement includes HTMLHyperlinkElementUtils;
interface HTMLDataElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString value;
+ [CEReactions, Reflect] attribute DOMString value;
};
[Exposed=Window]
interface HTMLTimeElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString dateTime;
+ [CEReactions, Reflect] attribute DOMString dateTime;
};
[Exposed=Window]
@@ -389,7 +389,7 @@ interface HTMLBRElement : HTMLElement {
};
interface mixin HTMLHyperlinkElementUtils {
- [CEReactions] stringifier attribute USVString href;
+ [CEReactions, ReflectSetter] stringifier attribute USVString href;
readonly attribute USVString origin;
[CEReactions] attribute USVString protocol;
[CEReactions] attribute USVString username;
@@ -406,8 +406,8 @@ interface mixin HTMLHyperlinkElementUtils {
interface HTMLModElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString cite;
- [CEReactions] attribute DOMString dateTime;
+ [CEReactions, ReflectURL] attribute USVString cite;
+ [CEReactions, Reflect] attribute DOMString dateTime;
};
[Exposed=Window]
@@ -419,13 +419,13 @@ interface HTMLPictureElement : HTMLElement {
interface HTMLSourceElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute USVString srcset;
- [CEReactions] attribute DOMString sizes;
- [CEReactions] attribute DOMString media;
- [CEReactions] attribute unsigned long width;
- [CEReactions] attribute unsigned long height;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute DOMString type;
+ [CEReactions, Reflect] attribute USVString srcset;
+ [CEReactions, Reflect] attribute DOMString sizes;
+ [CEReactions, Reflect] attribute DOMString media;
+ [CEReactions, Reflect] attribute unsigned long width;
+ [CEReactions, Reflect] attribute unsigned long height;
};
[Exposed=Window,
@@ -433,15 +433,15 @@ interface HTMLSourceElement : HTMLElement {
interface HTMLImageElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString alt;
- [CEReactions] attribute USVString src;
- [CEReactions] attribute USVString srcset;
- [CEReactions] attribute DOMString sizes;
+ [CEReactions, Reflect] attribute DOMString alt;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute USVString srcset;
+ [CEReactions, Reflect] attribute DOMString sizes;
[CEReactions] attribute DOMString? crossOrigin;
- [CEReactions] attribute DOMString useMap;
- [CEReactions] attribute boolean isMap;
- [CEReactions] attribute unsigned long width;
- [CEReactions] attribute unsigned long height;
+ [CEReactions, Reflect] attribute DOMString useMap;
+ [CEReactions, Reflect] attribute boolean isMap;
+ [CEReactions, ReflectSetter] attribute unsigned long width;
+ [CEReactions, ReflectSetter] attribute unsigned long height;
readonly attribute unsigned long naturalWidth;
readonly attribute unsigned long naturalHeight;
readonly attribute boolean complete;
@@ -460,14 +460,14 @@ interface HTMLImageElement : HTMLElement {
interface HTMLIFrameElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString src;
+ [CEReactions, ReflectURL] attribute USVString src;
[CEReactions] attribute (TrustedHTML or DOMString) srcdoc;
- [CEReactions] attribute DOMString name;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList sandbox;
- [CEReactions] attribute DOMString allow;
- [CEReactions] attribute boolean allowFullscreen;
- [CEReactions] attribute DOMString width;
- [CEReactions] attribute DOMString height;
+ [CEReactions, Reflect] attribute DOMString name;
+ [SameObject, PutForwards=value, Reflect] readonly attribute DOMTokenList sandbox;
+ [CEReactions, Reflect] attribute DOMString allow;
+ [CEReactions, Reflect] attribute boolean allowFullscreen;
+ [CEReactions, Reflect] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString height;
[CEReactions] attribute DOMString referrerPolicy;
[CEReactions] attribute DOMString loading;
readonly attribute Document? contentDocument;
@@ -481,10 +481,10 @@ interface HTMLIFrameElement : HTMLElement {
interface HTMLEmbedElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute DOMString width;
- [CEReactions] attribute DOMString height;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString height;
Document? getSVGDocument();
// also has obsolete members
@@ -494,12 +494,12 @@ interface HTMLEmbedElement : HTMLElement {
interface HTMLObjectElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString data;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute DOMString name;
+ [CEReactions, ReflectURL] attribute USVString data;
+ [CEReactions, Reflect] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString name;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString width;
- [CEReactions] attribute DOMString height;
+ [CEReactions, Reflect] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString height;
readonly attribute Document? contentDocument;
readonly attribute WindowProxy? contentWindow;
Document? getSVGDocument();
@@ -518,12 +518,12 @@ interface HTMLObjectElement : HTMLElement {
interface HTMLVideoElement : HTMLMediaElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute unsigned long width;
- [CEReactions] attribute unsigned long height;
+ [CEReactions, Reflect] attribute unsigned long width;
+ [CEReactions, Reflect] attribute unsigned long height;
readonly attribute unsigned long videoWidth;
readonly attribute unsigned long videoHeight;
- [CEReactions] attribute USVString poster;
- [CEReactions] attribute boolean playsInline;
+ [CEReactions, ReflectURL] attribute USVString poster;
+ [CEReactions, Reflect] attribute boolean playsInline;
};
[Exposed=Window,
@@ -537,10 +537,10 @@ interface HTMLTrackElement : HTMLElement {
[HTMLConstructor] constructor();
[CEReactions] attribute DOMString kind;
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString srclang;
- [CEReactions] attribute DOMString label;
- [CEReactions] attribute boolean default;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute DOMString srclang;
+ [CEReactions, Reflect] attribute DOMString label;
+ [CEReactions, Reflect] attribute boolean default;
const unsigned short NONE = 0;
const unsigned short LOADING = 1;
@@ -561,7 +561,7 @@ interface HTMLMediaElement : HTMLElement {
readonly attribute MediaError? error;
// network state
- [CEReactions] attribute USVString src;
+ [CEReactions, ReflectURL] attribute USVString src;
attribute MediaProvider? srcObject;
readonly attribute USVString currentSrc;
[CEReactions] attribute DOMString? crossOrigin;
@@ -596,16 +596,16 @@ interface HTMLMediaElement : HTMLElement {
readonly attribute TimeRanges played;
readonly attribute TimeRanges seekable;
readonly attribute boolean ended;
- [CEReactions] attribute boolean autoplay;
- [CEReactions] attribute boolean loop;
+ [CEReactions, Reflect] attribute boolean autoplay;
+ [CEReactions, Reflect] attribute boolean loop;
Promise play();
undefined pause();
// controls
- [CEReactions] attribute boolean controls;
+ [CEReactions, Reflect] attribute boolean controls;
attribute double volume;
attribute boolean muted;
- [CEReactions] attribute boolean defaultMuted;
+ [CEReactions, Reflect="muted"] attribute boolean defaultMuted;
// tracks
[SameObject] readonly attribute AudioTrackList audioTracks;
@@ -742,7 +742,7 @@ dictionary TrackEventInit : EventInit {
interface HTMLMapElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString name;
[SameObject] readonly attribute HTMLCollection areas;
};
@@ -750,14 +750,14 @@ interface HTMLMapElement : HTMLElement {
interface HTMLAreaElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString alt;
- [CEReactions] attribute DOMString coords;
- [CEReactions] attribute DOMString shape;
- [CEReactions] attribute DOMString target;
- [CEReactions] attribute DOMString download;
- [CEReactions] attribute USVString ping;
- [CEReactions] attribute DOMString rel;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
+ [CEReactions, Reflect] attribute DOMString alt;
+ [CEReactions, Reflect] attribute DOMString coords;
+ [CEReactions, Reflect] attribute DOMString shape;
+ [CEReactions, Reflect] attribute DOMString target;
+ [CEReactions, Reflect] attribute DOMString download;
+ [CEReactions, Reflect] attribute USVString ping;
+ [CEReactions, Reflect] attribute DOMString rel;
+ [SameObject, PutForwards=value, Reflect="rel"] readonly attribute DOMTokenList relList;
[CEReactions] attribute DOMString referrerPolicy;
// also has obsolete members
@@ -801,7 +801,7 @@ interface HTMLTableCaptionElement : HTMLElement {
interface HTMLTableColElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute unsigned long span;
+ [CEReactions, Reflect, ReflectDefault=1, ReflectRange=(1, 1000)] attribute unsigned long span;
// also has obsolete members
};
@@ -834,13 +834,13 @@ interface HTMLTableRowElement : HTMLElement {
interface HTMLTableCellElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute unsigned long colSpan;
- [CEReactions] attribute unsigned long rowSpan;
- [CEReactions] attribute DOMString headers;
+ [CEReactions, Reflect, ReflectDefault=1, ReflectRange=(1, 1000)] attribute unsigned long colSpan;
+ [CEReactions, Reflect, ReflectDefault=1, ReflectRange=(0, 65534)] attribute unsigned long rowSpan;
+ [CEReactions, Reflect] attribute DOMString headers;
readonly attribute long cellIndex;
[CEReactions] attribute DOMString scope; // only conforming for th elements
- [CEReactions] attribute DOMString abbr; // only conforming for th elements
+ [CEReactions, Reflect] attribute DOMString abbr; // only conforming for th elements
// also has obsolete members
};
@@ -851,17 +851,17 @@ interface HTMLTableCellElement : HTMLElement {
interface HTMLFormElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString acceptCharset;
- [CEReactions] attribute USVString action;
+ [CEReactions, Reflect="accept-charset"] attribute DOMString acceptCharset;
+ [CEReactions, ReflectSetter] attribute USVString action;
[CEReactions] attribute DOMString autocomplete;
[CEReactions] attribute DOMString enctype;
[CEReactions] attribute DOMString encoding;
[CEReactions] attribute DOMString method;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute boolean noValidate;
- [CEReactions] attribute DOMString target;
- [CEReactions] attribute DOMString rel;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute boolean noValidate;
+ [CEReactions, Reflect] attribute DOMString target;
+ [CEReactions, Reflect] attribute DOMString rel;
+ [SameObject, PutForwards=value, Reflect="rel"] readonly attribute DOMTokenList relList;
[SameObject] readonly attribute HTMLFormControlsCollection elements;
readonly attribute unsigned long length;
@@ -880,7 +880,7 @@ interface HTMLLabelElement : HTMLElement {
[HTMLConstructor] constructor();
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString htmlFor;
+ [CEReactions, Reflect="for"] attribute DOMString htmlFor;
readonly attribute HTMLElement? control;
};
@@ -888,44 +888,44 @@ interface HTMLLabelElement : HTMLElement {
interface HTMLInputElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString accept;
- [CEReactions] attribute boolean alpha;
- [CEReactions] attribute DOMString alt;
- [CEReactions] attribute DOMString autocomplete;
- [CEReactions] attribute boolean defaultChecked;
+ [CEReactions, Reflect] attribute DOMString accept;
+ [CEReactions, Reflect] attribute boolean alpha;
+ [CEReactions, Reflect] attribute DOMString alt;
+ [CEReactions, ReflectSetter] attribute DOMString autocomplete;
+ [CEReactions, Reflect="checked"] attribute boolean defaultChecked;
attribute boolean checked;
[CEReactions] attribute DOMString colorSpace;
- [CEReactions] attribute DOMString dirName;
- [CEReactions] attribute boolean disabled;
+ [CEReactions, Reflect] attribute DOMString dirName;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute FileList? files;
- [CEReactions] attribute USVString formAction;
+ [CEReactions, ReflectSetter] attribute USVString formAction;
[CEReactions] attribute DOMString formEnctype;
[CEReactions] attribute DOMString formMethod;
- [CEReactions] attribute boolean formNoValidate;
- [CEReactions] attribute DOMString formTarget;
- [CEReactions] attribute unsigned long height;
+ [CEReactions, Reflect] attribute boolean formNoValidate;
+ [CEReactions, Reflect] attribute DOMString formTarget;
+ [CEReactions, ReflectSetter] attribute unsigned long height;
attribute boolean indeterminate;
readonly attribute HTMLDataListElement? list;
- [CEReactions] attribute DOMString max;
- [CEReactions] attribute long maxLength;
- [CEReactions] attribute DOMString min;
- [CEReactions] attribute long minLength;
- [CEReactions] attribute boolean multiple;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString pattern;
- [CEReactions] attribute DOMString placeholder;
- [CEReactions] attribute boolean readOnly;
- [CEReactions] attribute boolean required;
- [CEReactions] attribute unsigned long size;
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString step;
+ [CEReactions, Reflect] attribute DOMString max;
+ [CEReactions, ReflectNonNegative] attribute long maxLength;
+ [CEReactions, Reflect] attribute DOMString min;
+ [CEReactions, ReflectNonNegative] attribute long minLength;
+ [CEReactions, Reflect] attribute boolean multiple;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString pattern;
+ [CEReactions, Reflect] attribute DOMString placeholder;
+ [CEReactions, Reflect] attribute boolean readOnly;
+ [CEReactions, Reflect] attribute boolean required;
+ [CEReactions, Reflect] attribute unsigned long size;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute DOMString step;
[CEReactions] attribute DOMString type;
- [CEReactions] attribute DOMString defaultValue;
+ [CEReactions, Reflect="value"] attribute DOMString defaultValue;
[CEReactions] attribute [LegacyNullToEmptyString] DOMString value;
attribute object? valueAsDate;
attribute unrestricted double valueAsNumber;
- [CEReactions] attribute unsigned long width;
+ [CEReactions, ReflectSetter] attribute unsigned long width;
undefined stepUp(optional long n = 1);
undefined stepDown(optional long n = 1);
@@ -951,24 +951,24 @@ interface HTMLInputElement : HTMLElement {
// also has obsolete members
};
-HTMLInputElement includes PopoverInvokerElement;
+HTMLInputElement includes PopoverTargetAttributes;
[Exposed=Window]
interface HTMLButtonElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString command;
- [CEReactions] attribute Element? commandForElement;
- [CEReactions] attribute boolean disabled;
+ [CEReactions, ReflectSetter] attribute DOMString command;
+ [CEReactions, Reflect] attribute Element? commandForElement;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute USVString formAction;
+ [CEReactions, ReflectSetter] attribute USVString formAction;
[CEReactions] attribute DOMString formEnctype;
[CEReactions] attribute DOMString formMethod;
- [CEReactions] attribute boolean formNoValidate;
- [CEReactions] attribute DOMString formTarget;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute DOMString value;
+ [CEReactions, Reflect] attribute boolean formNoValidate;
+ [CEReactions, Reflect] attribute DOMString formTarget;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, ReflectSetter] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString value;
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
@@ -979,19 +979,19 @@ interface HTMLButtonElement : HTMLElement {
readonly attribute NodeList labels;
};
-HTMLButtonElement includes PopoverInvokerElement;
+HTMLButtonElement includes PopoverTargetAttributes;
[Exposed=Window]
interface HTMLSelectElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString autocomplete;
- [CEReactions] attribute boolean disabled;
+ [CEReactions, ReflectSetter] attribute DOMString autocomplete;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute boolean multiple;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute boolean required;
- [CEReactions] attribute unsigned long size;
+ [CEReactions, Reflect] attribute boolean multiple;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute boolean required;
+ [CEReactions, Reflect, ReflectDefault=0] attribute unsigned long size;
readonly attribute DOMString type;
@@ -1031,8 +1031,8 @@ interface HTMLDataListElement : HTMLElement {
interface HTMLOptGroupElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean disabled;
- [CEReactions] attribute DOMString label;
+ [CEReactions, Reflect] attribute boolean disabled;
+ [CEReactions, Reflect] attribute DOMString label;
};
[Exposed=Window,
@@ -1040,12 +1040,12 @@ interface HTMLOptGroupElement : HTMLElement {
interface HTMLOptionElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean disabled;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString label;
- [CEReactions] attribute boolean defaultSelected;
+ [CEReactions, ReflectSetter] attribute DOMString label;
+ [CEReactions, Reflect="selected"] attribute boolean defaultSelected;
attribute boolean selected;
- [CEReactions] attribute DOMString value;
+ [CEReactions, ReflectSetter] attribute DOMString value;
[CEReactions] attribute DOMString text;
readonly attribute long index;
@@ -1055,19 +1055,19 @@ interface HTMLOptionElement : HTMLElement {
interface HTMLTextAreaElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString autocomplete;
- [CEReactions] attribute unsigned long cols;
- [CEReactions] attribute DOMString dirName;
- [CEReactions] attribute boolean disabled;
+ [CEReactions, ReflectSetter] attribute DOMString autocomplete;
+ [CEReactions, ReflectPositiveWithFallback, ReflectDefault=20] attribute unsigned long cols;
+ [CEReactions, Reflect] attribute DOMString dirName;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute long maxLength;
- [CEReactions] attribute long minLength;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString placeholder;
- [CEReactions] attribute boolean readOnly;
- [CEReactions] attribute boolean required;
- [CEReactions] attribute unsigned long rows;
- [CEReactions] attribute DOMString wrap;
+ [CEReactions, ReflectNonNegative] attribute long maxLength;
+ [CEReactions, ReflectNonNegative] attribute long minLength;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString placeholder;
+ [CEReactions, Reflect] attribute boolean readOnly;
+ [CEReactions, Reflect] attribute boolean required;
+ [CEReactions, ReflectPositiveWithFallback, ReflectDefault=2] attribute unsigned long rows;
+ [CEReactions, Reflect] attribute DOMString wrap;
readonly attribute DOMString type;
[CEReactions] attribute DOMString defaultValue;
@@ -1096,9 +1096,9 @@ interface HTMLTextAreaElement : HTMLElement {
interface HTMLOutputElement : HTMLElement {
[HTMLConstructor] constructor();
- [SameObject, PutForwards=value] readonly attribute DOMTokenList htmlFor;
+ [SameObject, PutForwards=value, Reflect="for"] readonly attribute DOMTokenList htmlFor;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString name;
readonly attribute DOMString type;
[CEReactions] attribute DOMString defaultValue;
@@ -1118,8 +1118,8 @@ interface HTMLOutputElement : HTMLElement {
interface HTMLProgressElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute double value;
- [CEReactions] attribute double max;
+ [CEReactions, ReflectSetter] attribute double value;
+ [CEReactions, ReflectPositive, ReflectDefault=1.0] attribute double max;
readonly attribute double position;
readonly attribute NodeList labels;
};
@@ -1128,12 +1128,12 @@ interface HTMLProgressElement : HTMLElement {
interface HTMLMeterElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute double value;
- [CEReactions] attribute double min;
- [CEReactions] attribute double max;
- [CEReactions] attribute double low;
- [CEReactions] attribute double high;
- [CEReactions] attribute double optimum;
+ [CEReactions, ReflectSetter] attribute double value;
+ [CEReactions, ReflectSetter] attribute double min;
+ [CEReactions, ReflectSetter] attribute double max;
+ [CEReactions, ReflectSetter] attribute double low;
+ [CEReactions, ReflectSetter] attribute double high;
+ [CEReactions, ReflectSetter] attribute double optimum;
readonly attribute NodeList labels;
};
@@ -1141,9 +1141,9 @@ interface HTMLMeterElement : HTMLElement {
interface HTMLFieldSetElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean disabled;
+ [CEReactions, Reflect] attribute boolean disabled;
readonly attribute HTMLFormElement? form;
- [CEReactions] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString name;
readonly attribute DOMString type;
@@ -1166,6 +1166,11 @@ interface HTMLLegendElement : HTMLElement {
// also has obsolete members
};
+[Exposed=Window]
+interface HTMLSelectedContentElement : HTMLElement {
+ [HTMLConstructor] constructor();
+};
+
enum SelectionMode {
"select",
"start",
@@ -1214,17 +1219,17 @@ dictionary FormDataEventInit : EventInit {
interface HTMLDetailsElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute boolean open;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute boolean open;
};
[Exposed=Window]
interface HTMLDialogElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean open;
+ [CEReactions, Reflect] attribute boolean open;
attribute DOMString returnValue;
- [CEReactions] attribute DOMString closedBy;
+ [CEReactions, ReflectSetter] attribute DOMString closedBy;
[CEReactions] undefined show();
[CEReactions] undefined showModal();
[CEReactions] undefined close(optional DOMString returnValue);
@@ -1235,18 +1240,19 @@ interface HTMLDialogElement : HTMLElement {
interface HTMLScriptElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute boolean noModule;
+ [CEReactions, Reflect] attribute DOMString type;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute boolean noModule;
[CEReactions] attribute boolean async;
- [CEReactions] attribute boolean defer;
+ [CEReactions, Reflect] attribute boolean defer;
+ [SameObject, PutForwards=value, Reflect] readonly attribute DOMTokenList blocking;
[CEReactions] attribute DOMString? crossOrigin;
- [CEReactions] attribute DOMString text;
- [CEReactions] attribute DOMString integrity;
[CEReactions] attribute DOMString referrerPolicy;
- [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking;
+ [CEReactions, Reflect] attribute DOMString integrity;
[CEReactions] attribute DOMString fetchPriority;
+ [CEReactions] attribute DOMString text;
+
static boolean supports(DOMString type);
// also has obsolete members
@@ -1258,16 +1264,17 @@ interface HTMLTemplateElement : HTMLElement {
readonly attribute DocumentFragment content;
[CEReactions] attribute DOMString shadowRootMode;
- [CEReactions] attribute boolean shadowRootDelegatesFocus;
- [CEReactions] attribute boolean shadowRootClonable;
- [CEReactions] attribute boolean shadowRootSerializable;
+ [CEReactions, Reflect] attribute boolean shadowRootDelegatesFocus;
+ [CEReactions, Reflect] attribute boolean shadowRootClonable;
+ [CEReactions, Reflect] attribute boolean shadowRootSerializable;
+ [CEReactions, Reflect] attribute DOMString shadowRootCustomElementRegistry;
};
[Exposed=Window]
interface HTMLSlotElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString name;
sequence assignedNodes(optional AssignedNodesOptions options = {});
sequence assignedElements(optional AssignedNodesOptions options = {});
undefined assign((Element or Text)... nodes);
@@ -1541,22 +1548,6 @@ interface TextMetrics {
readonly attribute double ideographicBaseline;
};
-dictionary ImageDataSettings {
- PredefinedColorSpace colorSpace;
-};
-
-[Exposed=(Window,Worker),
- Serializable]
-interface ImageData {
- constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {});
- constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {});
-
- readonly attribute unsigned long width;
- readonly attribute unsigned long height;
- readonly attribute Uint8ClampedArray data;
- readonly attribute PredefinedColorSpace colorSpace;
-};
-
[Exposed=(Window,Worker)]
interface Path2D {
constructor(optional (Path2D or DOMString) path);
@@ -1623,11 +1614,14 @@ OffscreenCanvasRenderingContext2D includes CanvasPath;
[Exposed=Window]
interface CustomElementRegistry {
+ constructor();
+
[CEReactions] undefined define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {});
(CustomElementConstructor or undefined) get(DOMString name);
DOMString? getName(CustomElementConstructor constructor);
Promise whenDefined(DOMString name);
[CEReactions] undefined upgrade(Node root);
+ undefined initialize(Node root);
};
callback CustomElementConstructor = HTMLElement ();
@@ -1706,6 +1700,7 @@ interface ToggleEvent : Event {
constructor(DOMString type, optional ToggleEventInit eventInitDict = {});
readonly attribute DOMString oldState;
readonly attribute DOMString newState;
+ readonly attribute Element? source;
};
dictionary ToggleEventInit : EventInit {
@@ -1803,8 +1798,8 @@ dictionary DragEventInit : MouseEventInit {
DataTransfer? dataTransfer = null;
};
-interface mixin PopoverInvokerElement {
- [CEReactions] attribute Element? popoverTargetElement;
+interface mixin PopoverTargetAttributes {
+ [CEReactions, Reflect] attribute Element? popoverTargetElement;
[CEReactions] attribute DOMString popoverTargetAction;
};
@@ -2466,6 +2461,28 @@ interface MimeType {
readonly attribute Plugin enabledPlugin;
};
+typedef (Uint8ClampedArray or Float16Array) ImageDataArray;
+
+enum ImageDataPixelFormat { "rgba-unorm8", "rgba-float16" };
+
+dictionary ImageDataSettings {
+ PredefinedColorSpace colorSpace;
+ ImageDataPixelFormat pixelFormat = "rgba-unorm8";
+};
+
+[Exposed=(Window,Worker),
+ Serializable]
+interface ImageData {
+ constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings = {});
+ constructor(ImageDataArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings = {});
+
+ readonly attribute unsigned long width;
+ readonly attribute unsigned long height;
+ readonly attribute ImageDataArray data;
+ readonly attribute ImageDataPixelFormat pixelFormat;
+ readonly attribute PredefinedColorSpace colorSpace;
+};
+
[Exposed=(Window,Worker), Serializable, Transferable]
interface ImageBitmap {
readonly attribute unsigned long width;
@@ -2639,9 +2656,9 @@ interface Worker : EventTarget {
};
dictionary WorkerOptions {
+ DOMString name = "";
WorkerType type = "classic";
RequestCredentials credentials = "same-origin"; // credentials is only used if type is "module"
- DOMString name = "";
};
enum WorkerType { "classic", "module" };
@@ -2738,17 +2755,17 @@ dictionary StorageEventInit : EventInit {
interface HTMLMarqueeElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString behavior;
- [CEReactions] attribute DOMString bgColor;
- [CEReactions] attribute DOMString direction;
- [CEReactions] attribute DOMString height;
- [CEReactions] attribute unsigned long hspace;
+ [CEReactions, Reflect] attribute DOMString behavior;
+ [CEReactions, Reflect] attribute DOMString bgColor;
+ [CEReactions, Reflect] attribute DOMString direction;
+ [CEReactions, Reflect] attribute DOMString height;
+ [CEReactions, Reflect] attribute unsigned long hspace;
[CEReactions] attribute long loop;
- [CEReactions] attribute unsigned long scrollAmount;
- [CEReactions] attribute unsigned long scrollDelay;
- [CEReactions] attribute boolean trueSpeed;
- [CEReactions] attribute unsigned long vspace;
- [CEReactions] attribute DOMString width;
+ [CEReactions, Reflect, ReflectDefault=6] attribute unsigned long scrollAmount;
+ [CEReactions, Reflect, ReflectDefault=85] attribute unsigned long scrollDelay;
+ [CEReactions, Reflect] attribute boolean trueSpeed;
+ [CEReactions, Reflect] attribute unsigned long vspace;
+ [CEReactions, Reflect] attribute DOMString width;
undefined start();
undefined stop();
@@ -2758,8 +2775,8 @@ interface HTMLMarqueeElement : HTMLElement {
interface HTMLFrameSetElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString cols;
- [CEReactions] attribute DOMString rows;
+ [CEReactions, Reflect] attribute DOMString cols;
+ [CEReactions, Reflect] attribute DOMString rows;
};
HTMLFrameSetElement includes WindowEventHandlers;
@@ -2767,242 +2784,242 @@ HTMLFrameSetElement includes WindowEventHandlers;
interface HTMLFrameElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString scrolling;
- [CEReactions] attribute USVString src;
- [CEReactions] attribute DOMString frameBorder;
- [CEReactions] attribute USVString longDesc;
- [CEReactions] attribute boolean noResize;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString scrolling;
+ [CEReactions, ReflectURL] attribute USVString src;
+ [CEReactions, Reflect] attribute DOMString frameBorder;
+ [CEReactions, ReflectURL] attribute USVString longDesc;
+ [CEReactions, Reflect] attribute boolean noResize;
readonly attribute Document? contentDocument;
readonly attribute WindowProxy? contentWindow;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString marginHeight;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString marginWidth;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString marginHeight;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString marginWidth;
};
partial interface HTMLAnchorElement {
- [CEReactions] attribute DOMString coords;
- [CEReactions] attribute DOMString charset;
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString rev;
- [CEReactions] attribute DOMString shape;
+ [CEReactions, Reflect] attribute DOMString coords;
+ [CEReactions, Reflect] attribute DOMString charset;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString rev;
+ [CEReactions, Reflect] attribute DOMString shape;
};
partial interface HTMLAreaElement {
- [CEReactions] attribute boolean noHref;
+ [CEReactions, Reflect] attribute boolean noHref;
};
partial interface HTMLBodyElement {
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString text;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString link;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString vLink;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString aLink;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString bgColor;
- [CEReactions] attribute DOMString background;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString text;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString link;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString vLink;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString aLink;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString bgColor;
+ [CEReactions, Reflect] attribute DOMString background;
};
partial interface HTMLBRElement {
- [CEReactions] attribute DOMString clear;
+ [CEReactions, Reflect] attribute DOMString clear;
};
partial interface HTMLTableCaptionElement {
- [CEReactions] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString align;
};
partial interface HTMLTableColElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString ch;
- [CEReactions] attribute DOMString chOff;
- [CEReactions] attribute DOMString vAlign;
- [CEReactions] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect="char"] attribute DOMString ch;
+ [CEReactions, Reflect="charoff"] attribute DOMString chOff;
+ [CEReactions, Reflect] attribute DOMString vAlign;
+ [CEReactions, Reflect] attribute DOMString width;
};
[Exposed=Window]
interface HTMLDirectoryElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute boolean compact;
+ [CEReactions, Reflect] attribute boolean compact;
};
partial interface HTMLDivElement {
- [CEReactions] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString align;
};
partial interface HTMLDListElement {
- [CEReactions] attribute boolean compact;
+ [CEReactions, Reflect] attribute boolean compact;
};
partial interface HTMLEmbedElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString name;
};
[Exposed=Window]
interface HTMLFontElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString color;
- [CEReactions] attribute DOMString face;
- [CEReactions] attribute DOMString size;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString color;
+ [CEReactions, Reflect] attribute DOMString face;
+ [CEReactions, Reflect] attribute DOMString size;
};
partial interface HTMLHeadingElement {
- [CEReactions] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString align;
};
partial interface HTMLHRElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString color;
- [CEReactions] attribute boolean noShade;
- [CEReactions] attribute DOMString size;
- [CEReactions] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString color;
+ [CEReactions, Reflect] attribute boolean noShade;
+ [CEReactions, Reflect] attribute DOMString size;
+ [CEReactions, Reflect] attribute DOMString width;
};
partial interface HTMLHtmlElement {
- [CEReactions] attribute DOMString version;
+ [CEReactions, Reflect] attribute DOMString version;
};
partial interface HTMLIFrameElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString scrolling;
- [CEReactions] attribute DOMString frameBorder;
- [CEReactions] attribute USVString longDesc;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString scrolling;
+ [CEReactions, Reflect] attribute DOMString frameBorder;
+ [CEReactions, ReflectURL] attribute USVString longDesc;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString marginHeight;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString marginWidth;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString marginHeight;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString marginWidth;
};
partial interface HTMLImageElement {
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute USVString lowsrc;
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute unsigned long hspace;
- [CEReactions] attribute unsigned long vspace;
- [CEReactions] attribute USVString longDesc;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, ReflectURL] attribute USVString lowsrc;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute unsigned long hspace;
+ [CEReactions, Reflect] attribute unsigned long vspace;
+ [CEReactions, ReflectURL] attribute USVString longDesc;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString border;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString border;
};
partial interface HTMLInputElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString useMap;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString useMap;
};
partial interface HTMLLegendElement {
- [CEReactions] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString align;
};
partial interface HTMLLIElement {
- [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString type;
};
partial interface HTMLLinkElement {
- [CEReactions] attribute DOMString charset;
- [CEReactions] attribute DOMString rev;
- [CEReactions] attribute DOMString target;
+ [CEReactions, Reflect] attribute DOMString charset;
+ [CEReactions, Reflect] attribute DOMString rev;
+ [CEReactions, Reflect] attribute DOMString target;
};
partial interface HTMLMenuElement {
- [CEReactions] attribute boolean compact;
+ [CEReactions, Reflect] attribute boolean compact;
};
partial interface HTMLMetaElement {
- [CEReactions] attribute DOMString scheme;
+ [CEReactions, Reflect] attribute DOMString scheme;
};
partial interface HTMLObjectElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString archive;
- [CEReactions] attribute DOMString code;
- [CEReactions] attribute boolean declare;
- [CEReactions] attribute unsigned long hspace;
- [CEReactions] attribute DOMString standby;
- [CEReactions] attribute unsigned long vspace;
- [CEReactions] attribute DOMString codeBase;
- [CEReactions] attribute DOMString codeType;
- [CEReactions] attribute DOMString useMap;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString archive;
+ [CEReactions, Reflect] attribute DOMString code;
+ [CEReactions, Reflect] attribute boolean declare;
+ [CEReactions, Reflect] attribute unsigned long hspace;
+ [CEReactions, Reflect] attribute DOMString standby;
+ [CEReactions, Reflect] attribute unsigned long vspace;
+ [CEReactions, ReflectURL] attribute DOMString codeBase;
+ [CEReactions, Reflect] attribute DOMString codeType;
+ [CEReactions, Reflect] attribute DOMString useMap;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString border;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString border;
};
partial interface HTMLOListElement {
- [CEReactions] attribute boolean compact;
+ [CEReactions, Reflect] attribute boolean compact;
};
partial interface HTMLParagraphElement {
- [CEReactions] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString align;
};
[Exposed=Window]
interface HTMLParamElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions] attribute DOMString name;
- [CEReactions] attribute DOMString value;
- [CEReactions] attribute DOMString type;
- [CEReactions] attribute DOMString valueType;
+ [CEReactions, Reflect] attribute DOMString name;
+ [CEReactions, Reflect] attribute DOMString value;
+ [CEReactions, Reflect] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString valueType;
};
partial interface HTMLPreElement {
- [CEReactions] attribute long width;
+ [CEReactions, Reflect] attribute long width;
};
partial interface HTMLStyleElement {
- [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect] attribute DOMString type;
};
partial interface HTMLScriptElement {
- [CEReactions] attribute DOMString charset;
- [CEReactions] attribute DOMString event;
- [CEReactions] attribute DOMString htmlFor;
+ [CEReactions, Reflect] attribute DOMString charset;
+ [CEReactions, Reflect] attribute DOMString event;
+ [CEReactions, Reflect="for"] attribute DOMString htmlFor;
};
partial interface HTMLTableElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString border;
- [CEReactions] attribute DOMString frame;
- [CEReactions] attribute DOMString rules;
- [CEReactions] attribute DOMString summary;
- [CEReactions] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString border;
+ [CEReactions, Reflect] attribute DOMString frame;
+ [CEReactions, Reflect] attribute DOMString rules;
+ [CEReactions, Reflect] attribute DOMString summary;
+ [CEReactions, Reflect] attribute DOMString width;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString bgColor;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString cellPadding;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString cellSpacing;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString bgColor;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString cellPadding;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString cellSpacing;
};
partial interface HTMLTableSectionElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString ch;
- [CEReactions] attribute DOMString chOff;
- [CEReactions] attribute DOMString vAlign;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect="char"] attribute DOMString ch;
+ [CEReactions, Reflect="charoff"] attribute DOMString chOff;
+ [CEReactions, Reflect] attribute DOMString vAlign;
};
partial interface HTMLTableCellElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString axis;
- [CEReactions] attribute DOMString height;
- [CEReactions] attribute DOMString width;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect] attribute DOMString axis;
+ [CEReactions, Reflect] attribute DOMString height;
+ [CEReactions, Reflect] attribute DOMString width;
- [CEReactions] attribute DOMString ch;
- [CEReactions] attribute DOMString chOff;
- [CEReactions] attribute boolean noWrap;
- [CEReactions] attribute DOMString vAlign;
+ [CEReactions, Reflect="char"] attribute DOMString ch;
+ [CEReactions, Reflect="charoff"] attribute DOMString chOff;
+ [CEReactions, Reflect] attribute boolean noWrap;
+ [CEReactions, Reflect] attribute DOMString vAlign;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString bgColor;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString bgColor;
};
partial interface HTMLTableRowElement {
- [CEReactions] attribute DOMString align;
- [CEReactions] attribute DOMString ch;
- [CEReactions] attribute DOMString chOff;
- [CEReactions] attribute DOMString vAlign;
+ [CEReactions, Reflect] attribute DOMString align;
+ [CEReactions, Reflect="char"] attribute DOMString ch;
+ [CEReactions, Reflect="charoff"] attribute DOMString chOff;
+ [CEReactions, Reflect] attribute DOMString vAlign;
- [CEReactions] attribute [LegacyNullToEmptyString] DOMString bgColor;
+ [CEReactions, Reflect] attribute [LegacyNullToEmptyString] DOMString bgColor;
};
partial interface HTMLUListElement {
- [CEReactions] attribute boolean compact;
- [CEReactions] attribute DOMString type;
+ [CEReactions, Reflect] attribute boolean compact;
+ [CEReactions, Reflect] attribute DOMString type;
};
partial interface Document {
diff --git a/test/fixtures/wpt/interfaces/image-capture.idl b/test/fixtures/wpt/interfaces/image-capture.idl
index 21e03d4db82..26cc7fab5cd 100644
--- a/test/fixtures/wpt/interfaces/image-capture.idl
+++ b/test/fixtures/wpt/interfaces/image-capture.idl
@@ -3,7 +3,7 @@
// (https://github.com/w3c/webref)
// Source: MediaStream Image Capture (https://w3c.github.io/mediacapture-image/)
-[Exposed=Window]
+[Exposed=Window, SecureContext]
interface ImageCapture {
constructor(MediaStreamTrack videoTrack);
Promise takePhoto(optional PhotoSettings photoSettings = {});
diff --git a/test/fixtures/wpt/interfaces/interest-invokers.tentative.idl b/test/fixtures/wpt/interfaces/interest-invokers.tentative.idl
index fe164e23575..53838c1f802 100644
--- a/test/fixtures/wpt/interfaces/interest-invokers.tentative.idl
+++ b/test/fixtures/wpt/interfaces/interest-invokers.tentative.idl
@@ -1,5 +1,5 @@
interface mixin InterestInvokerElement {
- [CEReactions,Reflect=interesttarget] attribute Element? interestTargetElement;
+ [CEReactions,Reflect=interestfor] attribute Element? interestForElement;
};
HTMLAnchorElement includes InterestInvokerElement;
diff --git a/test/fixtures/wpt/interfaces/intervention-reporting.idl b/test/fixtures/wpt/interfaces/intervention-reporting.idl
index 3c3b8001e74..e1fabd8bf24 100644
--- a/test/fixtures/wpt/interfaces/intervention-reporting.idl
+++ b/test/fixtures/wpt/interfaces/intervention-reporting.idl
@@ -3,12 +3,10 @@
// (https://github.com/w3c/webref)
// Source: Intervention Reporting (https://wicg.github.io/intervention-reporting/)
-[Exposed=(Window,Worker)]
-interface InterventionReportBody : ReportBody {
- [Default] object toJSON();
- readonly attribute DOMString id;
- readonly attribute DOMString message;
- readonly attribute DOMString? sourceFile;
- readonly attribute unsigned long? lineNumber;
- readonly attribute unsigned long? columnNumber;
+dictionary InterventionReportBody : ReportBody {
+ DOMString id;
+ DOMString message;
+ DOMString? sourceFile;
+ unsigned long? lineNumber;
+ unsigned long? columnNumber;
};
diff --git a/test/fixtures/wpt/interfaces/largest-contentful-paint.idl b/test/fixtures/wpt/interfaces/largest-contentful-paint.idl
index 872ba552b0d..4eb5c7fa475 100644
--- a/test/fixtures/wpt/interfaces/largest-contentful-paint.idl
+++ b/test/fixtures/wpt/interfaces/largest-contentful-paint.idl
@@ -5,11 +5,13 @@
[Exposed=Window]
interface LargestContentfulPaint : PerformanceEntry {
- readonly attribute DOMHighResTimeStamp renderTime;
readonly attribute DOMHighResTimeStamp loadTime;
+ readonly attribute DOMHighResTimeStamp renderTime;
readonly attribute unsigned long size;
readonly attribute DOMString id;
readonly attribute DOMString url;
readonly attribute Element? element;
[Default] object toJSON();
};
+
+LargestContentfulPaint includes PaintTimingMixin;
diff --git a/test/fixtures/wpt/interfaces/media-capabilities.idl b/test/fixtures/wpt/interfaces/media-capabilities.idl
index 68ab0a8d0d1..3ded93519b1 100644
--- a/test/fixtures/wpt/interfaces/media-capabilities.idl
+++ b/test/fixtures/wpt/interfaces/media-capabilities.idl
@@ -91,11 +91,11 @@ dictionary MediaCapabilitiesInfo {
dictionary MediaCapabilitiesDecodingInfo : MediaCapabilitiesInfo {
required MediaKeySystemAccess? keySystemAccess;
- MediaDecodingConfiguration configuration;
+ required MediaDecodingConfiguration configuration;
};
dictionary MediaCapabilitiesEncodingInfo : MediaCapabilitiesInfo {
- MediaEncodingConfiguration configuration;
+ required MediaEncodingConfiguration configuration;
};
[Exposed=Window]
diff --git a/test/fixtures/wpt/interfaces/mediacapture-streams.idl b/test/fixtures/wpt/interfaces/mediacapture-streams.idl
index f6c8e2b82da..6000b0f2ae3 100644
--- a/test/fixtures/wpt/interfaces/mediacapture-streams.idl
+++ b/test/fixtures/wpt/interfaces/mediacapture-streams.idl
@@ -73,7 +73,7 @@ dictionary MediaTrackCapabilities {
sequence resizeMode;
ULongRange sampleRate;
ULongRange sampleSize;
- sequence echoCancellation;
+ sequence<(boolean or DOMString)> echoCancellation;
sequence autoGainControl;
sequence noiseSuppression;
DoubleRange latency;
@@ -96,7 +96,7 @@ dictionary MediaTrackConstraintSet {
ConstrainDOMString resizeMode;
ConstrainULong sampleRate;
ConstrainULong sampleSize;
- ConstrainBoolean echoCancellation;
+ ConstrainBooleanOrDOMString echoCancellation;
ConstrainBoolean autoGainControl;
ConstrainBoolean noiseSuppression;
ConstrainDouble latency;
@@ -115,7 +115,7 @@ dictionary MediaTrackSettings {
DOMString resizeMode;
unsigned long sampleRate;
unsigned long sampleSize;
- boolean echoCancellation;
+ (boolean or DOMString) echoCancellation;
boolean autoGainControl;
boolean noiseSuppression;
double latency;
@@ -137,6 +137,11 @@ enum VideoResizeModeEnum {
"crop-and-scale"
};
+enum EchoCancellationModeEnum {
+ "all",
+ "remote-only"
+};
+
[Exposed=Window]
interface MediaStreamTrackEvent : Event {
constructor(DOMString type, MediaStreamTrackEventInit eventInitDict);
@@ -234,6 +239,11 @@ dictionary ConstrainDOMStringParameters {
(DOMString or sequence) ideal;
};
+dictionary ConstrainBooleanOrDOMStringParameters {
+ (boolean or DOMString) exact;
+ (boolean or DOMString) ideal;
+};
+
typedef ([Clamp] unsigned long or ConstrainULongRange) ConstrainULong;
typedef (double or ConstrainDoubleRange) ConstrainDouble;
@@ -244,6 +254,8 @@ typedef (DOMString or
sequence or
ConstrainDOMStringParameters) ConstrainDOMString;
+typedef (boolean or DOMString or ConstrainBooleanOrDOMStringParameters) ConstrainBooleanOrDOMString;
+
dictionary CameraDevicePermissionDescriptor : PermissionDescriptor {
boolean panTiltZoom = false;
};
diff --git a/test/fixtures/wpt/interfaces/mediaqueries-5.idl b/test/fixtures/wpt/interfaces/mediaqueries-5.idl
index 52154c96725..c951c356ca3 100644
--- a/test/fixtures/wpt/interfaces/mediaqueries-5.idl
+++ b/test/fixtures/wpt/interfaces/mediaqueries-5.idl
@@ -3,6 +3,14 @@
// (https://github.com/w3c/webref)
// Source: Media Queries Level 5 (https://drafts.csswg.org/mediaqueries-5/)
+typedef (MediaList or boolean) CustomMediaQuery;
+
+[Exposed=Window]
+interface CSSCustomMediaRule : CSSRule {
+ readonly attribute CSSOMString name;
+ readonly attribute CustomMediaQuery query;
+};
+
[Exposed=Window, SecureContext]
partial interface Navigator {
[SameObject] readonly attribute PreferenceManager preferences;
diff --git a/test/fixtures/wpt/interfaces/mediastream-recording.idl b/test/fixtures/wpt/interfaces/mediastream-recording.idl
index 496bfcf2e27..68c891cdc91 100644
--- a/test/fixtures/wpt/interfaces/mediastream-recording.idl
+++ b/test/fixtures/wpt/interfaces/mediastream-recording.idl
@@ -56,7 +56,7 @@ interface BlobEvent : Event {
readonly attribute DOMHighResTimeStamp timecode;
};
-dictionary BlobEventInit {
+dictionary BlobEventInit : EventInit {
required Blob data;
DOMHighResTimeStamp timecode;
};
diff --git a/test/fixtures/wpt/interfaces/notifications.idl b/test/fixtures/wpt/interfaces/notifications.idl
index 4300b171071..eeb26424bce 100644
--- a/test/fixtures/wpt/interfaces/notifications.idl
+++ b/test/fixtures/wpt/interfaces/notifications.idl
@@ -21,6 +21,7 @@ interface Notification : EventTarget {
readonly attribute NotificationDirection dir;
readonly attribute DOMString lang;
readonly attribute DOMString body;
+ readonly attribute USVString navigate;
readonly attribute DOMString tag;
readonly attribute USVString image;
readonly attribute USVString icon;
@@ -40,6 +41,7 @@ dictionary NotificationOptions {
NotificationDirection dir = "auto";
DOMString lang = "";
DOMString body = "";
+ USVString navigate;
DOMString tag = "";
USVString image;
USVString icon;
@@ -68,6 +70,7 @@ enum NotificationDirection {
dictionary NotificationAction {
required DOMString action;
required DOMString title;
+ USVString navigate;
USVString icon;
};
diff --git a/test/fixtures/wpt/interfaces/origin.tentative.idl b/test/fixtures/wpt/interfaces/origin.tentative.idl
new file mode 100644
index 00000000000..c2f91171339
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/origin.tentative.idl
@@ -0,0 +1,16 @@
+// https://github.com/mikewest/origin-api/
+[Exposed=*]
+interface Origin {
+ constructor();
+ constructor(USVString serializedOrigin);
+
+ static Origin? parse(USVString serializedOrigin);
+ static Origin? fromURL(USVString serializedURL);
+
+ stringifier USVString toJSON();
+
+ readonly attribute boolean opaque;
+
+ boolean isSameOrigin(Origin other);
+ boolean isSameSite(Origin other);
+};
diff --git a/test/fixtures/wpt/interfaces/paint-timing.idl b/test/fixtures/wpt/interfaces/paint-timing.idl
index fbf91858571..bc2b60f9de6 100644
--- a/test/fixtures/wpt/interfaces/paint-timing.idl
+++ b/test/fixtures/wpt/interfaces/paint-timing.idl
@@ -10,5 +10,7 @@ interface mixin PaintTimingMixin {
};
[Exposed=Window]
-interface PerformancePaintTiming : PerformanceEntry {};
+interface PerformancePaintTiming : PerformanceEntry {
+ [Default] object toJSON();
+};
PerformancePaintTiming includes PaintTimingMixin;
diff --git a/test/fixtures/wpt/interfaces/permissions-policy.idl b/test/fixtures/wpt/interfaces/permissions-policy.idl
index b17304de8d0..46eb6914a34 100644
--- a/test/fixtures/wpt/interfaces/permissions-policy.idl
+++ b/test/fixtures/wpt/interfaces/permissions-policy.idl
@@ -19,14 +19,12 @@ partial interface HTMLIFrameElement {
[SameObject] readonly attribute PermissionsPolicy permissionsPolicy;
};
-[Exposed=Window]
-interface PermissionsPolicyViolationReportBody : ReportBody {
- [Default] object toJSON();
- readonly attribute DOMString featureId;
- readonly attribute DOMString? sourceFile;
- readonly attribute long? lineNumber;
- readonly attribute long? columnNumber;
- readonly attribute DOMString disposition;
- readonly attribute DOMString? allowAttribute;
- readonly attribute DOMString? srcAttribute;
+dictionary PermissionsPolicyViolationReportBody : ReportBody {
+ DOMString featureId;
+ DOMString? sourceFile;
+ long? lineNumber;
+ long? columnNumber;
+ DOMString disposition;
+ DOMString? allowAttribute;
+ DOMString? srcAttribute;
};
diff --git a/test/fixtures/wpt/interfaces/pointer-animations.idl b/test/fixtures/wpt/interfaces/pointer-animations.idl
new file mode 100644
index 00000000000..e1b03197514
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/pointer-animations.idl
@@ -0,0 +1,23 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Pointer-driven Animations (https://drafts.csswg.org/pointer-animations-1/)
+
+enum PointerAxis {
+ "block",
+ "inline",
+ "x",
+ "y"
+};
+
+dictionary PointerTimelineOptions {
+ Element? source;
+ PointerAxis axis = "block";
+};
+
+[Exposed=Window]
+interface PointerTimeline : AnimationTimeline {
+ constructor(optional PointerTimelineOptions options = {});
+ readonly attribute Element? source;
+ readonly attribute PointerAxis axis;
+};
diff --git a/test/fixtures/wpt/interfaces/ppa.idl b/test/fixtures/wpt/interfaces/ppa.idl
deleted file mode 100644
index ef3eb360bdf..00000000000
--- a/test/fixtures/wpt/interfaces/ppa.idl
+++ /dev/null
@@ -1,65 +0,0 @@
-// GENERATED CONTENT - DO NOT EDIT
-// Content was automatically extracted by Reffy into webref
-// (https://github.com/w3c/webref)
-// Source: Privacy-Preserving Attribution: Level 1 (https://w3c.github.io/ppa/)
-
-partial interface Navigator {
- [SecureContext, SameObject] readonly attribute PrivateAttribution privateAttribution;
-};
-
-enum PrivateAttributionProtocol { "dap-12-histogram", "tee-00" };
-
-dictionary PrivateAttributionAggregationService {
- required DOMString protocol;
-};
-
-[SecureContext, Exposed=Window]
-interface PrivateAttributionAggregationServices {
- readonly maplike;
-};
-
-[SecureContext, Exposed=Window]
-interface PrivateAttribution {
- readonly attribute PrivateAttributionAggregationServices aggregationServices;
-};
-
-dictionary PrivateAttributionImpressionOptions {
- required unsigned long histogramIndex;
- unsigned long filterData = 0;
- required USVString conversionSite;
- unsigned long lifetimeDays = 30;
-};
-
-[SecureContext, Exposed=Window]
-partial interface PrivateAttribution {
- undefined saveImpression(PrivateAttributionImpressionOptions options);
-};
-
-dictionary PrivateAttributionConversionOptions {
- required USVString aggregationService;
- double epsilon = 1.0;
-
- required unsigned long histogramSize;
-
- unsigned long lookbackDays;
- unsigned long filterData;
- sequence impressionSites = [];
- sequence intermediarySites = [];
-
- PrivateAttributionLogic logic = "last-touch";
- unsigned long value = 1;
- unsigned long maxValue = 1;
-};
-
-dictionary PrivateAttributionConversionResult {
- required Uint8Array report;
-};
-
-[SecureContext, Exposed=Window]
-partial interface PrivateAttribution {
- Promise measureConversion(PrivateAttributionConversionOptions options);
-};
-
-enum PrivateAttributionLogic {
- "last-touch",
-};
diff --git a/test/fixtures/wpt/interfaces/privacy-preserving-attribution.idl b/test/fixtures/wpt/interfaces/privacy-preserving-attribution.idl
new file mode 100644
index 00000000000..2cf43b1e9bc
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/privacy-preserving-attribution.idl
@@ -0,0 +1,75 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Attribution Level 1 (https://w3c.github.io/attribution/)
+
+partial interface Navigator {
+ [SecureContext, SameObject] readonly attribute Attribution attribution;
+};
+
+enum AttributionAggregationProtocol { "dap-15-histogram", "tee-00" };
+
+dictionary AttributionAggregationService {
+ required DOMString protocol;
+};
+
+[SecureContext, Exposed=Window]
+interface AttributionAggregationServices {
+ readonly maplike;
+};
+
+[SecureContext, Exposed=Window]
+interface Attribution {
+ readonly attribute AttributionAggregationServices aggregationServices;
+};
+
+dictionary AttributionImpressionOptions {
+ required unsigned long histogramIndex;
+ unsigned long matchValue = 0;
+ sequence conversionSites = [];
+ sequence conversionCallers = [];
+ unsigned long lifetimeDays = 30;
+ long priority = 0;
+};
+
+dictionary AttributionImpressionResult {
+};
+
+[SecureContext, Exposed=Window]
+partial interface Attribution {
+ Promise saveImpression(AttributionImpressionOptions options);
+};
+
+dictionary AttributionConversionOptions {
+ required USVString aggregationService;
+ double epsilon = 1.0;
+
+ required unsigned long histogramSize;
+
+ unsigned long lookbackDays;
+ sequence matchValues = [];
+ sequence impressionSites = [];
+ sequence impressionCallers = [];
+
+ AttributionLogic logic = "last-n-touch";
+ AttributionLogicOptions logicOptions;
+ unsigned long value = 1;
+ unsigned long maxValue = 1;
+};
+
+enum AttributionLogic {
+ "last-n-touch",
+};
+
+dictionary AttributionLogicOptions {
+ sequence credit;
+};
+
+dictionary AttributionConversionResult {
+ required Uint8Array report;
+};
+
+[SecureContext, Exposed=Window]
+partial interface Attribution {
+ Promise measureConversion(AttributionConversionOptions options);
+};
diff --git a/test/fixtures/wpt/interfaces/push-api.idl b/test/fixtures/wpt/interfaces/push-api.idl
index b16a730b722..a1de7a416b6 100644
--- a/test/fixtures/wpt/interfaces/push-api.idl
+++ b/test/fixtures/wpt/interfaces/push-api.idl
@@ -73,14 +73,16 @@ partial interface ServiceWorkerGlobalScope {
interface PushEvent : ExtendableEvent {
constructor(DOMString type, optional PushEventInit eventInitDict = {});
readonly attribute PushMessageData? data;
+ readonly attribute Notification? notification;
};
-typedef (BufferSource or USVString) PushMessageDataInit;
-
dictionary PushEventInit : ExtendableEventInit {
- PushMessageDataInit data;
+ PushMessageDataInit? data = null;
+ Notification? notification = null;
};
+typedef (BufferSource or USVString) PushMessageDataInit;
+
[Exposed=ServiceWorker, SecureContext]
interface PushSubscriptionChangeEvent : ExtendableEvent {
constructor(DOMString type, optional PushSubscriptionChangeEventInit eventInitDict = {});
diff --git a/test/fixtures/wpt/interfaces/reporting.idl b/test/fixtures/wpt/interfaces/reporting.idl
index c0a400a999e..4511e4dca60 100644
--- a/test/fixtures/wpt/interfaces/reporting.idl
+++ b/test/fixtures/wpt/interfaces/reporting.idl
@@ -3,17 +3,13 @@
// (https://github.com/w3c/webref)
// Source: Reporting API (https://w3c.github.io/reporting/)
-[Exposed=(Window,Worker)]
-interface ReportBody {
- [Default] object toJSON();
+dictionary ReportBody {
};
-[Exposed=(Window,Worker)]
-interface Report {
- [Default] object toJSON();
- readonly attribute DOMString type;
- readonly attribute DOMString url;
- readonly attribute ReportBody? body;
+dictionary Report {
+ DOMString type;
+ DOMString url;
+ ReportBody? body;
};
[Exposed=(Window,Worker)]
diff --git a/test/fixtures/wpt/interfaces/resource-timing.idl b/test/fixtures/wpt/interfaces/resource-timing.idl
index 66f2841d744..499d27b6ee6 100644
--- a/test/fixtures/wpt/interfaces/resource-timing.idl
+++ b/test/fixtures/wpt/interfaces/resource-timing.idl
@@ -28,6 +28,7 @@ interface PerformanceResourceTiming : PerformanceEntry {
readonly attribute unsigned short responseStatus;
readonly attribute RenderBlockingStatusType renderBlockingStatus;
readonly attribute DOMString contentType;
+ readonly attribute DOMString contentEncoding;
[Default] object toJSON();
};
diff --git a/test/fixtures/wpt/interfaces/screen-capture.idl b/test/fixtures/wpt/interfaces/screen-capture.idl
index 45fd0dd72c5..eb5685eee41 100644
--- a/test/fixtures/wpt/interfaces/screen-capture.idl
+++ b/test/fixtures/wpt/interfaces/screen-capture.idl
@@ -29,6 +29,12 @@ enum SystemAudioPreferenceEnum {
"exclude"
};
+enum WindowAudioPreferenceEnum {
+ "system",
+ "window",
+ "exclude"
+};
+
enum SurfaceSwitchingPreferenceEnum {
"include",
"exclude"
@@ -45,6 +51,7 @@ dictionary DisplayMediaStreamOptions {
CaptureController controller;
SelfCapturePreferenceEnum selfBrowserSurface;
SystemAudioPreferenceEnum systemAudio;
+ WindowAudioPreferenceEnum windowAudio;
SurfaceSwitchingPreferenceEnum surfaceSwitching;
MonitorTypeSurfacesEnum monitorTypeSurfaces;
};
@@ -71,6 +78,7 @@ partial dictionary MediaTrackSettings {
DOMString cursor;
boolean restrictOwnAudio;
boolean suppressLocalAudioPlayback;
+ double screenPixelRatio;
};
partial dictionary MediaTrackCapabilities {
diff --git a/test/fixtures/wpt/interfaces/secure-payment-confirmation.idl b/test/fixtures/wpt/interfaces/secure-payment-confirmation.idl
index bec599d7a23..3847651c1f3 100644
--- a/test/fixtures/wpt/interfaces/secure-payment-confirmation.idl
+++ b/test/fixtures/wpt/interfaces/secure-payment-confirmation.idl
@@ -11,13 +11,23 @@ dictionary SecurePaymentConfirmationRequest {
unsigned long timeout;
USVString payeeName;
USVString payeeOrigin;
+ sequence paymentEntitiesLogos;
AuthenticationExtensionsClientInputs extensions;
+ sequence browserBoundPubKeyCredParams;
sequence locale;
boolean showOptOut;
};
+enum SecurePaymentConfirmationAvailability {
+ "available",
+ "unavailable-unknown-reason",
+ "unavailable-feature-not-enabled",
+ "unavailable-no-permission-policy",
+ "unavailable-no-user-verifying-platform-authenticator",
+};
+
partial interface PaymentRequest {
- static Promise isSecurePaymentConfirmationAvailable();
+ static Promise securePaymentConfirmationAvailability();
};
partial dictionary AuthenticationExtensionsClientInputs {
@@ -26,18 +36,32 @@ partial dictionary AuthenticationExtensionsClientInputs {
dictionary AuthenticationExtensionsPaymentInputs {
boolean isPayment;
+ sequence browserBoundPubKeyCredParams;
// Only used for authentication.
USVString rpId;
USVString topOrigin;
USVString payeeName;
USVString payeeOrigin;
+ sequence paymentEntitiesLogos;
PaymentCurrencyAmount total;
PaymentCredentialInstrument instrument;
};
+partial dictionary AuthenticationExtensionsClientOutputs {
+ AuthenticationExtensionsPaymentOutputs payment;
+};
+
+dictionary AuthenticationExtensionsPaymentOutputs {
+ BrowserBoundSignature browserBoundSignature;
+};
+
+dictionary BrowserBoundSignature {
+ required ArrayBuffer signature;
+};
+
dictionary CollectedClientPaymentData : CollectedClientData {
- required CollectedClientAdditionalPaymentData payment;
+ required (CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData) payment;
};
dictionary CollectedClientAdditionalPaymentData {
@@ -45,12 +69,24 @@ dictionary CollectedClientAdditionalPaymentData {
required USVString topOrigin;
USVString payeeName;
USVString payeeOrigin;
+ sequence paymentEntitiesLogos;
required PaymentCurrencyAmount total;
required PaymentCredentialInstrument instrument;
+ USVString browserBoundPublicKey;
+};
+
+dictionary CollectedClientAdditionalPaymentRegistrationData {
+ USVString browserBoundPublicKey;
};
dictionary PaymentCredentialInstrument {
required USVString displayName;
required USVString icon;
boolean iconMustBeShown = true;
+ USVString details;
+};
+
+dictionary PaymentEntityLogo {
+ required USVString url;
+ required USVString label;
};
diff --git a/test/fixtures/wpt/interfaces/service-workers.idl b/test/fixtures/wpt/interfaces/service-workers.idl
index d9ff2f651f8..34af3372401 100644
--- a/test/fixtures/wpt/interfaces/service-workers.idl
+++ b/test/fixtures/wpt/interfaces/service-workers.idl
@@ -34,7 +34,7 @@ interface ServiceWorkerRegistration : EventTarget {
readonly attribute USVString scope;
readonly attribute ServiceWorkerUpdateViaCache updateViaCache;
- [NewObject] Promise update();
+ [NewObject] Promise update();
[NewObject] Promise unregister();
// event
diff --git a/test/fixtures/wpt/interfaces/shared-storage.idl b/test/fixtures/wpt/interfaces/shared-storage.idl
index e3e221a3aa7..d44997faf19 100644
--- a/test/fixtures/wpt/interfaces/shared-storage.idl
+++ b/test/fixtures/wpt/interfaces/shared-storage.idl
@@ -105,7 +105,7 @@ interface SharedStorage {
Promise remainingBudget();
[Exposed=SharedStorageWorklet]
- async iterable;
+ async_iterable;
};
dictionary SharedStoragePrivateAggregationConfig {
diff --git a/test/fixtures/wpt/interfaces/speech-api.idl b/test/fixtures/wpt/interfaces/speech-api.idl
index bc0635fa3f2..92dbd02d22e 100644
--- a/test/fixtures/wpt/interfaces/speech-api.idl
+++ b/test/fixtures/wpt/interfaces/speech-api.idl
@@ -3,24 +3,26 @@
// (https://github.com/w3c/webref)
// Source: Web Speech API (https://webaudio.github.io/web-speech-api/)
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognition : EventTarget {
constructor();
// recognition parameters
+ attribute SpeechGrammarList grammars;
attribute DOMString lang;
attribute boolean continuous;
attribute boolean interimResults;
attribute unsigned long maxAlternatives;
- attribute SpeechRecognitionMode mode;
+ attribute boolean processLocally;
+ attribute ObservableArray phrases;
// methods to drive the speech interaction
undefined start();
undefined start(MediaStreamTrack audioTrack);
undefined stop();
undefined abort();
- static Promise availableOnDevice(DOMString lang);
- static Promise installOnDevice(DOMString lang);
+ static Promise available(SpeechRecognitionOptions options);
+ static Promise install(SpeechRecognitionOptions options);
// event methods
attribute EventHandler onaudiostart;
@@ -36,6 +38,11 @@ interface SpeechRecognition : EventTarget {
attribute EventHandler onend;
};
+dictionary SpeechRecognitionOptions {
+ required sequence langs;
+ boolean processLocally = false;
+};
+
enum SpeechRecognitionErrorCode {
"no-speech",
"aborted",
@@ -43,16 +50,18 @@ enum SpeechRecognitionErrorCode {
"network",
"not-allowed",
"service-not-allowed",
- "language-not-supported"
+ "language-not-supported",
+ "phrases-not-supported"
};
-enum SpeechRecognitionMode {
- "ondevice-preferred", // On-device speech recognition if available, otherwise use Cloud speech recognition as a fallback.
- "ondevice-only", // On-device speech recognition only. Returns an error if on-device speech recognition is not available.
- "cloud-only", // Cloud speech recognition only.
+enum AvailabilityStatus {
+ "unavailable",
+ "downloadable",
+ "downloading",
+ "available"
};
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionErrorEvent : Event {
constructor(DOMString type, SpeechRecognitionErrorEventInit eventInitDict);
readonly attribute SpeechRecognitionErrorCode error;
@@ -65,14 +74,14 @@ dictionary SpeechRecognitionErrorEventInit : EventInit {
};
// Item in N-best list
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionAlternative {
readonly attribute DOMString transcript;
readonly attribute float confidence;
};
// A complete one-shot simple response
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionResult {
readonly attribute unsigned long length;
getter SpeechRecognitionAlternative item(unsigned long index);
@@ -80,14 +89,14 @@ interface SpeechRecognitionResult {
};
// A collection of responses (used in continuous mode)
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionResultList {
readonly attribute unsigned long length;
getter SpeechRecognitionResult item(unsigned long index);
};
// A full response, which could be interim or final, part of a continuous response or not
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionEvent : Event {
constructor(DOMString type, SpeechRecognitionEventInit eventInitDict);
readonly attribute unsigned long resultIndex;
@@ -99,6 +108,33 @@ dictionary SpeechRecognitionEventInit : EventInit {
required SpeechRecognitionResultList results;
};
+// The object representing a speech grammar. This interface has been deprecated and exists in this spec for the sole purpose of maintaining backwards compatibility.
+[Exposed=Window]
+interface SpeechGrammar {
+ attribute DOMString src;
+ attribute float weight;
+};
+
+// The object representing a speech grammar collection. This interface has been deprecated and exists in this spec for the sole purpose of maintaining backwards compatibility.
+[Exposed=Window]
+interface SpeechGrammarList {
+ constructor();
+ readonly attribute unsigned long length;
+ getter SpeechGrammar item(unsigned long index);
+ undefined addFromURI(DOMString src,
+ optional float weight = 1.0);
+ undefined addFromString(DOMString string,
+ optional float weight = 1.0);
+};
+
+// The object representing a phrase for contextual biasing.
+[SecureContext, Exposed=Window]
+interface SpeechRecognitionPhrase {
+ constructor(DOMString phrase, optional float boost = 1.0);
+ readonly attribute DOMString phrase;
+ readonly attribute float boost;
+};
+
[Exposed=Window]
interface SpeechSynthesis : EventTarget {
readonly attribute boolean pending;
diff --git a/test/fixtures/wpt/interfaces/sri.idl b/test/fixtures/wpt/interfaces/sri.idl
new file mode 100644
index 00000000000..d179ca467d1
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/sri.idl
@@ -0,0 +1,11 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Subresource Integrity (https://w3c.github.io/webappsec-subresource-integrity/)
+
+dictionary IntegrityViolationReportBody : ReportBody {
+ USVString documentURL;
+ USVString blockedURL;
+ USVString destination;
+ boolean reportOnly;
+};
diff --git a/test/fixtures/wpt/interfaces/streams.idl b/test/fixtures/wpt/interfaces/streams.idl
index ab9be033e43..8abc8f5cfda 100644
--- a/test/fixtures/wpt/interfaces/streams.idl
+++ b/test/fixtures/wpt/interfaces/streams.idl
@@ -17,7 +17,7 @@ interface ReadableStream {
Promise pipeTo(WritableStream destination, optional StreamPipeOptions options = {});
sequence tee();
- async iterable(optional ReadableStreamIteratorOptions options = {});
+ async_iterable(optional ReadableStreamIteratorOptions options = {});
};
typedef (ReadableStreamDefaultReader or ReadableStreamBYOBReader) ReadableStreamReader;
diff --git a/test/fixtures/wpt/interfaces/translation-api.idl b/test/fixtures/wpt/interfaces/translation-api.idl
new file mode 100644
index 00000000000..6cbad38938a
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/translation-api.idl
@@ -0,0 +1,85 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Translator and Language Detector APIs (https://webmachinelearning.github.io/translation-api/)
+
+[Exposed=Window, SecureContext]
+interface Translator {
+ static Promise create(TranslatorCreateOptions options);
+ static Promise availability(TranslatorCreateCoreOptions options);
+
+ Promise translate(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+ ReadableStream translateStreaming(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+
+ readonly attribute DOMString sourceLanguage;
+ readonly attribute DOMString targetLanguage;
+
+ Promise measureInputUsage(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+Translator includes DestroyableModel;
+
+dictionary TranslatorCreateCoreOptions {
+ required DOMString sourceLanguage;
+ required DOMString targetLanguage;
+};
+
+dictionary TranslatorCreateOptions : TranslatorCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+};
+
+dictionary TranslatorTranslateOptions {
+ AbortSignal signal;
+};
+
+[Exposed=Window, SecureContext]
+interface LanguageDetector {
+ static Promise create(
+ optional LanguageDetectorCreateOptions options = {}
+ );
+ static Promise availability(
+ optional LanguageDetectorCreateCoreOptions options = {}
+ );
+
+ Promise> detect(
+ DOMString input,
+ optional LanguageDetectorDetectOptions options = {}
+ );
+
+ readonly attribute FrozenArray? expectedInputLanguages;
+
+ Promise measureInputUsage(
+ DOMString input,
+ optional LanguageDetectorDetectOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+LanguageDetector includes DestroyableModel;
+
+dictionary LanguageDetectorCreateCoreOptions {
+ sequence expectedInputLanguages;
+};
+
+dictionary LanguageDetectorCreateOptions : LanguageDetectorCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+};
+
+dictionary LanguageDetectorDetectOptions {
+ AbortSignal signal;
+};
+
+dictionary LanguageDetectionResult {
+ DOMString detectedLanguage;
+ double confidence;
+};
diff --git a/test/fixtures/wpt/interfaces/turtledove.idl b/test/fixtures/wpt/interfaces/turtledove.idl
index b9f50d47885..7f11cdc3790 100644
--- a/test/fixtures/wpt/interfaces/turtledove.idl
+++ b/test/fixtures/wpt/interfaces/turtledove.idl
@@ -206,6 +206,7 @@ partial interface Navigator {
[Exposed=InterestGroupScriptRunnerGlobalScope]
interface InterestGroupScriptRunnerGlobalScope {
readonly attribute PrivateAggregation? privateAggregation;
+ readonly attribute ProtectedAudienceUtilities protectedAudience;
};
dictionary PASignalValue {
@@ -220,6 +221,12 @@ dictionary PAExtendedHistogramContribution {
bigint filteringId = 0;
};
+[Exposed=InterestGroupScriptRunnerGlobalScope]
+interface ProtectedAudienceUtilities {
+ Uint8Array encodeUtf8(USVString input);
+ USVString decodeUtf8(Uint8Array bytes);
+};
+
[Exposed=InterestGroupBiddingAndScoringScriptRunnerGlobalScope]
interface ForDebuggingOnly {
undefined reportAdAuctionWin(USVString url);
diff --git a/test/fixtures/wpt/interfaces/wai-aria.idl b/test/fixtures/wpt/interfaces/wai-aria.idl
index deebc5626e2..3364bc9a769 100644
--- a/test/fixtures/wpt/interfaces/wai-aria.idl
+++ b/test/fixtures/wpt/interfaces/wai-aria.idl
@@ -57,4 +57,4 @@ interface mixin ARIAMixin {
[CEReactions] attribute DOMString? ariaValueNow;
[CEReactions] attribute DOMString? ariaValueText;
};
-Element includes ARIAMixin;
+ Element includes ARIAMixin;
diff --git a/test/fixtures/wpt/interfaces/web-animations-2.idl b/test/fixtures/wpt/interfaces/web-animations-2.idl
index c4a0c2532d9..f18cdd4f458 100644
--- a/test/fixtures/wpt/interfaces/web-animations-2.idl
+++ b/test/fixtures/wpt/interfaces/web-animations-2.idl
@@ -118,7 +118,7 @@ dictionary AnimationPlaybackEventInit : EventInit {
interface AnimationTrigger {
constructor(optional AnimationTriggerOptions options = {});
attribute AnimationTimeline timeline;
- attribute AnimationTriggerType type;
+ attribute AnimationTriggerBehavior behavior;
attribute any rangeStart;
attribute any rangeEnd;
attribute any exitRangeStart;
@@ -127,11 +127,11 @@ interface AnimationTrigger {
dictionary AnimationTriggerOptions {
AnimationTimeline? timeline;
- AnimationTriggerType? type = "once";
+ AnimationTriggerBehavior? behavior = "once";
(TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or DOMString) rangeStart = "normal";
(TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or DOMString) rangeEnd = "normal";
(TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or DOMString) exitRangeStart = "auto";
(TimelineRangeOffset or CSSNumericValue or CSSKeywordValue or DOMString) exitRangeEnd = "auto";
};
-enum AnimationTriggerType { "once", "repeat", "alternate", "state" };
+enum AnimationTriggerBehavior { "once", "repeat", "alternate", "state" };
diff --git a/test/fixtures/wpt/interfaces/webaudio.idl b/test/fixtures/wpt/interfaces/webaudio.idl
index 3b351f4d9e9..286aeba4069 100644
--- a/test/fixtures/wpt/interfaces/webaudio.idl
+++ b/test/fixtures/wpt/interfaces/webaudio.idl
@@ -6,7 +6,8 @@
enum AudioContextState {
"suspended",
"running",
- "closed"
+ "closed",
+ "interrupted"
};
enum AudioContextRenderSizeCategory {
diff --git a/test/fixtures/wpt/interfaces/webauthn.idl b/test/fixtures/wpt/interfaces/webauthn.idl
index a33c85e7bad..7fbe55e6765 100644
--- a/test/fixtures/wpt/interfaces/webauthn.idl
+++ b/test/fixtures/wpt/interfaces/webauthn.idl
@@ -311,22 +311,37 @@ enum PublicKeyCredentialHint {
partial dictionary AuthenticationExtensionsClientInputs {
DOMString appid;
};
+partial dictionary AuthenticationExtensionsClientInputsJSON {
+ DOMString appid;
+};
partial dictionary AuthenticationExtensionsClientOutputs {
boolean appid;
};
+partial dictionary AuthenticationExtensionsClientOutputsJSON {
+ boolean appid;
+};
partial dictionary AuthenticationExtensionsClientInputs {
DOMString appidExclude;
};
+partial dictionary AuthenticationExtensionsClientInputsJSON {
+ DOMString appidExclude;
+};
partial dictionary AuthenticationExtensionsClientOutputs {
boolean appidExclude;
};
+partial dictionary AuthenticationExtensionsClientOutputsJSON {
+ boolean appidExclude;
+};
partial dictionary AuthenticationExtensionsClientInputs {
boolean credProps;
};
+partial dictionary AuthenticationExtensionsClientInputsJSON {
+ boolean credProps;
+};
dictionary CredentialPropertiesOutput {
boolean rk;
@@ -335,33 +350,57 @@ dictionary CredentialPropertiesOutput {
partial dictionary AuthenticationExtensionsClientOutputs {
CredentialPropertiesOutput credProps;
};
+partial dictionary AuthenticationExtensionsClientOutputsJSON {
+ CredentialPropertiesOutput credProps;
+};
dictionary AuthenticationExtensionsPRFValues {
required BufferSource first;
BufferSource second;
};
+dictionary AuthenticationExtensionsPRFValuesJSON {
+ required Base64URLString first;
+ Base64URLString second;
+};
dictionary AuthenticationExtensionsPRFInputs {
AuthenticationExtensionsPRFValues eval;
record evalByCredential;
};
+dictionary AuthenticationExtensionsPRFInputsJSON {
+ AuthenticationExtensionsPRFValuesJSON eval;
+ record evalByCredential;
+};
partial dictionary AuthenticationExtensionsClientInputs {
AuthenticationExtensionsPRFInputs prf;
};
+partial dictionary AuthenticationExtensionsClientInputsJSON {
+ AuthenticationExtensionsPRFInputsJSON prf;
+};
dictionary AuthenticationExtensionsPRFOutputs {
boolean enabled;
AuthenticationExtensionsPRFValues results;
};
+dictionary AuthenticationExtensionsPRFOutputsJSON {
+ boolean enabled;
+ AuthenticationExtensionsPRFValuesJSON results;
+};
partial dictionary AuthenticationExtensionsClientOutputs {
AuthenticationExtensionsPRFOutputs prf;
};
+partial dictionary AuthenticationExtensionsClientOutputsJSON {
+ AuthenticationExtensionsPRFOutputsJSON prf;
+};
partial dictionary AuthenticationExtensionsClientInputs {
AuthenticationExtensionsLargeBlobInputs largeBlob;
};
+partial dictionary AuthenticationExtensionsClientInputsJSON {
+ AuthenticationExtensionsLargeBlobInputsJSON largeBlob;
+};
enum LargeBlobSupport {
"required",
@@ -373,13 +412,26 @@ dictionary AuthenticationExtensionsLargeBlobInputs {
boolean read;
BufferSource write;
};
+dictionary AuthenticationExtensionsLargeBlobInputsJSON {
+ DOMString support;
+ boolean read;
+ Base64URLString write;
+};
partial dictionary AuthenticationExtensionsClientOutputs {
AuthenticationExtensionsLargeBlobOutputs largeBlob;
};
+partial dictionary AuthenticationExtensionsClientOutputsJSON {
+ AuthenticationExtensionsLargeBlobOutputsJSON largeBlob;
+};
dictionary AuthenticationExtensionsLargeBlobOutputs {
boolean supported;
ArrayBuffer blob;
boolean written;
};
+dictionary AuthenticationExtensionsLargeBlobOutputsJSON {
+ boolean supported;
+ Base64URLString blob;
+ boolean written;
+};
diff --git a/test/fixtures/wpt/interfaces/webcodecs.idl b/test/fixtures/wpt/interfaces/webcodecs.idl
index 274ef96578a..3d4db1ed49d 100644
--- a/test/fixtures/wpt/interfaces/webcodecs.idl
+++ b/test/fixtures/wpt/interfaces/webcodecs.idl
@@ -141,7 +141,7 @@ dictionary AudioDecoderConfig {
required DOMString codec;
[EnforceRange] required unsigned long sampleRate;
[EnforceRange] required unsigned long numberOfChannels;
- BufferSource description;
+ AllowSharedBufferSource description;
};
dictionary VideoDecoderConfig {
diff --git a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl b/test/fixtures/wpt/interfaces/webcrypto.idl
similarity index 98%
rename from test/fixtures/wpt/interfaces/WebCryptoAPI.idl
rename to test/fixtures/wpt/interfaces/webcrypto.idl
index ff7a89cd0d5..9c742fa9709 100644
--- a/test/fixtures/wpt/interfaces/WebCryptoAPI.idl
+++ b/test/fixtures/wpt/interfaces/webcrypto.idl
@@ -1,7 +1,7 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into webref
// (https://github.com/w3c/webref)
-// Source: Web Cryptography API (https://w3c.github.io/webcrypto/)
+// Source: Web Cryptography API Level 2 (https://w3c.github.io/webcrypto/)
partial interface mixin WindowOrWorkerGlobalScope {
[SameObject] readonly attribute Crypto crypto;
diff --git a/test/fixtures/wpt/interfaces/webgpu.idl b/test/fixtures/wpt/interfaces/webgpu.idl
index d91a6a710b1..b5851304fc9 100644
--- a/test/fixtures/wpt/interfaces/webgpu.idl
+++ b/test/fixtures/wpt/interfaces/webgpu.idl
@@ -64,6 +64,7 @@ interface GPUAdapterInfo {
readonly attribute DOMString description;
readonly attribute unsigned long subgroupMinSize;
readonly attribute unsigned long subgroupMaxSize;
+ readonly attribute boolean isFallbackAdapter;
};
interface mixin NavigatorGPU {
@@ -96,7 +97,6 @@ interface GPUAdapter {
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
[SameObject] readonly attribute GPUAdapterInfo info;
- readonly attribute boolean isFallbackAdapter;
Promise requestDevice(optional GPUDeviceDescriptor descriptor = {});
};
@@ -109,6 +109,7 @@ dictionary GPUDeviceDescriptor
};
enum GPUFeatureName {
+ "core-features-and-limits",
"depth-clip-control",
"depth32float-stencil8",
"texture-compression-bc",
@@ -126,6 +127,8 @@ enum GPUFeatureName {
"clip-distances",
"dual-source-blending",
"subgroups",
+ "texture-formats-tier1",
+ "texture-formats-tier2",
};
[Exposed=(Window, Worker), SecureContext]
@@ -294,6 +297,8 @@ enum GPUTextureFormat {
"r8sint",
// 16-bit formats
+ "r16unorm",
+ "r16snorm",
"r16uint",
"r16sint",
"r16float",
@@ -306,6 +311,8 @@ enum GPUTextureFormat {
"r32uint",
"r32sint",
"r32float",
+ "rg16unorm",
+ "rg16snorm",
"rg16uint",
"rg16sint",
"rg16float",
@@ -326,6 +333,8 @@ enum GPUTextureFormat {
"rg32uint",
"rg32sint",
"rg32float",
+ "rgba16unorm",
+ "rgba16snorm",
"rgba16uint",
"rgba16sint",
"rgba16float",
@@ -555,7 +564,12 @@ dictionary GPUBindGroupDescriptor
required sequence entries;
};
-typedef (GPUSampler or GPUTextureView or GPUBufferBinding or GPUExternalTexture) GPUBindingResource;
+typedef (GPUSampler or
+ GPUTexture or
+ GPUTextureView or
+ GPUBuffer or
+ GPUBufferBinding or
+ GPUExternalTexture) GPUBindingResource;
dictionary GPUBindGroupEntry {
required GPUIndex32 binding;
@@ -936,12 +950,16 @@ interface GPUCommandEncoder {
GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
+ undefined copyBufferToBuffer(
+ GPUBuffer source,
+ GPUBuffer destination,
+ optional GPUSize64 size);
undefined copyBufferToBuffer(
GPUBuffer source,
GPUSize64 sourceOffset,
GPUBuffer destination,
GPUSize64 destinationOffset,
- GPUSize64 size);
+ optional GPUSize64 size);
undefined copyBufferToTexture(
GPUTexelCopyBufferInfo source,
@@ -985,7 +1003,7 @@ interface mixin GPUBindingCommandsMixin {
optional sequence dynamicOffsets = []);
undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup,
- Uint32Array dynamicOffsetsData,
+ [AllowShared] Uint32Array dynamicOffsetsData,
GPUSize64 dynamicOffsetsDataStart,
GPUSize32 dynamicOffsetsDataLength);
};
@@ -1060,9 +1078,9 @@ dictionary GPURenderPassDescriptor
};
dictionary GPURenderPassColorAttachment {
- required GPUTextureView view;
+ required (GPUTexture or GPUTextureView) view;
GPUIntegerCoordinate depthSlice;
- GPUTextureView resolveTarget;
+ (GPUTexture or GPUTextureView) resolveTarget;
GPUColor clearValue;
required GPULoadOp loadOp;
@@ -1070,7 +1088,7 @@ dictionary GPURenderPassColorAttachment {
};
dictionary GPURenderPassDepthStencilAttachment {
- required GPUTextureView view;
+ required (GPUTexture or GPUTextureView) view;
float depthClearValue;
GPULoadOp depthLoadOp;
diff --git a/test/fixtures/wpt/interfaces/webidl.idl b/test/fixtures/wpt/interfaces/webidl.idl
index f3db91096ac..651c1922115 100644
--- a/test/fixtures/wpt/interfaces/webidl.idl
+++ b/test/fixtures/wpt/interfaces/webidl.idl
@@ -3,6 +3,19 @@
// (https://github.com/w3c/webref)
// Source: Web IDL Standard (https://webidl.spec.whatwg.org/)
+[Exposed=*, Serializable]
+interface QuotaExceededError : DOMException {
+ constructor(optional DOMString message = "", optional QuotaExceededErrorOptions options = {});
+
+ readonly attribute double? quota;
+ readonly attribute double? requested;
+};
+
+dictionary QuotaExceededErrorOptions {
+ double quota;
+ double requested;
+};
+
typedef (Int8Array or Int16Array or Int32Array or
Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
BigInt64Array or BigUint64Array or
diff --git a/test/fixtures/wpt/interfaces/webnn.idl b/test/fixtures/wpt/interfaces/webnn.idl
index 8dc3a0ebc14..3490f40e832 100644
--- a/test/fixtures/wpt/interfaces/webnn.idl
+++ b/test/fixtures/wpt/interfaces/webnn.idl
@@ -36,6 +36,8 @@ interface MLContext {
undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);
Promise createTensor(MLTensorDescriptor descriptor);
+ Promise createConstantTensor(
+ MLOperandDescriptor descriptor, AllowSharedBufferSource inputData);
Promise readTensor(MLTensor tensor);
Promise readTensor(MLTensor tensor, AllowSharedBufferSource outputData);
@@ -51,24 +53,37 @@ interface MLContext {
dictionary MLOpSupportLimits {
MLInputOperandLayout preferredInputLayout;
- MLSupportLimits input;
- MLSupportLimits constant;
- MLSupportLimits output;
+ [EnforceRange] unsigned long long maxTensorByteLength;
+ MLDataTypeLimits input;
+ MLDataTypeLimits constant;
+ MLDataTypeLimits output;
};
-dictionary MLSupportLimits {
- sequence dataTypes;
+typedef sequence MLDataTypeList;
+
+dictionary MLDataTypeLimits {
+ MLDataTypeList dataTypes;
+};
+
+dictionary MLRankRange {
+ unsigned long min;
+ unsigned long max;
+};
+
+dictionary MLTensorLimits {
+ MLDataTypeList dataTypes;
+ MLRankRange rankRange;
};
dictionary MLBinarySupportLimits {
- MLSupportLimits a;
- MLSupportLimits b;
- MLSupportLimits output;
+ MLTensorLimits a;
+ MLTensorLimits b;
+ MLDataTypeLimits output;
};
dictionary MLSingleInputSupportLimits {
- MLSupportLimits input;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLDataTypeLimits output;
};
[SecureContext, Exposed=(Window, Worker)]
@@ -120,6 +135,7 @@ interface MLTensor {
readonly attribute FrozenArray shape;
readonly attribute boolean readable;
readonly attribute boolean writable;
+ readonly attribute boolean constant;
undefined destroy();
};
@@ -141,6 +157,9 @@ interface MLGraphBuilder {
// Create a scalar operand from the specified number of the specified type.
MLOperand constant(MLOperandDataType type, MLNumber value);
+ // Create an operand from a specified constant tensor.
+ MLOperand constant(MLTensor tensor);
+
// Compile the graph up to the specified output operands asynchronously.
Promise build(MLNamedOperands outputs);
};
@@ -175,12 +194,12 @@ partial interface MLGraphBuilder {
};
dictionary MLBatchNormalizationSupportLimits {
- MLSupportLimits input;
- MLSupportLimits mean;
- MLSupportLimits variance;
- MLSupportLimits scale;
- MLSupportLimits bias;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits mean;
+ MLTensorLimits variance;
+ MLTensorLimits scale;
+ MLTensorLimits bias;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -217,8 +236,8 @@ partial interface MLGraphBuilder {
};
dictionary MLConcatSupportLimits {
- MLSupportLimits inputs;
- MLSupportLimits output;
+ MLTensorLimits inputs;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -249,10 +268,10 @@ partial interface MLGraphBuilder {
};
dictionary MLConv2dSupportLimits {
- MLSupportLimits input;
- MLSupportLimits filter;
- MLSupportLimits bias;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits filter;
+ MLTensorLimits bias;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -350,11 +369,13 @@ partial interface MLGraphBuilder {
MLOperand logicalXor(MLOperand a,
MLOperand b,
optional MLOperatorOptions options = {});
+ MLOperand isNaN(MLOperand a, optional MLOperatorOptions options = {});
+ MLOperand isInfinite(MLOperand a, optional MLOperatorOptions options = {});
};
dictionary MLLogicalNotSupportLimits {
- MLSupportLimits a;
- MLSupportLimits output;
+ MLTensorLimits a;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -368,6 +389,8 @@ partial dictionary MLOpSupportLimits {
MLBinarySupportLimits logicalAnd;
MLBinarySupportLimits logicalOr;
MLBinarySupportLimits logicalXor;
+ MLLogicalNotSupportLimits isNaN;
+ MLLogicalNotSupportLimits isInfinite;
};
partial interface MLGraphBuilder {
@@ -381,6 +404,7 @@ partial interface MLGraphBuilder {
MLOperand log(MLOperand input, optional MLOperatorOptions options = {});
MLOperand neg(MLOperand input, optional MLOperatorOptions options = {});
MLOperand reciprocal(MLOperand input, optional MLOperatorOptions options = {});
+ MLOperand roundEven(MLOperand input, optional MLOperatorOptions options = {});
MLOperand sin(MLOperand input, optional MLOperatorOptions options = {});
MLOperand sign(MLOperand input, optional MLOperatorOptions options = {});
MLOperand sqrt(MLOperand input, optional MLOperatorOptions options = {});
@@ -398,6 +422,7 @@ partial dictionary MLOpSupportLimits {
MLSingleInputSupportLimits log;
MLSingleInputSupportLimits neg;
MLSingleInputSupportLimits reciprocal;
+ MLSingleInputSupportLimits roundEven;
MLSingleInputSupportLimits sin;
MLSingleInputSupportLimits sign;
MLSingleInputSupportLimits sqrt;
@@ -411,15 +436,15 @@ partial interface MLGraphBuilder {
optional MLOperatorOptions options = {});
};
-dictionary MLQuantizationSupportLimits {
- MLSupportLimits input;
- MLSupportLimits scale;
- MLSupportLimits zeroPoint;
- MLSupportLimits output;
+dictionary MLQuantizeDequantizeLinearSupportLimits {
+ MLTensorLimits input;
+ MLTensorLimits scale;
+ MLTensorLimits zeroPoint;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
- MLQuantizationSupportLimits dequantizeLinear;
+ MLQuantizeDequantizeLinearSupportLimits dequantizeLinear;
};
partial interface MLGraphBuilder {
@@ -430,7 +455,7 @@ partial interface MLGraphBuilder {
};
partial dictionary MLOpSupportLimits {
- MLQuantizationSupportLimits quantizeLinear;
+ MLQuantizeDequantizeLinearSupportLimits quantizeLinear;
};
dictionary MLEluOptions : MLOperatorOptions {
@@ -466,9 +491,9 @@ partial interface MLGraphBuilder {
};
dictionary MLGatherSupportLimits {
- MLSupportLimits input;
- MLSupportLimits indices;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits indices;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -516,10 +541,10 @@ partial interface MLGraphBuilder {
};
dictionary MLGemmSupportLimits {
- MLSupportLimits a;
- MLSupportLimits b;
- MLSupportLimits c;
- MLSupportLimits output;
+ MLTensorLimits a;
+ MLTensorLimits b;
+ MLTensorLimits c;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -564,13 +589,13 @@ partial interface MLGraphBuilder {
};
dictionary MLGruSupportLimits {
- MLSupportLimits input;
- MLSupportLimits weight;
- MLSupportLimits recurrentWeight;
- MLSupportLimits bias;
- MLSupportLimits recurrentBias;
- MLSupportLimits initialHiddenState;
- MLSupportLimits outputs;
+ MLTensorLimits input;
+ MLTensorLimits weight;
+ MLTensorLimits recurrentWeight;
+ MLTensorLimits bias;
+ MLTensorLimits recurrentBias;
+ MLTensorLimits initialHiddenState;
+ MLDataTypeLimits outputs;
};
partial dictionary MLOpSupportLimits {
@@ -595,13 +620,13 @@ partial interface MLGraphBuilder {
};
dictionary MLGruCellSupportLimits {
- MLSupportLimits input;
- MLSupportLimits weight;
- MLSupportLimits recurrentWeight;
- MLSupportLimits hiddenState;
- MLSupportLimits bias;
- MLSupportLimits recurrentBias;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits weight;
+ MLTensorLimits recurrentWeight;
+ MLTensorLimits hiddenState;
+ MLTensorLimits bias;
+ MLTensorLimits recurrentBias;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -642,10 +667,10 @@ partial interface MLGraphBuilder {
};
dictionary MLNormalizationSupportLimits {
- MLSupportLimits input;
- MLSupportLimits scale;
- MLSupportLimits bias;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits scale;
+ MLTensorLimits bias;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -720,15 +745,15 @@ partial interface MLGraphBuilder {
};
dictionary MLLstmSupportLimits {
- MLSupportLimits input;
- MLSupportLimits weight;
- MLSupportLimits recurrentWeight;
- MLSupportLimits bias;
- MLSupportLimits recurrentBias;
- MLSupportLimits peepholeWeight;
- MLSupportLimits initialHiddenState;
- MLSupportLimits initialCellState;
- MLSupportLimits outputs;
+ MLTensorLimits input;
+ MLTensorLimits weight;
+ MLTensorLimits recurrentWeight;
+ MLTensorLimits bias;
+ MLTensorLimits recurrentBias;
+ MLTensorLimits peepholeWeight;
+ MLTensorLimits initialHiddenState;
+ MLTensorLimits initialCellState;
+ MLDataTypeLimits outputs;
};
partial dictionary MLOpSupportLimits {
@@ -754,15 +779,15 @@ partial interface MLGraphBuilder {
};
dictionary MLLstmCellSupportLimits {
- MLSupportLimits input;
- MLSupportLimits weight;
- MLSupportLimits recurrentWeight;
- MLSupportLimits hiddenState;
- MLSupportLimits cellState;
- MLSupportLimits bias;
- MLSupportLimits recurrentBias;
- MLSupportLimits peepholeWeight;
- MLSupportLimits outputs;
+ MLTensorLimits input;
+ MLTensorLimits weight;
+ MLTensorLimits recurrentWeight;
+ MLTensorLimits hiddenState;
+ MLTensorLimits cellState;
+ MLTensorLimits bias;
+ MLTensorLimits recurrentBias;
+ MLTensorLimits peepholeWeight;
+ MLDataTypeLimits outputs;
};
partial dictionary MLOpSupportLimits {
@@ -780,8 +805,7 @@ partial dictionary MLOpSupportLimits {
enum MLPaddingMode {
"constant",
"edge",
- "reflection",
- "symmetric"
+ "reflection"
};
dictionary MLPadOptions : MLOperatorOptions {
@@ -834,9 +858,9 @@ partial interface MLGraphBuilder {
};
dictionary MLPreluSupportLimits {
- MLSupportLimits input;
- MLSupportLimits slope;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits slope;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -936,10 +960,10 @@ partial interface MLGraphBuilder {
};
dictionary MLScatterSupportLimits {
- MLSupportLimits input;
- MLSupportLimits indices;
- MLSupportLimits updates;
- MLSupportLimits output;
+ MLTensorLimits input;
+ MLTensorLimits indices;
+ MLTensorLimits updates;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
@@ -1018,8 +1042,8 @@ partial interface MLGraphBuilder {
};
dictionary MLSplitSupportLimits {
- MLSupportLimits input;
- MLSupportLimits outputs;
+ MLTensorLimits input;
+ MLDataTypeLimits outputs;
};
partial dictionary MLOpSupportLimits {
@@ -1077,10 +1101,10 @@ partial interface MLGraphBuilder {
};
dictionary MLWhereSupportLimits {
- MLSupportLimits condition;
- MLSupportLimits trueValue;
- MLSupportLimits falseValue;
- MLSupportLimits output;
+ MLTensorLimits condition;
+ MLTensorLimits trueValue;
+ MLTensorLimits falseValue;
+ MLDataTypeLimits output;
};
partial dictionary MLOpSupportLimits {
diff --git a/test/fixtures/wpt/interfaces/webrtc-encoded-transform.idl b/test/fixtures/wpt/interfaces/webrtc-encoded-transform.idl
index 8a6ba816016..c982e7fc3c5 100644
--- a/test/fixtures/wpt/interfaces/webrtc-encoded-transform.idl
+++ b/test/fixtures/wpt/interfaces/webrtc-encoded-transform.idl
@@ -19,8 +19,18 @@ enum SFrameTransformRole {
"decrypt"
};
+// List of supported cipher suites, as defined in [[RFC9605]] section 4.5.
+enum SFrameCipherSuite {
+ "AES_128_CTR_HMAC_SHA256_80",
+ "AES_128_CTR_HMAC_SHA256_64",
+ "AES_128_CTR_HMAC_SHA256_32",
+ "AES_128_GCM_SHA256_128",
+ "AES_256_GCM_SHA512_128"
+};
+
dictionary SFrameTransformOptions {
SFrameTransformRole role = "encrypt";
+ required SFrameCipherSuite cipherSuite;
};
typedef [EnforceRange] unsigned long long SmallCryptoKeyID;
@@ -55,6 +65,17 @@ dictionary SFrameTransformErrorEventInit : EventInit {
CryptoKeyID? keyID;
};
+dictionary RTCEncodedFrameMetadata {
+ unsigned long synchronizationSource;
+ octet payloadType;
+ sequence contributingSources;
+ unsigned long rtpTimestamp;
+ DOMHighResTimeStamp receiveTime;
+ DOMHighResTimeStamp captureTime;
+ DOMHighResTimeStamp senderCaptureTimeOffset;
+ DOMString mimeType;
+};
+
// New enum for video frame types. Will eventually re-use the equivalent defined
// by WebCodecs.
enum RTCEncodedVideoFrameType {
@@ -63,22 +84,14 @@ enum RTCEncodedVideoFrameType {
"delta",
};
-dictionary RTCEncodedVideoFrameMetadata {
+dictionary RTCEncodedVideoFrameMetadata : RTCEncodedFrameMetadata {
unsigned long long frameId;
sequence dependencies;
unsigned short width;
unsigned short height;
unsigned long spatialIndex;
unsigned long temporalIndex;
- unsigned long synchronizationSource;
- octet payloadType;
- sequence contributingSources;
long long timestamp; // microseconds
- unsigned long rtpTimestamp;
- DOMHighResTimeStamp receiveTime;
- DOMHighResTimeStamp captureTime;
- DOMHighResTimeStamp senderCaptureTimeOffset;
- DOMString mimeType;
};
dictionary RTCEncodedVideoFrameOptions {
@@ -95,16 +108,9 @@ interface RTCEncodedVideoFrame {
RTCEncodedVideoFrameMetadata getMetadata();
};
-dictionary RTCEncodedAudioFrameMetadata {
- unsigned long synchronizationSource;
- octet payloadType;
- sequence contributingSources;
+dictionary RTCEncodedAudioFrameMetadata : RTCEncodedFrameMetadata {
short sequenceNumber;
- unsigned long rtpTimestamp;
- DOMHighResTimeStamp receiveTime;
- DOMHighResTimeStamp captureTime;
- DOMHighResTimeStamp senderCaptureTimeOffset;
- DOMString mimeType;
+ double audioLevel;
};
dictionary RTCEncodedAudioFrameOptions {
diff --git a/test/fixtures/wpt/interfaces/webrtc-identity.idl b/test/fixtures/wpt/interfaces/webrtc-identity.idl
index 108c3ad9b11..69597acea62 100644
--- a/test/fixtures/wpt/interfaces/webrtc-identity.idl
+++ b/test/fixtures/wpt/interfaces/webrtc-identity.idl
@@ -19,7 +19,7 @@ dictionary RTCIdentityProvider {
};
callback GenerateAssertionCallback = Promise
-(DOMString contents, DOMString origin, RTCIdentityProviderOptions options);
+(DOMString contents, DOMString origin, optional RTCIdentityProviderOptions options = {});
callback ValidateAssertionCallback = Promise
(DOMString assertion, DOMString origin);
diff --git a/test/fixtures/wpt/interfaces/webrtc-stats.idl b/test/fixtures/wpt/interfaces/webrtc-stats.idl
index ac820c7c9dc..b5eff2d0bf5 100644
--- a/test/fixtures/wpt/interfaces/webrtc-stats.idl
+++ b/test/fixtures/wpt/interfaces/webrtc-stats.idl
@@ -38,6 +38,10 @@ dictionary RTCCodecStats : RTCStats {
dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats {
unsigned long long packetsReceived;
+ unsigned long long packetsReceivedWithEct1;
+ unsigned long long packetsReceivedWithCe;
+ unsigned long long packetsReportedAsLost;
+ unsigned long long packetsReportedAsLostButRecovered;
long long packetsLost;
double jitter;
};
@@ -107,11 +111,12 @@ dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
double totalRoundTripTime;
double fractionLost;
unsigned long long roundTripTimeMeasurements;
+ unsigned long long packetsWithBleachedEct1Marking;
};
dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
- unsigned long long packetsSent;
- unsigned long long bytesSent;
+ unsigned long long packetsSent;
+ unsigned long long bytesSent;
};
dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
@@ -119,6 +124,7 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
DOMString mediaSourceId;
DOMString remoteId;
DOMString rid;
+ unsigned long encodingIndex;
unsigned long long headerBytesSent;
unsigned long long retransmittedPacketsSent;
unsigned long long retransmittedBytesSent;
@@ -133,6 +139,8 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
unsigned long framesEncoded;
unsigned long keyFramesEncoded;
unsigned long long qpSum;
+ record psnrSum;
+ unsigned long long psnrMeasurements;
double totalEncodeTime;
double totalPacketSendDelay;
RTCQualityLimitationReason qualityLimitationReason;
@@ -145,6 +153,7 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
boolean powerEfficientEncoder;
boolean active;
DOMString scalabilityMode;
+ unsigned long long packetsSentWithEct1;
};
enum RTCQualityLimitationReason {
@@ -225,6 +234,8 @@ dictionary RTCTransportStats : RTCStats {
RTCDtlsRole dtlsRole;
DOMString srtpCipher;
unsigned long selectedCandidatePairChanges;
+ unsigned long ccfbMessagesSent;
+ unsigned long ccfbMessagesReceived;
};
enum RTCDtlsRole {
diff --git a/test/fixtures/wpt/interfaces/webrtc.idl b/test/fixtures/wpt/interfaces/webrtc.idl
index 174ead6261c..4a651551f14 100644
--- a/test/fixtures/wpt/interfaces/webrtc.idl
+++ b/test/fixtures/wpt/interfaces/webrtc.idl
@@ -13,7 +13,7 @@ dictionary RTCConfiguration {
};
dictionary RTCIceServer {
- required (DOMString or sequence) urls;
+ required (USVString or sequence) urls;
DOMString username;
DOMString credential;
};
@@ -163,7 +163,7 @@ dictionary RTCLocalSessionDescriptionInit {
[Exposed=Window]
interface RTCIceCandidate {
- constructor(optional RTCIceCandidateInit candidateInitDict = {});
+ constructor(optional RTCLocalIceCandidateInit candidateInitDict = {});
readonly attribute DOMString candidate;
readonly attribute DOMString? sdpMid;
readonly attribute unsigned short? sdpMLineIndex;
@@ -179,7 +179,7 @@ interface RTCIceCandidate {
readonly attribute unsigned short? relatedPort;
readonly attribute DOMString? usernameFragment;
readonly attribute RTCIceServerTransportProtocol? relayProtocol;
- readonly attribute DOMString? url;
+ readonly attribute USVString? url;
RTCIceCandidateInit toJSON();
};
@@ -190,6 +190,11 @@ dictionary RTCIceCandidateInit {
DOMString? usernameFragment = null;
};
+dictionary RTCLocalIceCandidateInit : RTCIceCandidateInit {
+ RTCIceServerTransportProtocol? relayProtocol = null;
+ USVString? url = null;
+};
+
enum RTCIceProtocol {
"udp",
"tcp"
@@ -218,12 +223,12 @@ enum RTCIceServerTransportProtocol {
interface RTCPeerConnectionIceEvent : Event {
constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict = {});
readonly attribute RTCIceCandidate? candidate;
- readonly attribute DOMString? url;
+ readonly attribute USVString? url;
};
dictionary RTCPeerConnectionIceEventInit : EventInit {
RTCIceCandidate? candidate;
- DOMString? url;
+ USVString? url;
};
[Exposed=Window]
@@ -231,7 +236,7 @@ interface RTCPeerConnectionIceErrorEvent : Event {
constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict);
readonly attribute DOMString? address;
readonly attribute unsigned short? port;
- readonly attribute DOMString url;
+ readonly attribute USVString url;
readonly attribute unsigned short errorCode;
readonly attribute USVString errorText;
};
@@ -239,7 +244,7 @@ interface RTCPeerConnectionIceErrorEvent : Event {
dictionary RTCPeerConnectionIceErrorEventInit : EventInit {
DOMString? address;
unsigned short? port;
- DOMString url;
+ USVString url;
required unsigned short errorCode;
USVString errorText;
};
diff --git a/test/fixtures/wpt/interfaces/webtransport.idl b/test/fixtures/wpt/interfaces/webtransport.idl
index eb456336081..e49791cdef0 100644
--- a/test/fixtures/wpt/interfaces/webtransport.idl
+++ b/test/fixtures/wpt/interfaces/webtransport.idl
@@ -14,7 +14,6 @@ interface WebTransportDatagramDuplexStream {
WebTransportDatagramsWritable createWritable(
optional WebTransportSendOptions options = {});
readonly attribute ReadableStream readable;
- readonly attribute WebTransportDatagramsWritable writable;
readonly attribute unsigned long maxDatagramSize;
attribute unrestricted double? incomingMaxAge;
@@ -28,6 +27,7 @@ interface WebTransport {
constructor(USVString url, optional WebTransportOptions options = {});
Promise getStats();
+ [NewObject] Promise exportKeyingMaterial(BufferSource label, optional BufferSource context);
readonly attribute Promise ready;
readonly attribute WebTransportReliabilityMode reliability;
readonly attribute WebTransportCongestionControl congestionControl;
@@ -74,6 +74,7 @@ dictionary WebTransportOptions {
[EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams = null;
[EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams = null;
sequence protocols = [];
+ DatagramsReadableMode datagramsReadableMode;
};
enum WebTransportCongestionControl {
@@ -82,6 +83,8 @@ enum WebTransportCongestionControl {
"low-latency",
};
+enum DatagramsReadableMode { "bytes" };
+
dictionary WebTransportCloseInfo {
unsigned long closeCode = 0;
USVString reason = "";
@@ -156,6 +159,7 @@ interface WebTransportBidirectionalStream {
[Exposed=*, SecureContext]
interface WebTransportWriter : WritableStreamDefaultWriter {
Promise atomicWrite(optional any chunk);
+ undefined commit();
};
[Exposed=(Window,Worker), Serializable, SecureContext]
diff --git a/test/fixtures/wpt/interfaces/webxr-depth-sensing.idl b/test/fixtures/wpt/interfaces/webxr-depth-sensing.idl
index b77b59c0ce6..7ddbec7cc97 100644
--- a/test/fixtures/wpt/interfaces/webxr-depth-sensing.idl
+++ b/test/fixtures/wpt/interfaces/webxr-depth-sensing.idl
@@ -3,6 +3,11 @@
// (https://github.com/w3c/webref)
// Source: WebXR Depth Sensing Module (https://immersive-web.github.io/depth-sensing/)
+enum XRDepthType {
+ "raw",
+ "smooth",
+};
+
enum XRDepthUsage {
"cpu-optimized",
"gpu-optimized",
@@ -17,6 +22,8 @@ enum XRDepthDataFormat {
dictionary XRDepthStateInit {
required sequence usagePreference;
required sequence dataFormatPreference;
+ sequence depthTypeRequest;
+ boolean matchDepthView = true;
};
partial dictionary XRSessionInit {
@@ -26,6 +33,11 @@ partial dictionary XRSessionInit {
partial interface XRSession {
readonly attribute XRDepthUsage depthUsage;
readonly attribute XRDepthDataFormat depthDataFormat;
+ readonly attribute XRDepthType? depthType;
+ readonly attribute boolean? depthActive;
+
+ undefined pauseDepthSensing();
+ undefined resumeDepthSensing();
};
[SecureContext, Exposed=Window]
@@ -37,6 +49,8 @@ interface XRDepthInformation {
readonly attribute float rawValueToMeters;
};
+XRDepthInformation includes XRViewGeometry;
+
[Exposed=Window]
interface XRCPUDepthInformation : XRDepthInformation {
[SameObject] readonly attribute ArrayBuffer data;
diff --git a/test/fixtures/wpt/interfaces/webxr.idl b/test/fixtures/wpt/interfaces/webxr.idl
index dea448d7440..874994086a2 100644
--- a/test/fixtures/wpt/interfaces/webxr.idl
+++ b/test/fixtures/wpt/interfaces/webxr.idl
@@ -70,6 +70,7 @@ enum XRVisibilityState {
dictionary XRRenderStateInit {
double depthNear;
double depthFar;
+ boolean passthroughFullyObscured;
double inlineVerticalFieldOfView;
XRWebGLLayer? baseLayer;
sequence? layers;
@@ -78,6 +79,7 @@ dictionary XRRenderStateInit {
[SecureContext, Exposed=Window] interface XRRenderState {
readonly attribute double depthNear;
readonly attribute double depthFar;
+ readonly attribute boolean? passthroughFullyObscured;
readonly attribute double? inlineVerticalFieldOfView;
readonly attribute XRWebGLLayer? baseLayer;
};
@@ -116,6 +118,11 @@ interface XRBoundedReferenceSpace : XRReferenceSpace {
readonly attribute FrozenArray boundsGeometry;
};
+[SecureContext, Exposed=Window] interface mixin XRViewGeometry {
+ readonly attribute Float32Array projectionMatrix;
+ [SameObject] readonly attribute XRRigidTransform transform;
+};
+
enum XREye {
"none",
"left",
@@ -124,13 +131,13 @@ enum XREye {
[SecureContext, Exposed=Window] interface XRView {
readonly attribute XREye eye;
- readonly attribute Float32Array projectionMatrix;
- [SameObject] readonly attribute XRRigidTransform transform;
readonly attribute double? recommendedViewportScale;
undefined requestViewportScale(double? scale);
};
+XRView includes XRViewGeometry;
+
[SecureContext, Exposed=Window] interface XRViewport {
readonly attribute long x;
readonly attribute long y;
diff --git a/test/fixtures/wpt/interfaces/webxrlayers.idl b/test/fixtures/wpt/interfaces/webxrlayers.idl
index c8b3a71c699..b99bef707fb 100644
--- a/test/fixtures/wpt/interfaces/webxrlayers.idl
+++ b/test/fixtures/wpt/interfaces/webxrlayers.idl
@@ -170,6 +170,8 @@ dictionary XRCubeLayerInit : XRLayerInit {
XRWebGLSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none");
XRWebGLSubImage getViewSubImage(XRProjectionLayer layer, XRView view);
+
+ undefined foveateBoundTexture(GLenum target, float fixed_foveation);
};
dictionary XRMediaLayerInit {
diff --git a/test/fixtures/wpt/interfaces/writing-assistance-apis.idl b/test/fixtures/wpt/interfaces/writing-assistance-apis.idl
new file mode 100644
index 00000000000..82acfdb48e2
--- /dev/null
+++ b/test/fixtures/wpt/interfaces/writing-assistance-apis.idl
@@ -0,0 +1,193 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Writing Assistance APIs (https://webmachinelearning.github.io/writing-assistance-apis/)
+
+[Exposed=Window, SecureContext]
+interface Summarizer {
+ static Promise create(optional SummarizerCreateOptions options = {});
+ static Promise availability(optional SummarizerCreateCoreOptions options = {});
+
+ Promise summarize(
+ DOMString input,
+ optional SummarizerSummarizeOptions options = {}
+ );
+ ReadableStream summarizeStreaming(
+ DOMString input,
+ optional SummarizerSummarizeOptions options = {}
+ );
+
+ readonly attribute DOMString sharedContext;
+ readonly attribute SummarizerType type;
+ readonly attribute SummarizerFormat format;
+ readonly attribute SummarizerLength length;
+
+ readonly attribute FrozenArray? expectedInputLanguages;
+ readonly attribute FrozenArray? expectedContextLanguages;
+ readonly attribute DOMString? outputLanguage;
+
+ Promise measureInputUsage(
+ DOMString input,
+ optional SummarizerSummarizeOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+Summarizer includes DestroyableModel;
+
+dictionary SummarizerCreateCoreOptions {
+ SummarizerType type = "key-points";
+ SummarizerFormat format = "markdown";
+ SummarizerLength length = "short";
+
+ sequence expectedInputLanguages;
+ sequence expectedContextLanguages;
+ DOMString outputLanguage;
+};
+
+dictionary SummarizerCreateOptions : SummarizerCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+
+ DOMString sharedContext;
+};
+
+dictionary SummarizerSummarizeOptions {
+ AbortSignal signal;
+ DOMString context;
+};
+
+enum SummarizerType { "tldr", "teaser", "key-points", "headline" };
+enum SummarizerFormat { "plain-text", "markdown" };
+enum SummarizerLength { "short", "medium", "long" };
+
+[Exposed=Window, SecureContext]
+interface Writer {
+ static Promise create(optional WriterCreateOptions options = {});
+ static Promise availability(optional WriterCreateCoreOptions options = {});
+
+ Promise write(
+ DOMString input,
+ optional WriterWriteOptions options = {}
+ );
+ ReadableStream writeStreaming(
+ DOMString input,
+ optional WriterWriteOptions options = {}
+ );
+
+ readonly attribute DOMString sharedContext;
+ readonly attribute WriterTone tone;
+ readonly attribute WriterFormat format;
+ readonly attribute WriterLength length;
+
+ readonly attribute FrozenArray? expectedInputLanguages;
+ readonly attribute FrozenArray? expectedContextLanguages;
+ readonly attribute DOMString? outputLanguage;
+
+ Promise measureInputUsage(
+ DOMString input,
+ optional WriterWriteOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+Writer includes DestroyableModel;
+
+dictionary WriterCreateCoreOptions {
+ WriterTone tone = "neutral";
+ WriterFormat format = "markdown";
+ WriterLength length = "short";
+
+ sequence expectedInputLanguages;
+ sequence expectedContextLanguages;
+ DOMString outputLanguage;
+};
+
+dictionary WriterCreateOptions : WriterCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+
+ DOMString sharedContext;
+};
+
+dictionary WriterWriteOptions {
+ DOMString context;
+ AbortSignal signal;
+};
+
+enum WriterTone { "formal", "neutral", "casual" };
+enum WriterFormat { "plain-text", "markdown" };
+enum WriterLength { "short", "medium", "long" };
+
+[Exposed=Window, SecureContext]
+interface Rewriter {
+ static Promise create(optional RewriterCreateOptions options = {});
+ static Promise availability(optional RewriterCreateCoreOptions options = {});
+
+ Promise rewrite(
+ DOMString input,
+ optional RewriterRewriteOptions options = {}
+ );
+ ReadableStream rewriteStreaming(
+ DOMString input,
+ optional RewriterRewriteOptions options = {}
+ );
+
+ readonly attribute DOMString sharedContext;
+ readonly attribute RewriterTone tone;
+ readonly attribute RewriterFormat format;
+ readonly attribute RewriterLength length;
+
+ readonly attribute FrozenArray? expectedInputLanguages;
+ readonly attribute FrozenArray? expectedContextLanguages;
+ readonly attribute DOMString? outputLanguage;
+
+ Promise measureInputUsage(
+ DOMString input,
+ optional RewriterRewriteOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+Rewriter includes DestroyableModel;
+
+dictionary RewriterCreateCoreOptions {
+ RewriterTone tone = "as-is";
+ RewriterFormat format = "as-is";
+ RewriterLength length = "as-is";
+
+ sequence expectedInputLanguages;
+ sequence expectedContextLanguages;
+ DOMString outputLanguage;
+};
+
+dictionary RewriterCreateOptions : RewriterCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+
+ DOMString sharedContext;
+};
+
+dictionary RewriterRewriteOptions {
+ DOMString context;
+ AbortSignal signal;
+};
+
+enum RewriterTone { "as-is", "more-formal", "more-casual" };
+enum RewriterFormat { "as-is", "plain-text", "markdown" };
+enum RewriterLength { "as-is", "shorter", "longer" };
+
+[Exposed=Window, SecureContext]
+interface CreateMonitor : EventTarget {
+ attribute EventHandler ondownloadprogress;
+};
+
+callback CreateMonitorCallback = undefined (CreateMonitor monitor);
+
+enum Availability {
+ "unavailable",
+ "downloadable",
+ "downloading",
+ "available"
+};
+
+interface mixin DestroyableModel {
+ undefined destroy();
+};
diff --git a/test/fixtures/wpt/resources/check-layout-th.js b/test/fixtures/wpt/resources/check-layout-th.js
index 54ddb35f311..2965a25d146 100644
--- a/test/fixtures/wpt/resources/check-layout-th.js
+++ b/test/fixtures/wpt/resources/check-layout-th.js
@@ -218,7 +218,7 @@ window.checkLayout = function(selectorList, callDone = true)
nodes = Array.prototype.slice.call(nodes);
var checkedLayout = false;
Array.prototype.forEach.call(nodes, function(node) {
- const title = node.title == '' ? '' : `: ${node.title}`;
+ const title = node.title ? `: ${node.title}` : '';
test(function(t) {
var container = node.parentNode.className == 'container' ? node.parentNode : node;
var prefix =
diff --git a/test/fixtures/wpt/resources/chromium/webxr-test.js b/test/fixtures/wpt/resources/chromium/webxr-test.js
index 15d015debb1..ece15d9fbec 100644
--- a/test/fixtures/wpt/resources/chromium/webxr-test.js
+++ b/test/fixtures/wpt/resources/chromium/webxr-test.js
@@ -355,6 +355,23 @@ class MockRuntime {
"world-space": vrMojom.XRInteractionMode.kWorldSpace,
};
+ static _depthTypeToMojoMap = {
+ "raw": xrSessionMojom.XRDepthType.kRawDepth,
+ "smooth": xrSessionMojom.XRDepthType.kSmoothDepth,
+ };
+
+ static _depthUsageToMojoMap = {
+ "cpu-optimized": xrSessionMojom.XRDepthUsage.kCPUOptimized,
+ "gpu-optimized": xrSessionMojom.XRDepthUsage.kGPUOptimized,
+ };
+
+ static _depthDataFormatToMojoMap = {
+ "luminance-alpha": xrSessionMojom.XRDepthDataFormat.kLuminanceAlpha,
+ "float32": xrSessionMojom.XRDepthDataFormat.kFloat32,
+ "unsigned-short": xrSessionMojom.XRDepthDataFormat.kUnsignedShort,
+ };
+
+
constructor(fakeDeviceInit, service) {
this.sessionClient_ = null;
this.presentation_provider_ = new MockXRPresentationProvider();
@@ -439,6 +456,8 @@ class MockRuntime {
this.setViews(fakeDeviceInit.views, fakeDeviceInit.secondaryViews);
+ this._setDepthSupport(fakeDeviceInit.depthSupport || {});
+
// Need to support webVR which doesn't have a notion of features
this._setFeatures(fakeDeviceInit.supportedFeatures || []);
}
@@ -658,6 +677,32 @@ class MockRuntime {
}
// WebXR Test API depth Sensing Extensions
+ _setDepthSupport(depthSupport) {
+ this.depthSupport_ = {};
+
+ this.depthSupport_.depthTypes = [];
+ for (const type of (depthSupport.depthTypes || [])) {
+ this.depthSupport_.depthTypes.push(MockRuntime._depthTypeToMojoMap[type]);
+ }
+
+ this.depthSupport_.depthFormats = [];
+ for (const format of (depthSupport.depthFormats || [])) {
+ this.depthSupport_.depthFormats.push(MockRuntime._depthDataFormatToMojoMap[format]);
+ }
+
+ this.depthSupport_.depthUsages = [];
+ for (const usage of (depthSupport.depthUsages || [])) {
+ // Because chrome doesn't support gpu-optimized for any devices at present
+ // avoid "false positive" WPTs by indicating that we don't support
+ // gpu-optimized.
+ if (usage === "gpu-optimized") {
+ continue;
+ }
+
+ this.depthSupport_.depthUsages.push(MockRuntime._depthUsageToMojoMap[usage]);
+ }
+ }
+
setDepthSensingData(depthSensingData) {
for(const key of ["depthData", "normDepthBufferFromNormView", "rawValueToMeters", "width", "height"]) {
if(!(key in depthSensingData)) {
@@ -757,34 +802,58 @@ class MockRuntime {
const viewport_size = 20;
return [{
eye: vrMojom.XREye.kLeft,
- fieldOfView: {
- upDegrees: 48.316,
- downDegrees: 50.099,
- leftDegrees: 50.899,
- rightDegrees: 35.197
+ geometry: {
+ fieldOfView: {
+ upDegrees: 48.316,
+ downDegrees: 50.099,
+ leftDegrees: 50.899,
+ rightDegrees: 35.197
+ },
+ mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform({
+ position: [-0.032, 0, 0],
+ orientation: [0, 0, 0, 1]
+ }))
},
- mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform({
- position: [-0.032, 0, 0],
- orientation: [0, 0, 0, 1]
- })),
viewport: { x: 0, y: 0, width: viewport_size, height: viewport_size }
},
{
eye: vrMojom.XREye.kRight,
- fieldOfView: {
- upDegrees: 48.316,
- downDegrees: 50.099,
- leftDegrees: 50.899,
- rightDegrees: 35.197
+ geometry: {
+ fieldOfView: {
+ upDegrees: 48.316,
+ downDegrees: 50.099,
+ leftDegrees: 50.899,
+ rightDegrees: 35.197
+ },
+ mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform({
+ position: [0.032, 0, 0],
+ orientation: [0, 0, 0, 1]
+ }))
},
- mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform({
- position: [0.032, 0, 0],
- orientation: [0, 0, 0, 1]
- })),
viewport: { x: viewport_size, y: 0, width: viewport_size, height: viewport_size }
}];
}
+ _getFovFromProjectionMatrix(projectionMatrix) {
+ const m = projectionMatrix;
+
+ function toDegrees(tan) {
+ return Math.atan(tan) * 180 / Math.PI;
+ }
+
+ const leftTan = (1 - m[8]) / m[0];
+ const rightTan = (1 + m[8]) / m[0];
+ const upTan = (1 + m[9]) / m[5];
+ const downTan = (1 - m[9]) / m[5];
+
+ return {
+ upDegrees: toDegrees(upTan),
+ downDegrees: toDegrees(downTan),
+ leftDegrees: toDegrees(leftTan),
+ rightDegrees: toDegrees(rightTan)
+ };
+ }
+
// This function converts between the matrix provided by the WebXR test API
// and the internal data representation.
_getView(fakeXRViewInit, xOffset) {
@@ -798,23 +867,7 @@ class MockRuntime {
rightDegrees: fakeXRViewInit.fieldOfView.rightDegrees
};
} else {
- const m = fakeXRViewInit.projectionMatrix;
-
- function toDegrees(tan) {
- return Math.atan(tan) * 180 / Math.PI;
- }
-
- const leftTan = (1 - m[8]) / m[0];
- const rightTan = (1 + m[8]) / m[0];
- const upTan = (1 + m[9]) / m[5];
- const downTan = (1 - m[9]) / m[5];
-
- fov = {
- upDegrees: toDegrees(upTan),
- downDegrees: toDegrees(downTan),
- leftDegrees: toDegrees(leftTan),
- rightDegrees: toDegrees(rightTan)
- };
+ fov = this._getFovFromProjectionMatrix(fakeXRViewInit.projectionMatrix);
}
let viewEye = vrMojom.XREye.kNone;
@@ -835,13 +888,18 @@ class MockRuntime {
return {
eye: viewEye,
- fieldOfView: fov,
- mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform(fakeXRViewInit.viewOffset)),
+ geometry: {
+ fieldOfView: fov,
+ mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform(fakeXRViewInit.viewOffset)),
+ // Mojo will ignore extra members, we stash the raw projection matrix
+ // here for ease of use with the depth extensions.
+ projectionMatrix: fakeXRViewInit.projectionMatrix,
+ },
viewport: {
x: xOffset,
- y: 0,
- width: fakeXRViewInit.resolution.width,
- height: fakeXRViewInit.resolution.height
+ y: 0,
+ width: fakeXRViewInit.resolution.width,
+ height: fakeXRViewInit.resolution.height
},
isFirstPersonObserver: fakeXRViewInit.isFirstPersonObserver ? true : false,
viewOffset: composeGFXTransform(fakeXRViewInit.viewOffset)
@@ -915,12 +973,12 @@ class MockRuntime {
let frame_views = this.primaryViews_;
for (let i = 0; i < this.primaryViews_.length; i++) {
- this.primaryViews_[i].mojoFromView =
+ this.primaryViews_[i].geometry.mojoFromView =
this._getMojoFromViewerWithOffset(this.primaryViews_[i].viewOffset);
}
if (this.enabledFeatures_.includes(xrSessionMojom.XRSessionFeature.SECONDARY_VIEWS)) {
for (let i = 0; i < this.secondaryViews_.length; i++) {
- this.secondaryViews_[i].mojoFromView =
+ this.secondaryViews_[i].geometry.mojoFromView =
this._getMojoFromViewerWithOffset(this.secondaryViews_[i].viewOffset);
}
@@ -956,7 +1014,9 @@ class MockRuntime {
this._calculateAnchorInformation(frameData);
- this._calculateDepthInformation(frameData);
+ if (options.depthActive) {
+ this._calculateDepthInformation(frameData);
+ }
this._injectAdditionalFrameData(options, frameData);
@@ -1191,7 +1251,7 @@ class MockRuntime {
const enabled_features = [];
for (let i = 0; i < sessionOptions.requiredFeatures.length; i++) {
const feature = sessionOptions.requiredFeatures[i];
- if (this._runtimeSupportsFeature(feature, sessionOptions)) {
+ if (this._maybeEnableFeature(feature, sessionOptions)) {
enabled_features.push(feature);
} else {
return Promise.resolve({session: null});
@@ -1200,7 +1260,7 @@ class MockRuntime {
for (let i =0; i < sessionOptions.optionalFeatures.length; i++) {
const feature = sessionOptions.optionalFeatures[i];
- if (this._runtimeSupportsFeature(feature, sessionOptions)) {
+ if (this._maybeEnableFeature(feature, sessionOptions)) {
enabled_features.push(feature);
}
}
@@ -1216,14 +1276,8 @@ class MockRuntime {
deviceConfig: {
defaultFramebufferScale: this.defaultFramebufferScale_,
supportsViewportScaling: true,
- depthConfiguration: enabled_features.includes(
- xrSessionMojom.XRSessionFeature.DEPTH) ?
- {
- depthUsage: xrSessionMojom.XRDepthUsage.kCPUOptimized,
- depthDataFormat:
- xrSessionMojom.XRDepthDataFormat.kLuminanceAlpha,
- } :
- null,
+ // If depth was not enabled above, this should be null.
+ depthConfiguration: this.depthConfiguration_,
views: this._getDefaultViews(),
},
enviromentBlendMode: this.enviromentBlendMode_,
@@ -1243,21 +1297,67 @@ class MockRuntime {
});
}
- _runtimeSupportsFeature(feature, options) {
+ _tryGetDepthConfig(options) {
+ if (!options.depthOptions) {
+ return null;
+ }
+
+ // At present, there are only two depth usages, and we only support CPU.
+ if (options.depthOptions.usagePreferences.length !== 0 &&
+ !options.depthOptions.usagePreferences.includes(
+ xrSessionMojom.XRDepthUsage.kCPUOptimized)) {
+ return null;
+ }
+ const selectedUsage = xrSessionMojom.XRDepthUsage.kCPUOptimized;
+
+ let selectedFormat = null;
+ if (options.depthOptions.dataFormatPreferences.length === 0) {
+ selectedFormat = this.depthSupport_.depthFormats.length === 0 ?
+ xrSessionMojom.XRDepthDataFormat.kLuminanceAlpha : this.depthSupport_.depthFormats[0];
+ } else {
+ for (const dataFormatRequest of options.depthOptions.dataFormatPreferences) {
+ if (this.depthSupport_.depthFormats.length === 0 ||
+ this.depthSupport_.depthFormats.includes(dataFormatRequest)) {
+ selectedFormat = dataFormatRequest;
+ break;
+ }
+ }
+ }
+
+ if (selectedFormat === null) {
+ return null;
+ }
+
+ // Default to our first supported depth type. If it's empty (meaning all),
+ // then just default to raw.
+ let selectedDepthType = this.depthSupport_.depthTypes.length === 0 ?
+ xrSessionMojom.XRDepthType.kRawDepth : this.depthSupport_.depthTypes[0];
+ // Try to set the depthType to the earliest requested one if it's supported.
+ for (const depthTypeRequest of options.depthOptions.depthTypeRequest) {
+ if (this.depthSupport_.depthTypes.length === 0 ||
+ this.depthSupport_.depthTypes.includes(depthTypeRequest)) {
+ selectedDepthType = depthTypeRequest;
+ break;
+ }
+ }
+
+ return {
+ depthUsage: selectedUsage,
+ depthDataFormat: selectedFormat,
+ depthType: selectedDepthType,
+ };
+ }
+
+ _maybeEnableFeature(feature, options) {
if (this.supportedFeatures_.indexOf(feature) === -1) {
return false;
}
switch (feature) {
case xrSessionMojom.XRSessionFeature.DEPTH:
- // This matches what Chrome can currently support.
- return options.depthOptions &&
- (options.depthOptions.usagePreferences.length == 0 ||
- options.depthOptions.usagePreferences.includes(
- xrSessionMojom.XRDepthUsage.kCPUOptimized)) &&
- (options.depthOptions.dataFormatPreferences.length == 0 ||
- options.depthOptions.dataFormatPreferences.includes(
- xrSessionMojom.XRDepthDataFormat.kLuminanceAlpha));
+ this.depthConfiguration_ = this._tryGetDepthConfig(options);
+ this.matchDepthView_ = options.depthOptions && options.depthOptions.matchDepthView;
+ return this.depthConfiguration_ != null;
default:
return true;
}
@@ -1317,6 +1417,179 @@ class MockRuntime {
// Private functions - depth sensing implementation:
+ /**
+ * Helper to get a TypedArray view for a given depth format.
+ * @param {ArrayBuffer} buffer The ArrayBuffer.
+ * @param {xrSessionMojom.XRDepthDataFormat} format The depth format.
+ * @return {Uint16Array|Float32Array} A typed array view.
+ */
+ static _getTypedArrayForFormat(buffer, format) {
+ if (format === xrSessionMojom.XRDepthDataFormat.kFloat32) {
+ return new Float32Array(buffer);
+ } else { // "luminance-alpha" or "unsigned-short"
+ return new Uint16Array(buffer);
+ }
+ }
+
+ /**
+ * Helper to get a TypedArray for the given depth format.
+ * @param {xrSessionMojom.XRDepthDataFormat} format - The Depth format
+ * @param {number} size - The size of the array to be created.
+ * @return {Uint16Array|Float32Array} A typed array view.
+ */
+ static _getEmptyTypedArrayForFormat(format, size) {
+ if (format === xrSessionMojom.XRDepthDataFormat.kFloat32) {
+ return new Float32Array(size).fill(0.0);
+ } else { // "luminance-alpha" or "unsigned-short" (Uint16)
+ return new Uint16Array(size).fill(0);
+ }
+ }
+
+ /**
+ * Reprojects depth data from a source view to a target view.
+ * The returned array will be the same width/height, but will be returned as a
+ * Uint8Array of the targetFormat (essentially a byte array that can be sent
+ * across mojo), so the overall returned size may be different.
+ *
+ * @param {ArrayBuffer} sourceDepthArrayBuffer - Raw depth data for the source.
+ * @param {number} width - Width of the depth data.
+ * @param {number} height - Height of the depth data.
+ * @param {xrSessionMojom.XRDepthDataFormat} sourceFormatEnum - Format of the source depth data.
+ * @param {Float32Array} sourceClipFromSourceView - Projection matrix for the source view.
+ * @param {Float32Array} mojoFromSourceView- Matrix of the transform for the source view.
+ * @param {xrSessionMojom.XRDepthDataFormat} targetFormatEnum - Format of the target depth data.
+ * @param {Float32Array} targetClipFromTargetView - Projection matrix for the target view.
+ * @param {Float32Array} mojoFromTargetView - Matrix of the transform for the target view.
+ * @return {Uint8Array | null} The reprojected depth data as an Uint8Array, or null on matrix error.
+ */
+ static copyDepthData(
+ sourceDepthArrayBuffer, width, height, sourceFormatEnum,
+ sourceClipFromSourceView, mojoFromSourceView,
+ targetFormatEnum,
+ targetClipFromTargetView, mojoFromTargetView) {
+
+ const targetViewFromTargetClip = XRMathHelper.inverse(targetClipFromTargetView);
+ const sourceViewFromMojo = XRMathHelper.inverse(mojoFromSourceView);
+
+ // Check if any matrices were not supplied or matrix inversions failed.
+ if (!targetViewFromTargetClip || !sourceViewFromMojo || !mojoFromTargetView) {
+ return null;
+ }
+
+ // Build the full transformation from Target Clip space to Source Clip space.
+ const mojoFromTargetClip = XRMathHelper.mul4x4(mojoFromTargetView, targetViewFromTargetClip);
+ if (!mojoFromTargetClip) return null;
+
+ const sourceViewFromTargetClip = XRMathHelper.mul4x4(sourceViewFromMojo, mojoFromTargetClip);
+ if (!sourceViewFromTargetClip) return null;
+
+ const sourceClipFromTargetClip = XRMathHelper.mul4x4(sourceClipFromSourceView, sourceViewFromTargetClip);
+ if (!sourceClipFromTargetClip) return null;
+
+ const sourceTypedArray = MockRuntime._getTypedArrayForFormat(sourceDepthArrayBuffer, sourceFormatEnum);
+ let internalTargetDepthTypedArray = MockRuntime._getEmptyTypedArrayForFormat(targetFormatEnum, width * height);
+
+ // Iterate over target pixels (Backward Mapping)
+ for (let ty = 0; ty < height; ++ty) {
+ for (let tx = 0; tx < width; ++tx) {
+ // Convert target pixel (tx, ty) to target NDC coordinates
+ const u_tgt_pixel = (tx + 0.5) / width; // u in [0, 1], Y-down from top-left
+ const v_tgt_pixel = (ty + 0.5) / height; // v in [0, 1], Y-down from top-left
+
+ const ndc_x_tgt = u_tgt_pixel * 2.0 - 1.0; // NDC X in [-1, 1]
+ const ndc_y_tgt = 1.0 - v_tgt_pixel * 2.0; // NDC Y in [-1, 1], Y-up
+
+ // Define a point on the near plane in target clip space
+ const P_clip_tgt = { x: ndc_x_tgt, y: ndc_y_tgt, z: -1.0, w: 1.0 };
+
+ // Transform this point to source clip space
+ const P_clip_src = XRMathHelper.transform_by_matrix(sourceClipFromTargetClip, P_clip_tgt);
+
+ // Homogenize to get source NDC coordinates
+ if (Math.abs(P_clip_src.w) < XRMathHelper.EPSILON) {
+ internalTargetDepthTypedArray[ty * width + tx] = 0; // Cannot project
+ continue;
+ }
+ const ndc_x_src = P_clip_src.x / P_clip_src.w;
+ const ndc_y_src = P_clip_src.y / P_clip_src.w;
+
+ // Convert source NDC to source pixel coordinates
+ const u_src_pixel = (ndc_x_src + 1.0) / 2.0;
+ const v_src_pixel = (1.0 - ndc_y_src) / 2.0; // Convert source NDC Y-up to pixel Y-down
+
+ const sx = Math.floor(u_src_pixel * width);
+ const sy = Math.floor(v_src_pixel * height);
+
+ let target_raw_depth = 0; // Default to 0 (no data)
+
+ // Check if the calculated source pixel is within bounds
+ if (sx >= 0 && sx < width && sy >= 0 && sy < height) {
+ const source_raw_value = sourceTypedArray[sy * width + sx];
+
+ let isValidSourceDepth = false;
+ if (sourceFormatEnum === xrSessionMojom.XRDepthDataFormat.kFloat32) {
+ if (source_raw_value > 0 && isFinite(source_raw_value)) {
+ isValidSourceDepth = true;
+ }
+ } else { // Uint16 source
+ if (source_raw_value > 0) {
+ isValidSourceDepth = true;
+ }
+ }
+
+ if (isValidSourceDepth) {
+ if (targetFormatEnum === xrSessionMojom.XRDepthDataFormat.kFloat32) {
+ target_raw_depth = source_raw_value;
+ } else {
+ // Clamp to the valid range for Uint16
+ target_raw_depth = Math.max(0, Math.min(0xFFFF, Math.round(source_raw_value)));
+ }
+ }
+ }
+
+ // If not in bounds or source depth invalid, target_raw_depth remains 0.
+ internalTargetDepthTypedArray[ty * width + tx] = target_raw_depth;
+ }
+ }
+
+ return new Uint8Array(internalTargetDepthTypedArray.buffer);
+ }
+
+ _getDepthPixelData(depthGeometry) {
+ if (!this.matchDepthView_ || !depthGeometry) {
+ return { bytes: this.depthSensingData_.depthData };
+ }
+
+ const sourceProjectionMatrix = depthGeometry.projectionMatrix;
+ const sourceViewOffset = depthGeometry.mojoFromView;
+ if (!sourceProjectionMatrix || !sourceViewOffset) {
+ return { bytes: this.depthSensingData_.depthData };
+ }
+
+ if (this.primaryViews_.length === 0) {
+ return { bytes: this.depthSensingData_.depthData };
+ }
+
+ const targetView = this.primaryViews_[0];
+ const targetProjectionMatrix = targetView.geometry.projectionMatrix;
+ const targetViewOffset = targetView.geometry.mojoFromView;
+ if (!targetProjectionMatrix || !targetViewOffset) {
+ return { bytes: this.depthSensingData_.depthData };
+ }
+
+ return { bytes: MockRuntime.copyDepthData(
+ this.depthSensingData_.depthData,
+ this.depthSensingData_.width,
+ this.depthSensingData_.height,
+ MockRuntime._depthDataFormatToMojoMap[this.depthSensingData_.depthFormat],
+ sourceProjectionMatrix,
+ sourceViewOffset.matrix,
+ this.depthConfiguration_.depthDataFormat,
+ targetProjectionMatrix,
+ targetViewOffset.matrix
+ )};
+ }
+
// Modifies passed in frameData to add anchor information.
_calculateDepthInformation(frameData) {
if (!this.supportedModes_.includes(xrSessionMojom.XRSessionMode.kImmersiveAr)) {
@@ -1336,13 +1609,29 @@ class MockRuntime {
} else if(!this.depthSensingDataDirty_) {
newDepthData = { dataStillValid: {}};
} else {
+ let viewGeometry = null;
+ const projectionMatrix = this.depthSensingData_.projectionMatrix;
+ const viewOffset = this.depthSensingData_.viewOffset;
+
+ if (projectionMatrix && viewOffset) {
+ const fov = this._getFovFromProjectionMatrix(projectionMatrix);
+
+ viewGeometry = {
+ fieldOfView: fov,
+ mojoFromView: this._getMojoFromViewerWithOffset(composeGFXTransform(viewOffset)),
+ // Convenience member for `_getDepthPixelData`
+ projectionMatrix: projectionMatrix
+ };
+ }
+
newDepthData = {
updatedDepthData: {
timeDelta: frameData.timeDelta,
normTextureFromNormView: this.depthSensingData_.normDepthBufferFromNormView,
rawValueToMeters: this.depthSensingData_.rawValueToMeters,
size: { width: this.depthSensingData_.width, height: this.depthSensingData_.height },
- pixelData: { bytes: this.depthSensingData_.depthData }
+ pixelData: this._getDepthPixelData(viewGeometry),
+ viewGeometry: this.matchDepthView_ ? null : viewGeometry
}
};
}
diff --git a/test/fixtures/wpt/resources/idlharness.js b/test/fixtures/wpt/resources/idlharness.js
index d52ba9fd3c4..2eb710c1827 100644
--- a/test/fixtures/wpt/resources/idlharness.js
+++ b/test/fixtures/wpt/resources/idlharness.js
@@ -783,6 +783,10 @@ IdlArray.prototype.merge_partials = function()
}
testedPartials.set(parsed_idl.name, partialTestCount);
+ if (!self.shouldRunSubTest(partialTestName)) {
+ return;
+ }
+
if (!parsed_idl.untested) {
test(function () {
assert_true(originalExists, `Original ${parsed_idl.type} should be defined`);
@@ -871,6 +875,7 @@ IdlArray.prototype.merge_mixins = function()
{
const lhs = parsed_idl.target;
const rhs = parsed_idl.includes;
+ const testName = lhs + " includes " + rhs + ": member names are unique";
var errStr = lhs + " includes " + rhs + ", but ";
if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";
@@ -878,7 +883,7 @@ IdlArray.prototype.merge_mixins = function()
if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";
if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";
- if (this.members[rhs].members.length) {
+ if (this.members[rhs].members.length && self.shouldRunSubTest(testName)) {
test(function () {
var clash = this.members[rhs].members.find(function(member) {
return this.members[lhs].members.find(function(m) {
@@ -892,7 +897,7 @@ IdlArray.prototype.merge_mixins = function()
this.members[lhs].members.push(new IdlInterfaceMember(member));
}.bind(this));
assert_true(!clash, "member " + (clash && clash.name) + " is unique");
- }.bind(this), lhs + " includes " + rhs + ": member names are unique");
+ }.bind(this), testName);
}
}
this.includes = [];
diff --git a/test/fixtures/wpt/resources/test/conftest.py b/test/fixtures/wpt/resources/test/conftest.py
index 723087d3184..0b67ca76761 100644
--- a/test/fixtures/wpt/resources/test/conftest.py
+++ b/test/fixtures/wpt/resources/test/conftest.py
@@ -55,6 +55,7 @@ def pytest_configure(config):
config.driver = webdriver.Session("localhost", 4444,
capabilities=capabilities)
+ config.driver.start()
config.add_cleanup(config.driver.end)
# Although the name of the `_create_unverified_context` method suggests
@@ -263,4 +264,4 @@ def _run_functional_test(self):
@staticmethod
def _assert_sequence(nums):
if nums and len(nums) > 0:
- assert nums == list(range(1, nums[-1] + 1))
+ assert nums == list(range(nums[-1] + 1))
diff --git a/test/fixtures/wpt/resources/test/tests/functional/api-tests-1.html b/test/fixtures/wpt/resources/test/tests/functional/api-tests-1.html
index 9de875b0f12..6ec396c221b 100644
--- a/test/fixtures/wpt/resources/test/tests/functional/api-tests-1.html
+++ b/test/fixtures/wpt/resources/test/tests/functional/api-tests-1.html
@@ -132,7 +132,13 @@ Sample HTML5 API Tests
{
assert_less_than(10, 11, "10 is less than 11")
}
- test(basicAssertApproxEquals, "basic assert_less_than test");
+ test(basicAssertLessThan, "basic assert_less_than test");
+
+ function bigintAssertLessThan()
+ {
+ assert_less_than(10n, 11n, "10n is less than 11n")
+ }
+ test(bigintAssertLessThan, "bigint assert_less_than test");
function basicAssertGreaterThan()
{
@@ -140,12 +146,24 @@ Sample HTML5 API Tests
}
test(basicAssertGreaterThan, "assert_greater_than expected to fail");
+ function bigintAssertGreaterThan()
+ {
+ assert_greater_than(10n, 11n, "10n is not greater than 11n");
+ }
+ test(bigintAssertGreaterThan, "bigint assert_greater_than expected to fail");
+
function basicAssertGreaterThanEqual()
{
assert_greater_than_equal(10, 10, "10 is greater than or equal to 10")
}
test(basicAssertGreaterThanEqual, "basic assert_greater_than_equal test");
+ function bigintAssertGreaterThanEqual()
+ {
+ assert_greater_than_equal(10n, 10n, "10n is greater than or equal to 10n")
+ }
+ test(bigintAssertGreaterThanEqual, "bigint assert_greater_than_equal test");
+
function basicAssertLessThanEqual()
{
assert_greater_than_equal('10', 10, "'10' is not a number")
@@ -462,6 +480,12 @@ Sample HTML5 API Tests
"message": "assert_greater_than: 10 is not greater than 11 expected a number greater than 11 but got 10",
"properties": {}
},
+ {
+ "status_string": "FAIL",
+ "name": "bigint assert_greater_than expected to fail",
+ "message": "assert_greater_than: 10n is not greater than 11n expected a number greater than 11n but got 10n",
+ "properties": {}
+ },
{
"status_string": "FAIL",
"name": "assert_less_than_equal expected to fail",
@@ -516,12 +540,24 @@ Sample HTML5 API Tests
"message": null,
"properties": {}
},
+ {
+ "status_string": "PASS",
+ "name": "bigint assert_greater_than_equal test",
+ "message": null,
+ "properties": {}
+ },
{
"status_string": "PASS",
"name": "basic assert_less_than test",
"message": null,
"properties": {}
},
+ {
+ "status_string": "PASS",
+ "name": "bigint assert_less_than test",
+ "message": null,
+ "properties": {}
+ },
{
"status_string": "PASS",
"name": "body element fires the onload event set from the attribute",
@@ -745,13 +781,22 @@ Sample HTML5 API Tests
"status": 0
},
{
- "assert_name": "assert_approx_equals",
+ "assert_name": "assert_less_than",
"test": "basic assert_less_than test",
"args": [
"10",
"11",
- "1",
- "\"10 is approximately (+/- 1) 11\""
+ "\"10 is less than 11\""
+ ],
+ "status": 0
+ },
+ {
+ "assert_name": "assert_less_than",
+ "test": "bigint assert_less_than test",
+ "args": [
+ "10n",
+ "11n",
+ "\"10n is less than 11n\""
],
"status": 0
},
@@ -765,6 +810,16 @@ Sample HTML5 API Tests
],
"status": 1
},
+ {
+ "assert_name": "assert_greater_than",
+ "test": "bigint assert_greater_than expected to fail",
+ "args": [
+ "10n",
+ "11n",
+ "\"10n is not greater than 11n\""
+ ],
+ "status": 1
+ },
{
"assert_name": "assert_greater_than_equal",
"test": "basic assert_greater_than_equal test",
@@ -775,6 +830,16 @@ Sample HTML5 API Tests
],
"status": 0
},
+ {
+ "assert_name": "assert_greater_than_equal",
+ "test": "bigint assert_greater_than_equal test",
+ "args": [
+ "10n",
+ "10n",
+ "\"10n is greater than or equal to 10n\""
+ ],
+ "status": 0
+ },
{
"assert_name": "assert_greater_than_equal",
"test": "assert_less_than_equal expected to fail",
diff --git a/test/fixtures/wpt/resources/testdriver-actions.js.headers b/test/fixtures/wpt/resources/testdriver-actions.js.headers
new file mode 100644
index 00000000000..5e8f640c665
--- /dev/null
+++ b/test/fixtures/wpt/resources/testdriver-actions.js.headers
@@ -0,0 +1,2 @@
+Content-Type: text/javascript; charset=utf-8
+Cache-Control: max-age=3600
diff --git a/test/fixtures/wpt/resources/testdriver.js b/test/fixtures/wpt/resources/testdriver.js
index 05301bf5589..5b390dedeb7 100644
--- a/test/fixtures/wpt/resources/testdriver.js
+++ b/test/fixtures/wpt/resources/testdriver.js
@@ -142,6 +142,24 @@
simulate_adapter: function (params) {
return window.test_driver_internal.bidi.bluetooth.simulate_adapter(params);
},
+ /**
+ * Disables the bluetooth simulation with the given params. Matches the
+ * `bluetooth.disableSimulation `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.disable_simulation();
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context to disable the simulation for. If not provided, the
+ * current browsing context is used.
+ * @returns {Promise} fulfilled after the simulation is disabled, or rejected if
+ * the operation fails.
+ */
+ disable_simulation: function (params) {
+ return window.test_driver_internal.bidi.bluetooth.disable_simulation(params);
+ },
/**
* Creates a simulated bluetooth peripheral with the given params.
* Matches the
@@ -185,6 +203,303 @@
return window.test_driver_internal.bidi.bluetooth
.simulate_preconnected_peripheral(params);
},
+ /**
+ * Simulates a GATT connection response for a given peripheral.
+ * Matches the `bluetooth.simulateGattConnectionResponse
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_gatt_connection_response({
+ * "address": "09:09:09:09:09:09",
+ * "code": 0x0
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated
+ * bluetooth peripheral. Matches the
+ * `bluetooth.SimulateGattConnectionResponseParameters:peripheral `_
+ * value.
+ * @param {number} params.code - The response code for a GATT connection attempted.
+ * Matches the
+ * `bluetooth.SimulateGattConnectionResponseParameters:code `_
+ * value.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT connection response should be simulated. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT connection response
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_gatt_connection_response: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_gatt_connection_response(params);
+ },
+ /**
+ * Simulates a GATT disconnection for a given peripheral.
+ * Matches the `bluetooth.simulateGattDisconnection
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_gatt_disconnection({
+ * "address": "09:09:09:09:09:09",
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated
+ * bluetooth peripheral. Matches the
+ * `bluetooth.SimulateGattDisconnectionParameters:address `_
+ * value.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT disconnection should be simulated. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT disconnection
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_gatt_disconnection: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_gatt_disconnection(params);
+ },
+ /**
+ * Simulates a GATT service.
+ * Matches the `bluetooth.simulateService
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_service({
+ * "address": "09:09:09:09:09:09",
+ * "uuid": "0000180d-0000-1000-8000-00805f9b34fb",
+ * "type": "add"
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated bluetooth peripheral this service belongs to.
+ * Matches the
+ * `bluetooth.SimulateServiceParameters:address `_
+ * value.
+ * @param {string} params.uuid - The uuid of the simulated GATT service.
+ * Matches the
+ * `bluetooth.SimulateServiceParameters:address `_
+ * value.
+ * @param {string} params.type - The type of the GATT service simulation, either "add" or "remove".
+ * Matches the
+ * `bluetooth.SimulateServiceParameters:address `_
+ * value.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT service should be simulated. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT service
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_service: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_service(params);
+ },
+ /**
+ * Simulates a GATT characteristic.
+ * Matches the `bluetooth.simulateCharacteristic
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_characteristic({
+ * "address": "09:09:09:09:09:09",
+ * "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
+ * "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
+ * "characteristicProperties": {
+ * "read": true,
+ * "write": true,
+ * "notify": true
+ * },
+ * "type": "add"
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated bluetooth peripheral the characterisitc belongs to.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicParameters:address `_
+ * value.
+ * @param {string} params.serviceUuid - The uuid of the simulated GATT service the characterisitc belongs to.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicParameters:address `_
+ * value.
+ * @param {string} params.characteristicUuid - The uuid of the simulated GATT characteristic.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicParameters:address `_
+ * value.
+ * @param {string} params.characteristicProperties - The properties of the simulated GATT characteristic.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicParameters:address `_
+ * value.
+ * @param {string} params.type - The type of the GATT characterisitc simulation, either "add" or "remove".
+ * Matches the
+ * `bluetooth.SimulateCharacteristicParameters:address `_
+ * value.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT characteristic should be simulated. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT characteristic
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_characteristic: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_characteristic(params);
+ },
+ /**
+ * Simulates a GATT characteristic response.
+ * Matches the `bluetooth.simulateCharacteristicResponse
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_characteristic({
+ * "address": "09:09:09:09:09:09",
+ * "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
+ * "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
+ * "type": "read",
+ * "code": 0,
+ * "data": [1, 2]
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated
+ * bluetooth peripheral. Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.
+ * @param {string} params.serviceUuid - The uuid of the simulated GATT service the characterisitc belongs to.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.
+ * @param {string} params.characteristicUuid - The uuid of the simulated characteristic.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.
+ * @param {string} params.type - The type of the simulated GATT characteristic operation."
+ * Can be "read", "write", "subscribe-to-notifications" or "unsubscribe-from-notifications".
+ * Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.
+ * @param {string} params.code - The simulated GATT characteristic response code.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.*
+ * @param {string} params.data - The data along with the simulated GATT characteristic response.
+ * Matches the
+ * `bluetooth.SimulateCharacteristicResponseParameters:address `_
+ * value.**
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT characteristic belongs to. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT characteristic
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_characteristic_response: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_characteristic_response(params);
+ },
+ /**
+ * Simulates a GATT descriptor.
+ * Matches the `bluetooth.simulateDescriptor
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_descriptor({
+ * "address": "09:09:09:09:09:09",
+ * "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
+ * "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
+ * "descriptorUuid": "00002901-0000-1000-8000-00805f9b34fb",
+ * "type": "add"
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated bluetooth peripheral the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorParameters:address `_
+ * value.
+ * @param {string} params.serviceUuid - The uuid of the simulated GATT service the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorParameters:address `_
+ * value.
+ * @param {string} params.characteristicUuid - The uuid of the simulated GATT characterisitc the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorParameters:address `_
+ * value.
+ * @param {string} params.descriptorUuid - The uuid of the simulated GATT descriptor.
+ * Matches the
+ * `bluetooth.SimulateDescriptorParameters:address `_
+ * value.*
+ * @param {string} params.type - The type of the GATT descriptor simulation, either "add" or "remove".
+ * Matches the
+ * `bluetooth.SimulateDescriptorParameters:address `_
+ * value.
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT descriptor should be simulated. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT descriptor
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_descriptor: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_descriptor(params);
+ },
+ /**
+ * Simulates a GATT descriptor response.
+ * Matches the `bluetooth.simulateDescriptorResponse
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.bluetooth.simulate_descriptor_response({
+ * "address": "09:09:09:09:09:09",
+ * "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
+ * "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
+ * "descriptorUuid": "00002901-0000-1000-8000-00805f9b34fb",
+ * "type": "read",
+ * "code": 0,
+ * "data": [1, 2]
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {string} params.address - The address of the simulated bluetooth peripheral the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.
+ * @param {string} params.serviceUuid - The uuid of the simulated GATT service the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.
+ * @param {string} params.characteristicUuid - The uuid of the simulated GATT characterisitc the descriptor belongs to.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.
+ * @param {string} params.descriptorUuid - The uuid of the simulated GATT descriptor.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.
+ * @param {string} params.type - The type of the simulated GATT descriptor operation.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.
+ * @param {string} params.code - The simulated GATT descriptor response code.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.*
+ * @param {string} params.data - The data along with the simulated GATT descriptor response.
+ * Matches the
+ * `bluetooth.SimulateDescriptorResponseParameters:address `_
+ * value.**
+ * @param {Context} [params.context] The optional context parameter specifies in
+ * which browsing context the GATT descriptor belongs to. If not
+ * provided, the current browsing context is used.
+ * @returns {Promise} fulfilled after the GATT descriptor response
+ * is simulated, or rejected if the operation fails.
+ */
+ simulate_descriptor_response: function(params) {
+ return window.test_driver_internal.bidi.bluetooth
+ .simulate_descriptor_response(params);
+ },
/**
* `bluetooth.RequestDevicePromptUpdatedParameters `_
* event.
@@ -211,8 +526,8 @@
* event will be subscribed to globally. If omitted, the
* event will be subscribed to on the current browsing
* context.
- * @returns {Promise} Resolves when the subscription
- * is successfully done.
+ * @returns {Promise<(function(): Promise)>} Callback
+ * for unsubscribing from the created subscription.
*/
subscribe: async function(params = {}) {
assertBidiIsEnabled();
@@ -251,15 +566,330 @@
});
});
},
+ },
+ /**
+ * `bluetooth.GattConnectionAttemptedParameters `_
+ * event.
+ */
+ gatt_connection_attempted: {
+ /**
+ * @typedef {object} GattConnectionAttempted
+ * `bluetooth.GattConnectionAttempted `_
+ * event.
+ */
+
+ /**
+ * Subscribes to the event. Events will be emitted only if
+ * there is a subscription for the event. This method does
+ * not add actual listeners. To listen to the event, use the
+ * `on` or `once` methods. The buffered events will be
+ * emitted before the command promise is resolved.
+ *
+ * @param {object} [params] Parameters for the subscription.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing
+ * contexts to subscribe to the event on. It should be
+ * either an array of Context objects, or null. If null, the
+ * event will be subscribed to globally. If omitted, the
+ * event will be subscribed to on the current browsing
+ * context.
+ * @returns {Promise<(function(): Promise)>} Callback
+ * for unsubscribing from the created subscription.
+ */
+ subscribe: async function(params = {}) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .gatt_connection_attempted.subscribe(params);
+ },
+ /**
+ * Adds an event listener for the event.
+ *
+ * @param {function(GattConnectionAttempted): void} callback The
+ * callback to be called when the event is emitted. The
+ * callback is called with the event object as a parameter.
+ * @returns {function(): void} A function that removes the
+ * added event listener when called.
+ */
+ on: function(callback) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .gatt_connection_attempted.on(callback);
+ },
+ /**
+ * Adds an event listener for the event that is only called
+ * once and removed afterward.
+ *
+ * @return {Promise} The promise which
+ * is resolved with the event object when the event is emitted.
+ */
+ once: function() {
+ assertBidiIsEnabled();
+ return new Promise(resolve => {
+ const remove_handler =
+ window.test_driver_internal.bidi.bluetooth
+ .gatt_connection_attempted.on(event => {
+ resolve(event);
+ remove_handler();
+ });
+ });
+ },
+ },
+ /**
+ * `bluetooth.CharacteristicEventGeneratedParameters `_
+ * event.
+ */
+ characteristic_event_generated: {
+ /**
+ * @typedef {object} CharacteristicEventGenerated
+ * `bluetooth.CharacteristicEventGenerated `_
+ * event.
+ */
+
+ /**
+ * Subscribes to the event. Events will be emitted only if
+ * there is a subscription for the event. This method does
+ * not add actual listeners. To listen to the event, use the
+ * `on` or `once` methods. The buffered events will be
+ * emitted before the command promise is resolved.
+ *
+ * @param {object} [params] Parameters for the subscription.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing
+ * contexts to subscribe to the event on. It should be
+ * either an array of Context objects, or null. If null, the
+ * event will be subscribed to globally. If omitted, the
+ * event will be subscribed to on the current browsing
+ * context.
+ * @returns {Promise<(function(): Promise)>} Callback
+ * for unsubscribing from the created subscription.
+ */
+ subscribe: async function(params = {}) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .characteristic_event_generated.subscribe(params);
+ },
+ /**
+ * Adds an event listener for the event.
+ *
+ * @param {function(CharacteristicEventGenerated): void} callback The
+ * callback to be called when the event is emitted. The
+ * callback is called with the event object as a parameter.
+ * @returns {function(): void} A function that removes the
+ * added event listener when called.
+ */
+ on: function(callback) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .characteristic_event_generated.on(callback);
+ },
+ /**
+ * Adds an event listener for the event that is only called
+ * once and removed afterward.
+ *
+ * @return {Promise} The promise which
+ * is resolved with the event object when the event is emitted.
+ */
+ once: function() {
+ assertBidiIsEnabled();
+ return new Promise(resolve => {
+ const remove_handler =
+ window.test_driver_internal.bidi.bluetooth
+ .characteristic_event_generated.on(event => {
+ resolve(event);
+ remove_handler();
+ });
+ });
+ },
+ },
+ /**
+ * `bluetooth.DescriptorEventGeneratedParameters `_
+ * event.
+ */
+ descriptor_event_generated: {
+ /**
+ * @typedef {object} DescriptorEventGenerated
+ * `bluetooth.DescriptorEventGenerated `_
+ * event.
+ */
+
+ /**
+ * Subscribes to the event. Events will be emitted only if
+ * there is a subscription for the event. This method does
+ * not add actual listeners. To listen to the event, use the
+ * `on` or `once` methods. The buffered events will be
+ * emitted before the command promise is resolved.
+ *
+ * @param {object} [params] Parameters for the subscription.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing
+ * contexts to subscribe to the event on. It should be
+ * either an array of Context objects, or null. If null, the
+ * event will be subscribed to globally. If omitted, the
+ * event will be subscribed to on the current browsing
+ * context.
+ * @returns {Promise<(function(): Promise)>} Callback
+ * for unsubscribing from the created subscription.
+ */
+ subscribe: async function(params = {}) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .descriptor_event_generated.subscribe(params);
+ },
+ /**
+ * Adds an event listener for the event.
+ *
+ * @param {function(DescriptorEventGenerated): void} callback The
+ * callback to be called when the event is emitted. The
+ * callback is called with the event object as a parameter.
+ * @returns {function(): void} A function that removes the
+ * added event listener when called.
+ */
+ on: function(callback) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.bluetooth
+ .descriptor_event_generated.on(callback);
+ },
+ /**
+ * Adds an event listener for the event that is only called
+ * once and removed afterward.
+ *
+ * @return {Promise} The promise which
+ * is resolved with the event object when the event is emitted.
+ */
+ once: function() {
+ assertBidiIsEnabled();
+ return new Promise(resolve => {
+ const remove_handler =
+ window.test_driver_internal.bidi.bluetooth
+ .descriptor_event_generated.on(event => {
+ resolve(event);
+ remove_handler();
+ });
+ });
+ },
}
},
/**
- * `log `_ module.
+ * `emulation `_ module.
+ */
+ emulation: {
+ /**
+ * Overrides the geolocation coordinates for the specified
+ * browsing contexts.
+ * Matches the `emulation.setGeolocationOverride
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.emulation.set_geolocation_override({
+ * coordinates: {
+ * latitude: 52.51,
+ * longitude: 13.39,
+ * accuracy: 0.5,
+ * altitude: 34,
+ * altitudeAccuracy: 0.75,
+ * heading: 180,
+ * speed: 2.77
+ * }
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {null|object} params.coordinates - The optional
+ * geolocation coordinates to set. Matches the
+ * `emulation.GeolocationCoordinates `_
+ * value. If null or omitted and the `params.error` is set, the
+ * emulation will be removed. Mutually exclusive with
+ * `params.error`.
+ * @param {object} params.error - The optional
+ * geolocation error to emulate. Matches the
+ * `emulation.GeolocationPositionError `_
+ * value. Mutually exclusive with `params.coordinates`.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing contexts
+ * to set the geolocation override on. It should be either an
+ * array of Context objects (window or browsing context id), or
+ * null. If null or omitted, the override will be set on the
+ * current browsing context.
+ * @returns {Promise} Resolves when the geolocation
+ * override is successfully set.
+ */
+ set_geolocation_override: function (params) {
+ // Ensure the bidi feature is enabled before calling the internal method
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.emulation.set_geolocation_override(
+ params);
+ },
+ /**
+ * Overrides the locale for the specified browsing contexts.
+ * Matches the `emulation.setLocaleOverride
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.emulation.set_locale_override({
+ * locale: 'de-DE'
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {null|string} params.locale - The optional
+ * locale to set.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing contexts
+ * to set the locale override on. It should be either an array
+ * of Context objects (window or browsing context id), or null.
+ * If null or omitted, the override will be set on the current
+ * browsing context.
+ * @returns {Promise} Resolves when the locale override
+ * is successfully set.
+ */
+ set_locale_override: function (params) {
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.emulation.set_locale_override(
+ params);
+ },
+ /**
+ * Overrides the screen orientation for the specified browsing
+ * contexts.
+ * Matches the `emulation.setScreenOrientationOverride
+ * `_
+ * WebDriver BiDi command.
+ *
+ * @example
+ * await test_driver.bidi.emulation.set_screen_orientation_override({
+ * screenOrientation: {
+ * natural: 'portrait',
+ * type: 'landscape-secondary'
+ * }
+ * });
+ *
+ * @param {object} params - Parameters for the command.
+ * @param {null|object} params.screenOrientation - The optional
+ * screen orientation. Matches the
+ * `emulation.ScreenOrientation `_
+ * type. If null or omitted, the override will be removed.
+ * @param {null|Array.<(Context)>} [params.contexts] The
+ * optional contexts parameter specifies which browsing contexts
+ * to set the screen orientation override on. It should be
+ * either an array of Context objects (window or browsing
+ * context id), or null. If null or omitted, the override will
+ * be set on the current browsing context.
+ * @returns {Promise} Resolves when the screen orientation
+ * override is successfully set.
+ */
+ set_screen_orientation_override: function (params) {
+ // Ensure the bidi feature is enabled before calling the internal method
+ assertBidiIsEnabled();
+ return window.test_driver_internal.bidi.emulation.set_screen_orientation_override(
+ params);
+ },
+ },
+ /**
+ * `log `_ module.
*/
log: {
entry_added: {
/**
- * @typedef {object} LogEntryAdded `log.entryAdded `_ event.
+ * @typedef {object} LogEntryAdded `log.entryAdded `_ event.
*/
/**
@@ -277,8 +907,8 @@
* event will be subscribed to globally. If omitted, the
* event will be subscribed to on the current browsing
* context.
- * @returns {Promise} Resolves when the subscription
- * is successfully done.
+ * @returns {Promise<(function(): Promise)>} Callback
+ * for unsubscribing from the created subscription.
*/
subscribe: async function (params = {}) {
assertBidiIsEnabled();
@@ -629,7 +1259,7 @@
/**
* Minimizes the browser window.
*
- * Matches the the behaviour of the `Minimize
+ * Matches the behaviour of the `Minimize
* `_
* WebDriver command
*
@@ -1428,7 +2058,7 @@
* Causes a virtual pressure source to report a new reading.
*
* Matches the `Update virtual pressure source
- * `_
+ * `_
* WebDriver command.
*
* @param {String} source_type - A `virtual pressure source type
@@ -1437,6 +2067,8 @@
* @param {String} sample - A `virtual pressure state
* `_
* such as "critical".
+ * @param {number} own_contribution_estimate - Optional, A `virtual own contribution estimate`
+ * `_
* @param {WindowProxy} [context=null] - Browsing context in which to
* run the call, or null for the
* current browsing context.
@@ -1447,8 +2079,8 @@
* virtual pressure source of the given type does not
* exist).
*/
- update_virtual_pressure_source: function(source_type, sample, context=null) {
- return window.test_driver_internal.update_virtual_pressure_source(source_type, sample, context);
+ update_virtual_pressure_source: function(source_type, sample, own_contribution_estimate, context=null) {
+ return window.test_driver_internal.update_virtual_pressure_source(source_type, sample, own_contribution_estimate, context);
},
/**
@@ -1472,6 +2104,71 @@
*/
remove_virtual_pressure_source: function(source_type, context=null) {
return window.test_driver_internal.remove_virtual_pressure_source(source_type, context);
+ },
+
+ /**
+ * Sets which hashes are considered k-anonymous for the Protected
+ * Audience interest group with specified `owner` and `name`.
+ *
+ * Matches the `Set Protected Audience K-Anonymity
+ *
+ * WebDriver command.
+ *
+ * @param {String} owner - Origin of the owner of the interest group
+ * to modify
+ * @param {String} name - Name of the interest group to modify
+ * @param {Array} hashes - An array of strings, each of which is a
+ * base64 ecoded hash to consider k-anonymous.
+ *
+ * @returns {Promise} Fulfilled after the k-anonymity status for the
+ * specified Protected Audience interest group has
+ * been updated.
+ *
+ */
+ set_protected_audience_k_anonymity: function(owner, name, hashes, context = null) {
+ return window.test_driver_internal.set_protected_audience_k_anonymity(owner, name, hashes, context);
+ },
+
+ /**
+ * Overrides the display features provided by the hardware so the viewport segments
+ * can be emulated.
+ *
+ * Matches the `Set display features
+ * `_
+ * WebDriver command.
+ *
+ * @param {Array} features - An array of `DisplayFeatureOverride
+ * `.
+ * @param {WindowProxy} [context=null] - Browsing context in which to
+ * run the call, or null for the
+ * current browsing context.
+ *
+ * @returns {Promise} Fulfilled when the display features are set.
+ * Rejected in case the WebDriver command errors out
+ * (including if the array is malformed).
+ */
+ set_display_features: function(features, context=null) {
+ return window.test_driver_internal.set_display_features(features, context);
+ },
+
+ /**
+ * Removes display features override and returns the control
+ * back to hardware.
+ *
+ * Matches the `Clear display features
+ * `_
+ * WebDriver command.
+ *
+ * @param {WindowProxy} [context=null] - Browsing context in which to
+ * run the call, or null for the
+ * current browsing context.
+ *
+ * @returns {Promise} Fulfilled after the display features override has
+ * been removed. Rejected in case the WebDriver
+ * command errors out.
+ */
+ clear_display_features: function(context=null) {
+ return window.test_driver_internal.clear_display_features(context);
}
};
@@ -1494,6 +2191,10 @@
throw new Error(
"bidi.bluetooth.simulate_adapter is not implemented by testdriver-vendor.js");
},
+ disable_simulation: function () {
+ throw new Error(
+ "bidi.bluetooth.disable_simulation is not implemented by testdriver-vendor.js");
+ },
simulate_preconnected_peripheral: function() {
throw new Error(
'bidi.bluetooth.simulate_preconnected_peripheral is not implemented by testdriver-vendor.js');
@@ -1507,6 +2208,50 @@
throw new Error(
'bidi.bluetooth.request_device_prompt_updated.on is not implemented by testdriver-vendor.js');
}
+ },
+ gatt_connection_attempted: {
+ async subscribe() {
+ throw new Error(
+ 'bidi.bluetooth.gatt_connection_attempted.subscribe is not implemented by testdriver-vendor.js');
+ },
+ on() {
+ throw new Error(
+ 'bidi.bluetooth.gatt_connection_attempted.on is not implemented by testdriver-vendor.js');
+ }
+ },
+ characteristic_event_generated: {
+ async subscribe() {
+ throw new Error(
+ 'bidi.bluetooth.characteristic_event_generated.subscribe is not implemented by testdriver-vendor.js');
+ },
+ on() {
+ throw new Error(
+ 'bidi.bluetooth.characteristic_event_generated.on is not implemented by testdriver-vendor.js');
+ }
+ },
+ descriptor_event_generated: {
+ async subscribe() {
+ throw new Error(
+ 'bidi.bluetooth.descriptor_event_generated.subscribe is not implemented by testdriver-vendor.js');
+ },
+ on() {
+ throw new Error(
+ 'bidi.bluetooth.descriptor_event_generated.on is not implemented by testdriver-vendor.js');
+ }
+ }
+ },
+ emulation: {
+ set_geolocation_override: function (params) {
+ throw new Error(
+ "bidi.emulation.set_geolocation_override is not implemented by testdriver-vendor.js");
+ },
+ set_locale_override: function (params) {
+ throw new Error(
+ "bidi.emulation.set_locale_override is not implemented by testdriver-vendor.js");
+ },
+ set_screen_orientation_override: function (params) {
+ throw new Error(
+ "bidi.emulation.set_screen_orientation_override is not implemented by testdriver-vendor.js");
}
},
log: {
@@ -1723,12 +2468,24 @@
throw new Error("create_virtual_pressure_source() is not implemented by testdriver-vendor.js");
},
- async update_virtual_pressure_source(source_type, sample, context=null) {
+ async update_virtual_pressure_source(source_type, sample, own_contribution_estimate, context=null) {
throw new Error("update_virtual_pressure_source() is not implemented by testdriver-vendor.js");
},
async remove_virtual_pressure_source(source_type, context=null) {
throw new Error("remove_virtual_pressure_source() is not implemented by testdriver-vendor.js");
+ },
+
+ async set_protected_audience_k_anonymity(owner, name, hashes, context=null) {
+ throw new Error("set_protected_audience_k_anonymity() is not implemented by testdriver-vendor.js");
+ },
+
+ async set_display_features(features, context=null) {
+ throw new Error("set_display_features() is not implemented by testdriver-vendor.js");
+ },
+
+ async clear_display_features(context=null) {
+ throw new Error("clear_display_features() is not implemented by testdriver-vendor.js");
}
};
})();
diff --git a/test/fixtures/wpt/resources/testharness.js b/test/fixtures/wpt/resources/testharness.js
index 5b5410c8b21..f495b62458b 100644
--- a/test/fixtures/wpt/resources/testharness.js
+++ b/test/fixtures/wpt/resources/testharness.js
@@ -88,7 +88,7 @@
status: harness_status.structured_clone(),
asserts: asserts.map(assert => assert.structured_clone())});
}]
- }
+ };
on_event(window, 'load', function() {
setTimeout(() => {
@@ -203,7 +203,7 @@
}
});
this.message_events = new_events;
- }
+ };
WindowTestEnvironment.prototype.next_default_test_name = function() {
var suffix = this.name_counter > 0 ? " " + this.name_counter : "";
@@ -225,8 +225,8 @@
WindowTestEnvironment.prototype.test_timeout = function() {
var metas = document.getElementsByTagName("meta");
for (var i = 0; i < metas.length; i++) {
- if (metas[i].name == "timeout") {
- if (metas[i].content == "long") {
+ if (metas[i].name === "timeout") {
+ if (metas[i].content === "long") {
return settings.harness_timeout.long;
}
break;
@@ -487,7 +487,7 @@
this.all_loaded = false;
this.on_loaded_callback = null;
Promise.resolve().then(function() {
- this.all_loaded = true
+ this.all_loaded = true;
if (this.on_loaded_callback) {
this.on_loaded_callback();
}
@@ -563,7 +563,7 @@
// The worker object may be from another execution context,
// so do not use instanceof here.
return 'ServiceWorker' in global_scope &&
- Object.prototype.toString.call(worker) == '[object ServiceWorker]';
+ Object.prototype.toString.call(worker) === '[object ServiceWorker]';
}
var seen_func_name = Object.create(null);
@@ -810,7 +810,7 @@
return bring_promise_to_current_realm(promise)
.then(test.unreached_func("Should have rejected: " + description))
.catch(function(e) {
- assert_throws_js_impl(constructor, function() { throw e },
+ assert_throws_js_impl(constructor, function() { throw e; },
description, "promise_rejects_js");
});
}
@@ -862,11 +862,59 @@
return bring_promise_to_current_realm(promise)
.then(test.unreached_func("Should have rejected: " + description))
.catch(function(e) {
- assert_throws_dom_impl(type, function() { throw e }, description,
+ assert_throws_dom_impl(type, function() { throw e; }, description,
"promise_rejects_dom", constructor);
});
}
+/**
+ * Assert that a `Promise` is rejected with a `QuotaExceededError` with the
+ * expected values.
+ *
+ * For the remaining arguments, there are two ways of calling
+ * `promise_rejects_quotaexceedederror`:
+ *
+ * 1) If the `QuotaExceededError` is expected to come from the
+ * current global, the second argument should be the promise
+ * expected to reject, the third and a fourth the expected
+ * `requested` and `quota` property values, and the fifth,
+ * optional, argument is the assertion description.
+ *
+ * 2) If the `QuotaExceededError` is expected to come from some
+ * other global, the second argument should be the
+ * `QuotaExceededError` constructor from that global, the third
+ * argument should be the promise expected to reject, the fourth
+ * and fifth the expected `requested` and `quota` property
+ * values, and the sixth, optional, argument is the assertion
+ * description.
+ *
+ */
+ function promise_rejects_quotaexceedederror(test, promiseOrConstructor, requestedOrPromise, quotaOrRequested, descriptionOrQuota, maybeDescription)
+ {
+ let constructor, promise, requested, quota, description;
+ if (typeof promiseOrConstructor === "function" &&
+ promiseOrConstructor.name === "QuotaExceededError") {
+ constructor = promiseOrConstructor;
+ promise = requestedOrPromise;
+ requested = quotaOrRequested;
+ quota = descriptionOrQuota;
+ description = maybeDescription;
+ } else {
+ constructor = self.QuotaExceededError;
+ promise = promiseOrConstructor;
+ requested = requestedOrPromise;
+ quota = quotaOrRequested;
+ description = descriptionOrQuota;
+ assert(maybeDescription === undefined,
+ "Too many args passed to no-constructor version of promise_rejects_quotaexceedederror");
+ }
+ return bring_promise_to_current_realm(promise)
+ .then(test.unreached_func("Should have rejected: " + description))
+ .catch(function(e) {
+ assert_throws_quotaexceedederror_impl(function() { throw e; }, requested, quota, description, "promise_rejects_quotaexceedederror", constructor);
+ });
+ }
+
/**
* Assert that a Promise is rejected with the provided value.
*
@@ -881,7 +929,7 @@
return bring_promise_to_current_realm(promise)
.then(test.unreached_func("Should have rejected: " + description))
.catch(function(e) {
- assert_throws_exactly_impl(exception, function() { throw e },
+ assert_throws_exactly_impl(exception, function() { throw e; },
description, "promise_rejects_exactly");
});
}
@@ -907,7 +955,7 @@
*/
function EventWatcher(test, watchedNode, eventTypes, timeoutPromise)
{
- if (typeof eventTypes == 'string') {
+ if (typeof eventTypes === 'string') {
eventTypes = [eventTypes];
}
@@ -972,7 +1020,7 @@
if (waitingFor) {
return Promise.reject('Already waiting for an event or events');
}
- if (typeof types == 'string') {
+ if (typeof types === 'string') {
types = [types];
}
if (options && options.record && options.record === 'all') {
@@ -987,7 +1035,7 @@
// This should always fail, otherwise we should have
// resolved the promise.
- assert_true(waitingFor.types.length == 0,
+ assert_true(waitingFor.types.length === 0,
'Timed out waiting for ' + waitingFor.types.join(', '));
var result = recordedEvents;
recordedEvents = null;
@@ -1011,13 +1059,13 @@
/**
* Stop listening for events
*/
- function stop_watching() {
+ this.stop_watching = function() {
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.removeEventListener(eventTypes[i], eventHandler, false);
}
};
- test._add_cleanup(stop_watching);
+ test._add_cleanup(this.stop_watching);
return this;
}
@@ -1132,7 +1180,7 @@
*
* Typically this function is called implicitly on page load; it's
* only necessary for users to call this when either the
- * ``explicit_done`` or ``single_page`` properties have been set
+ * ``explicit_done`` or ``single_test`` properties have been set
* via the :js:func:`setup` function.
*
* For single page tests this marks the test as complete and sets its status.
@@ -1240,6 +1288,7 @@
expose(promise_test, 'promise_test');
expose(promise_rejects_js, 'promise_rejects_js');
expose(promise_rejects_dom, 'promise_rejects_dom');
+ expose(promise_rejects_quotaexceedederror, 'promise_rejects_quotaexceedederror');
expose(promise_rejects_exactly, 'promise_rejects_exactly');
expose(generate_tests, 'generate_tests');
expose(setup, 'setup');
@@ -1330,6 +1379,15 @@
"0xffff": "uffff",
};
+ const formatEscapeMap = {
+ "\\": "\\\\",
+ '"': '\\"'
+ };
+ for (const p in replacements) {
+ formatEscapeMap[String.fromCharCode(p)] = "\\" + replacements[p];
+ }
+ const formatEscapePattern = new RegExp(`[${Object.keys(formatEscapeMap).map(k => k === "\\" ? "\\\\" : k).join("")}]`, "g");
+
/**
* Convert a value to a nice, human-readable string
*
@@ -1380,12 +1438,7 @@
switch (typeof val) {
case "string":
- val = val.replace(/\\/g, "\\\\");
- for (var p in replacements) {
- var replace = "\\" + replacements[p];
- val = val.replace(RegExp(String.fromCharCode(p), "g"), replace);
- }
- return '"' + val.replace(/"/g, '\\"') + '"';
+ return '"' + val.replace(formatEscapePattern, match => formatEscapeMap[match]) + '"';
case "boolean":
case "undefined":
return String(val);
@@ -1396,6 +1449,8 @@
return "-0";
}
return String(val);
+ case "bigint":
+ return String(val) + 'n';
case "object":
if (val === null) {
return "null";
@@ -1419,11 +1474,11 @@
case Node.COMMENT_NODE:
return "Comment node ";
case Node.DOCUMENT_NODE:
- return "Document node with " + val.childNodes.length + (val.childNodes.length == 1 ? " child" : " children");
+ return "Document node with " + val.childNodes.length + (val.childNodes.length === 1 ? " child" : " children");
case Node.DOCUMENT_TYPE_NODE:
return "DocumentType node";
case Node.DOCUMENT_FRAGMENT_NODE:
- return "DocumentFragment node with " + val.childNodes.length + (val.childNodes.length == 1 ? " child" : " children");
+ return "DocumentFragment node with " + val.childNodes.length + (val.childNodes.length === 1 ? " child" : " children");
default:
return "Node object of unknown type";
}
@@ -1767,20 +1822,25 @@
/**
* Assert that ``actual`` is a number less than ``expected``.
*
- * @param {number} actual - Test value.
- * @param {number} expected - Number that ``actual`` must be less than.
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} expected - Value that ``actual`` must be less than.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_less_than(actual, expected, description)
{
/*
- * Test if a primitive number is less than another
+ * Test if a primitive number (or bigint) is less than another
*/
- assert(typeof actual === "number",
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_less_than", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof expected,
+ "assert_less_than", description,
+ "expected a ${type_expected} but got a ${type_actual}",
+ {type_expected:typeof expected, type_actual:typeof actual});
+
assert(actual < expected,
"assert_less_than", description,
"expected a number less than ${expected} but got ${actual}",
@@ -1791,20 +1851,25 @@
/**
* Assert that ``actual`` is a number greater than ``expected``.
*
- * @param {number} actual - Test value.
- * @param {number} expected - Number that ``actual`` must be greater than.
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} expected - Value that ``actual`` must be greater than.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_greater_than(actual, expected, description)
{
/*
- * Test if a primitive number is greater than another
+ * Test if a primitive number (or bigint) is greater than another
*/
- assert(typeof actual === "number",
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_greater_than", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof expected,
+ "assert_greater_than", description,
+ "expected a ${type_expected} but got a ${type_actual}",
+ {type_expected:typeof expected, type_actual:typeof actual});
+
assert(actual > expected,
"assert_greater_than", description,
"expected a number greater than ${expected} but got ${actual}",
@@ -1816,21 +1881,31 @@
* Assert that ``actual`` is a number greater than ``lower`` and less
* than ``upper`` but not equal to either.
*
- * @param {number} actual - Test value.
- * @param {number} lower - Number that ``actual`` must be greater than.
- * @param {number} upper - Number that ``actual`` must be less than.
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} lower - Value that ``actual`` must be greater than.
+ * @param {number|bigint} upper - Value that ``actual`` must be less than.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_between_exclusive(actual, lower, upper, description)
{
/*
- * Test if a primitive number is between two others
+ * Test if a primitive number (or bigint) is between two others
*/
- assert(typeof actual === "number",
+ assert(typeof lower === typeof upper,
+ "assert_between_exclusive", description,
+ "expected lower (${type_lower}) and upper (${type_upper}) types to match (test error)",
+ {type_lower:typeof lower, type_upper:typeof upper});
+
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_between_exclusive", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof lower,
+ "assert_between_exclusive", description,
+ "expected a ${type_lower} but got a ${type_actual}",
+ {type_lower:typeof lower, type_actual:typeof actual});
+
assert(actual > lower && actual < upper,
"assert_between_exclusive", description,
"expected a number greater than ${lower} " +
@@ -1842,21 +1917,26 @@
/**
* Assert that ``actual`` is a number less than or equal to ``expected``.
*
- * @param {number} actual - Test value.
- * @param {number} expected - Number that ``actual`` must be less
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} expected - Value that ``actual`` must be less
* than or equal to.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_less_than_equal(actual, expected, description)
{
/*
- * Test if a primitive number is less than or equal to another
+ * Test if a primitive number (or bigint) is less than or equal to another
*/
- assert(typeof actual === "number",
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_less_than_equal", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof expected,
+ "assert_less_than_equal", description,
+ "expected a ${type_expected} but got a ${type_actual}",
+ {type_expected:typeof expected, type_actual:typeof actual});
+
assert(actual <= expected,
"assert_less_than_equal", description,
"expected a number less than or equal to ${expected} but got ${actual}",
@@ -1867,21 +1947,26 @@
/**
* Assert that ``actual`` is a number greater than or equal to ``expected``.
*
- * @param {number} actual - Test value.
- * @param {number} expected - Number that ``actual`` must be greater
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} expected - Value that ``actual`` must be greater
* than or equal to.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_greater_than_equal(actual, expected, description)
{
/*
- * Test if a primitive number is greater than or equal to another
+ * Test if a primitive number (or bigint) is greater than or equal to another
*/
- assert(typeof actual === "number",
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_greater_than_equal", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof expected,
+ "assert_greater_than_equal", description,
+ "expected a ${type_expected} but got a ${type_actual}",
+ {type_expected:typeof expected, type_actual:typeof actual});
+
assert(actual >= expected,
"assert_greater_than_equal", description,
"expected a number greater than or equal to ${expected} but got ${actual}",
@@ -1893,21 +1978,31 @@
* Assert that ``actual`` is a number greater than or equal to ``lower`` and less
* than or equal to ``upper``.
*
- * @param {number} actual - Test value.
- * @param {number} lower - Number that ``actual`` must be greater than or equal to.
- * @param {number} upper - Number that ``actual`` must be less than or equal to.
+ * @param {number|bigint} actual - Test value.
+ * @param {number|bigint} lower - Value that ``actual`` must be greater than or equal to.
+ * @param {number|bigint} upper - Value that ``actual`` must be less than or equal to.
* @param {string} [description] - Description of the condition being tested.
*/
function assert_between_inclusive(actual, lower, upper, description)
{
/*
- * Test if a primitive number is between to two others or equal to either of them
+ * Test if a primitive number (or bigint) is between to two others or equal to either of them
*/
- assert(typeof actual === "number",
+ assert(typeof lower === typeof upper,
+ "assert_between_inclusive", description,
+ "expected lower (${type_lower}) and upper (${type_upper}) types to match (test error)",
+ {type_lower:typeof lower, type_upper:typeof upper});
+
+ assert(typeof actual === "number" || typeof actual === "bigint",
"assert_between_inclusive", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
+ assert(typeof actual === typeof lower,
+ "assert_between_inclusive", description,
+ "expected a ${type_lower} but got a ${type_actual}",
+ {type_lower:typeof lower, type_actual:typeof actual});
+
assert(actual >= lower && actual <= upper,
"assert_between_inclusive", description,
"expected a number greater than or equal to ${lower} " +
@@ -2117,7 +2212,7 @@
{func:func});
// Basic sanity-check on the passed-in constructor
- assert(typeof constructor == "function",
+ assert(typeof constructor === "function",
assertion_type, description,
"${constructor} is not a constructor",
{constructor:constructor});
@@ -2192,7 +2287,7 @@
assert(maybeDescription === undefined,
"Too many args passed to no-constructor version of assert_throws_dom, or accidentally explicitly passed undefined");
}
- assert_throws_dom_impl(type, func, description, "assert_throws_dom", constructor)
+ assert_throws_dom_impl(type, func, description, "assert_throws_dom", constructor);
}
expose_assert(assert_throws_dom, "assert_throws_dom");
@@ -2225,8 +2320,8 @@
{func:func});
// Sanity-check our type
- assert(typeof type == "number" ||
- typeof type == "string",
+ assert(typeof type === "number" ||
+ typeof type === "string",
assertion_type, description,
"${type} is not a number or string",
{type:type});
@@ -2250,7 +2345,6 @@
NETWORK_ERR: 'NetworkError',
ABORT_ERR: 'AbortError',
URL_MISMATCH_ERR: 'URLMismatchError',
- QUOTA_EXCEEDED_ERR: 'QuotaExceededError',
TIMEOUT_ERR: 'TimeoutError',
INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError',
DATA_CLONE_ERR: 'DataCloneError'
@@ -2275,7 +2369,6 @@
NetworkError: 19,
AbortError: 20,
URLMismatchError: 21,
- QuotaExceededError: 22,
TimeoutError: 23,
InvalidNodeTypeError: 24,
DataCloneError: 25,
@@ -2306,12 +2399,19 @@
if (typeof type === "number") {
if (type === 0) {
throw new AssertionError('Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()');
- } else if (!(type in code_name_map)) {
+ }
+ if (type === 22) {
+ throw new AssertionError('Test bug: QuotaExceededError needs to be tested for using assert_throws_quotaexceedederror()');
+ }
+ if (!(type in code_name_map)) {
throw new AssertionError('Test bug: unrecognized DOMException code "' + type + '" passed to assert_throws_dom()');
}
name = code_name_map[type];
required_props.code = type;
} else if (typeof type === "string") {
+ if (name === "QuotaExceededError") {
+ throw new AssertionError('Test bug: QuotaExceededError needs to be tested for using assert_throws_quotaexceedederror()');
+ }
name = type in codename_name_map ? codename_name_map[type] : type;
if (!(name in name_code_map)) {
throw new AssertionError('Test bug: unrecognized DOMException code name or name "' + type + '" passed to assert_throws_dom()');
@@ -2346,6 +2446,137 @@
}
}
+ /**
+ * Assert a `QuotaExceededError` with the expected values is thrown.
+ *
+ * There are two ways of calling `assert_throws_quotaexceedederror`:
+ *
+ * 1) If the `QuotaExceededError` is expected to come from the
+ * current global, the first argument should be the function
+ * expected to throw, the second and a third the expected
+ * `requested` and `quota` property values, and the fourth,
+ * optional, argument is the assertion description.
+ *
+ * 2) If the `QuotaExceededError` is expected to come from some
+ * other global, the first argument should be the
+ * `QuotaExceededError` constructor from that global, the second
+ * argument should be the function expected to throw, the third
+ * and fourth the expected `requested` and `quota` property
+ * values, and the fifth, optional, argument is the assertion
+ * description.
+ *
+ * For the `requested` and `quota` values, instead of `null` or a
+ * number, the caller can provide a function which determines
+ * whether the value is acceptable by returning a boolean.
+ *
+ */
+ function assert_throws_quotaexceedederror(funcOrConstructor, requestedOrFunc, quotaOrRequested, descriptionOrQuota, maybeDescription)
+ {
+ let constructor, func, requested, quota, description;
+ if (funcOrConstructor.name === "QuotaExceededError") {
+ constructor = funcOrConstructor;
+ func = requestedOrFunc;
+ requested = quotaOrRequested;
+ quota = descriptionOrQuota;
+ description = maybeDescription;
+ } else {
+ constructor = self.QuotaExceededError;
+ func = funcOrConstructor;
+ requested = requestedOrFunc;
+ quota = quotaOrRequested;
+ description = descriptionOrQuota;
+ assert(maybeDescription === undefined,
+ "Too many args passed to no-constructor version of assert_throws_quotaexceedederror");
+ }
+ assert_throws_quotaexceedederror_impl(func, requested, quota, description, "assert_throws_quotaexceedederror", constructor);
+ }
+ expose_assert(assert_throws_quotaexceedederror, "assert_throws_quotaexceedederror");
+
+ /**
+ * Similar to `assert_throws_quotaexceedederror` but allows
+ * specifying the assertion type
+ * (`"assert_throws_quotaexceedederror"` or
+ * `"promise_rejects_quotaexceedederror"`, in practice). The
+ * `constructor` argument must be the `QuotaExceededError`
+ * constructor from the global we expect the exception to come from.
+ */
+ function assert_throws_quotaexceedederror_impl(func, requested, quota, description, assertion_type, constructor)
+ {
+ try {
+ func.call(this);
+ assert(false, assertion_type, description, "${func} did not throw",
+ {func});
+ } catch (e) {
+ if (e instanceof AssertionError) {
+ throw e;
+ }
+
+ // Basic sanity-checks on the thrown exception.
+ assert(typeof e === "object",
+ assertion_type, description,
+ "${func} threw ${e} with type ${type}, not an object",
+ {func, e, type:typeof e});
+
+ assert(e !== null,
+ assertion_type, description,
+ "${func} threw null, not an object",
+ {func});
+
+ // Sanity-check our requested and quota.
+ assert(requested === null ||
+ typeof requested === "number" ||
+ typeof requested === "function",
+ assertion_type, description,
+ "${requested} is not null, a number, or a function",
+ {requested});
+ assert(quota === null ||
+ typeof quota === "number" ||
+ typeof quota === "function",
+ assertion_type, description,
+ "${quota} is not null or a number",
+ {quota});
+
+ const required_props = {
+ code: 22,
+ name: "QuotaExceededError"
+ };
+ if (typeof requested !== "function") {
+ required_props.requested = requested;
+ }
+ if (typeof quota !== "function") {
+ required_props.quota = quota;
+ }
+
+ for (const [prop, expected] of Object.entries(required_props)) {
+ assert(prop in e && e[prop] == expected,
+ assertion_type, description,
+ "${func} threw ${e} that is not a correct QuotaExceededError: property ${prop} is equal to ${actual}, expected ${expected}",
+ {func, e, prop, actual:e[prop], expected});
+ }
+
+ if (typeof requested === "function") {
+ assert(requested(e.requested),
+ assertion_type, description,
+ "${func} threw ${e} that is not a correct QuotaExceededError: requested value ${requested} did not pass the requested predicate",
+ {func, e, requested});
+ }
+ if (typeof quota === "function") {
+ assert(quota(e.quota),
+ assertion_type, description,
+ "${func} threw ${e} that is not a correct QuotaExceededError: quota value ${quota} did not pass the quota predicate",
+ {func, e, quota});
+ }
+
+ // Check that the exception is from the right global. This check is last
+ // so more specific, and more informative, checks on the properties can
+ // happen in case a totally incorrect exception is thrown.
+ assert(e.constructor === constructor,
+ assertion_type, description,
+ "${func} threw an exception from the wrong global",
+ {func});
+ }
+ }
+
/**
* Assert the provided value is thrown.
*
@@ -2455,7 +2686,7 @@
function assert_implements(condition, description) {
assert(!!condition, "assert_implements", description);
}
- expose_assert(assert_implements, "assert_implements")
+ expose_assert(assert_implements, "assert_implements");
/**
* Assert that an optional feature is implemented, based on a 'truthy' condition.
@@ -2569,11 +2800,11 @@
2: "Timeout",
3: "Not Run",
4: "Optional Feature Unsupported",
- }
+ };
Test.prototype.format_status = function() {
return this.status_formats[this.status];
- }
+ };
Test.prototype.structured_clone = function()
{
@@ -2883,7 +3114,7 @@
return new Promise(resolve => {
this.step_wait_func(cond, resolve, description, timeout, interval);
});
- }
+ };
/*
* Private method for registering cleanup functions. `testharness.js`
@@ -3116,7 +3347,7 @@
throw new Error("AbortController is not supported in this browser");
}
return this._abortController.signal;
- }
+ };
/**
* A RemoteTest object mirrors a Test object on a remote worker. The
@@ -3192,11 +3423,11 @@
function(callback) {
callback();
});
- }
+ };
RemoteTest.prototype.format_status = function() {
return Test.prototype.status_formats[this.status];
- }
+ };
/*
* A RemoteContext listens for test events from a remote test context, such
@@ -3468,7 +3699,7 @@
this.all_done_callbacks = [];
this.hide_test_state = false;
- this.pending_remotes = [];
+ this.remotes = [];
this.current_test = null;
this.asserts_run = [];
@@ -3510,26 +3741,26 @@
for (var p in properties) {
if (properties.hasOwnProperty(p)) {
var value = properties[p];
- if (p == "allow_uncaught_exception") {
+ if (p === "allow_uncaught_exception") {
this.allow_uncaught_exception = value;
- } else if (p == "explicit_done" && value) {
+ } else if (p === "explicit_done" && value) {
this.wait_for_finish = true;
- } else if (p == "explicit_timeout" && value) {
+ } else if (p === "explicit_timeout" && value) {
this.timeout_length = null;
if (this.timeout_id)
{
clearTimeout(this.timeout_id);
}
- } else if (p == "single_test" && value) {
+ } else if (p === "single_test" && value) {
this.set_file_is_test();
- } else if (p == "timeout_multiplier") {
+ } else if (p === "timeout_multiplier") {
this.timeout_multiplier = value;
if (this.timeout_length) {
this.timeout_length *= this.timeout_multiplier;
}
- } else if (p == "hide_test_state") {
+ } else if (p === "hide_test_state") {
this.hide_test_state = value;
- } else if (p == "output") {
+ } else if (p === "output") {
this.output = value;
} else if (p === "debug") {
settings.debug = value;
@@ -3622,11 +3853,14 @@
Tests.prototype.push = function(test)
{
+ if (this.phase === this.phases.COMPLETE) {
+ return;
+ }
if (this.phase < this.phases.HAVE_TESTS) {
this.start();
}
this.num_pending++;
- test.index = this.tests.push(test);
+ test.index = this.tests.push(test) - 1;
this.notify_test_state(test);
};
@@ -3639,11 +3873,11 @@
};
Tests.prototype.all_done = function() {
- return (this.tests.length > 0 || this.pending_remotes.length > 0) &&
+ return (this.tests.length > 0 || this.remotes.length > 0) &&
test_environment.all_loaded &&
(this.num_pending === 0 || this.is_aborted) && !this.wait_for_finish &&
!this.processing_callbacks &&
- !this.pending_remotes.some(function(w) { return w.running; });
+ !this.remotes.some(function(w) { return w.running; });
};
Tests.prototype.start = function() {
@@ -3712,7 +3946,8 @@
function(test, testDone)
{
if (test.phase === test.phases.INITIAL) {
- test.phase = test.phases.COMPLETE;
+ test.phase = test.phases.HAS_RESULT;
+ test.done();
testDone();
} else {
add_test_done_callback(test, testDone);
@@ -3723,14 +3958,14 @@
};
Tests.prototype.set_assert = function(assert_name, args) {
- this.asserts_run.push(new AssertRecord(this.current_test, assert_name, args))
- }
+ this.asserts_run.push(new AssertRecord(this.current_test, assert_name, args));
+ };
Tests.prototype.set_assert_status = function(index, status, stack) {
let assert_record = this.asserts_run[index];
assert_record.status = status;
assert_record.stack = stack;
- }
+ };
/**
* Update the harness status to reflect an unrecoverable harness error that
@@ -3872,7 +4107,7 @@
}
var remoteContext = this.create_remote_worker(worker);
- this.pending_remotes.push(remoteContext);
+ this.remotes.push(remoteContext);
return remoteContext.done;
};
@@ -3895,7 +4130,7 @@
}
var remoteContext = this.create_remote_window(remote);
- this.pending_remotes.push(remoteContext);
+ this.remotes.push(remoteContext);
return remoteContext.done;
};
@@ -4107,8 +4342,8 @@
} else {
var root = output_document.documentElement;
var is_html = (root &&
- root.namespaceURI == "http://www.w3.org/1999/xhtml" &&
- root.localName == "html");
+ root.namespaceURI === "http://www.w3.org/1999/xhtml" &&
+ root.localName === "html");
var is_svg = (output_document.defaultView &&
"SVGSVGElement" in output_document.defaultView &&
root instanceof output_document.defaultView.SVGSVGElement);
@@ -4553,7 +4788,7 @@
*/
function AssertionError(message)
{
- if (typeof message == "string") {
+ if (typeof message === "string") {
message = sanitize_unpaired_surrogates(message);
}
this.message = message;
@@ -4599,7 +4834,7 @@
}
return lines.slice(i).join("\n");
- }
+ };
function OptionalFeatureUnsupportedError(message)
{
diff --git a/test/fixtures/wpt/resources/web-bluetooth-bidi-test.js b/test/fixtures/wpt/resources/web-bluetooth-bidi-test.js
index 044ad1a43ae..3283fef43fc 100644
--- a/test/fixtures/wpt/resources/web-bluetooth-bidi-test.js
+++ b/test/fixtures/wpt/resources/web-bluetooth-bidi-test.js
@@ -6,12 +6,22 @@
function convertToBidiManufacturerData(manufacturerData) {
const bidiManufacturerData = [];
for (const key in manufacturerData) {
- bidiManufacturerData.push(
- {key: parseInt(key), data: btoa(manufacturerData[key].buffer)})
+ bidiManufacturerData.push({
+ key: parseInt(key),
+ data: btoa(String.fromCharCode(...manufacturerData[key]))
+ })
}
return bidiManufacturerData;
}
+function ArrayToMojoCharacteristicProperties(arr) {
+ const struct = {};
+ arr.forEach(property => {
+ struct[property] = true;
+ });
+ return struct;
+}
+
class FakeBluetooth {
constructor() {
this.fake_central_ = null;
@@ -63,7 +73,8 @@ class FakeCentral {
address: address,
name: name,
manufacturerData: convertToBidiManufacturerData(manufacturerData),
- knownServiceUuids: knownServiceUUIDs
+ knownServiceUuids:
+ knownServiceUUIDs.map(uuid => BluetoothUUID.getService(uuid))
});
return this.fetchOrCreatePeripheral_(address);
@@ -84,6 +95,312 @@ class FakePeripheral {
constructor(address) {
this.address = address;
}
+
+ // Adds a fake GATT Service with |uuid| to be discovered when discovering
+ // the peripheral's GATT Attributes. Returns a FakeRemoteGATTService
+ // corresponding to this service. |uuid| should be a BluetoothServiceUUIDs
+ // https://webbluetoothcg.github.io/web-bluetooth/#typedefdef-bluetoothserviceuuid
+ async addFakeService({uuid}) {
+ const service_uuid = BluetoothUUID.getService(uuid);
+ await test_driver.bidi.bluetooth.simulate_service({
+ address: this.address,
+ uuid: service_uuid,
+ type: 'add',
+ });
+ return new FakeRemoteGATTService(service_uuid, this.address);
+ }
+
+ // Sets the next GATT Connection request response to |code|. |code| could be
+ // an HCI Error Code from BT 4.2 Vol 2 Part D 1.3 List Of Error Codes or a
+ // number outside that range returned by specific platforms e.g. Android
+ // returns 0x101 to signal a GATT failure
+ // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#GATT_FAILURE
+ async setNextGATTConnectionResponse({code}) {
+ const remove_handler =
+ test_driver.bidi.bluetooth.gatt_connection_attempted.on((event) => {
+ if (event.address != this.address) {
+ return;
+ }
+ remove_handler();
+ test_driver.bidi.bluetooth.simulate_gatt_connection_response({
+ address: event.address,
+ code,
+ });
+ });
+ }
+
+ async setNextGATTDiscoveryResponse({code}) {
+ // No-op for Web Bluetooth Bidi test, it will be removed when migration
+ // completes.
+ return Promise.resolve();
+ }
+
+ // Simulates a GATT connection response with |code| from the peripheral.
+ async simulateGATTConnectionResponse(code) {
+ await test_driver.bidi.bluetooth.simulate_gatt_connection_response(
+ {address: this.address, code});
+ }
+
+ // Simulates a GATT disconnection in the peripheral.
+ async simulateGATTDisconnection() {
+ await test_driver.bidi.bluetooth.simulate_gatt_disconnection(
+ {address: this.address});
+ }
+}
+
+class FakeRemoteGATTService {
+ constructor(service_uuid, peripheral_address) {
+ this.service_uuid_ = service_uuid;
+ this.peripheral_address_ = peripheral_address;
+ }
+
+ // Adds a fake GATT Characteristic with |uuid| and |properties|
+ // to this fake service. The characteristic will be found when discovering
+ // the peripheral's GATT Attributes. Returns a FakeRemoteGATTCharacteristic
+ // corresponding to the added characteristic.
+ async addFakeCharacteristic({uuid, properties}) {
+ const characteristic_uuid = BluetoothUUID.getCharacteristic(uuid);
+ await test_driver.bidi.bluetooth.simulate_characteristic({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: characteristic_uuid,
+ characteristicProperties: ArrayToMojoCharacteristicProperties(properties),
+ type: 'add'
+ });
+ return new FakeRemoteGATTCharacteristic(
+ characteristic_uuid, this.service_uuid_, this.peripheral_address_);
+ }
+
+ // Removes the fake GATT service from its fake peripheral.
+ async remove() {
+ await test_driver.bidi.bluetooth.simulate_service({
+ address: this.peripheral_address_,
+ uuid: this.service_uuid_,
+ type: 'remove'
+ });
+ }
+}
+
+class FakeRemoteGATTCharacteristic {
+ constructor(characteristic_uuid, service_uuid, peripheral_address) {
+ this.characteristic_uuid_ = characteristic_uuid;
+ this.service_uuid_ = service_uuid;
+ this.peripheral_address_ = peripheral_address;
+ this.last_written_value_ = {lastValue: null, lastWriteType: 'none'};
+ }
+
+ // Adds a fake GATT Descriptor with |uuid| to be discovered when
+ // discovering the peripheral's GATT Attributes. Returns a
+ // FakeRemoteGATTDescriptor corresponding to this descriptor. |uuid| should
+ // be a BluetoothDescriptorUUID
+ // https://webbluetoothcg.github.io/web-bluetooth/#typedefdef-bluetoothdescriptoruuid
+ async addFakeDescriptor({uuid}) {
+ const descriptor_uuid = BluetoothUUID.getDescriptor(uuid);
+ await test_driver.bidi.bluetooth.simulate_descriptor({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: this.characteristic_uuid_,
+ descriptorUuid: descriptor_uuid,
+ type: 'add'
+ });
+ return new FakeRemoteGATTDescriptor(
+ descriptor_uuid, this.characteristic_uuid_, this.service_uuid_,
+ this.peripheral_address_);
+ }
+
+ // Simulate a characteristic for operation |type| with response |code| and
+ // |data|.
+ async simulateResponse(type, code, data) {
+ await test_driver.bidi.bluetooth.simulate_characteristic_response({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: this.characteristic_uuid_,
+ type,
+ code,
+ data,
+ });
+ }
+
+ // Simulate a characteristic response for read operation with response |code|
+ // and |data|.
+ async simulateReadResponse(code, data) {
+ await this.simulateResponse('read', code, data);
+ }
+
+ // Simulate a characteristic response for write operation with response
+ // |code|.
+ async simulateWriteResponse(code) {
+ await this.simulateResponse('write', code);
+ }
+
+ // Sets the next read response for characteristic to |code| and |value|.
+ // |code| could be a GATT Error Response from
+ // BT 4.2 Vol 3 Part F 3.4.1.1 Error Response or a number outside that range
+ // returned by specific platforms e.g. Android returns 0x101 to signal a GATT
+ // failure.
+ // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#GATT_FAILURE
+ async setNextReadResponse(gatt_code, value = null) {
+ if (gatt_code === 0 && value === null) {
+ throw '|value| can\'t be null if read should success.';
+ }
+ if (gatt_code !== 0 && value !== null) {
+ throw '|value| must be null if read should fail.';
+ }
+
+ const remove_handler =
+ test_driver.bidi.bluetooth.characteristic_event_generated.on(
+ (event) => {
+ if (event.address != this.peripheral_address_) {
+ return;
+ }
+ remove_handler();
+ this.simulateReadResponse(gatt_code, value);
+ });
+ }
+
+ // Sets the next write response for this characteristic to |code|. If
+ // writing to a characteristic that only supports 'write-without-response'
+ // the set response will be ignored.
+ // |code| could be a GATT Error Response from
+ // BT 4.2 Vol 3 Part F 3.4.1.1 Error Response or a number outside that range
+ // returned by specific platforms e.g. Android returns 0x101 to signal a GATT
+ // failure.
+ async setNextWriteResponse(gatt_code) {
+ const remove_handler =
+ test_driver.bidi.bluetooth.characteristic_event_generated.on(
+ (event) => {
+ if (event.address != this.peripheral_address_) {
+ return;
+ }
+ this.last_written_value_ = {
+ lastValue: event.data,
+ lastWriteType: event.type
+ };
+ remove_handler();
+ if (event.type == 'write-with-response') {
+ this.simulateWriteResponse(gatt_code);
+ }
+ });
+ }
+
+ // Gets the last successfully written value to the characteristic and its
+ // write type. Write type is one of 'none', 'default-deprecated',
+ // 'with-response', 'without-response'. Returns {lastValue: null,
+ // lastWriteType: 'none'} if no value has yet been written to the
+ // characteristic.
+ async getLastWrittenValue() {
+ return this.last_written_value_;
+ }
+
+ // Removes the fake GATT Characteristic from its fake service.
+ async remove() {
+ await test_driver.bidi.bluetooth.simulate_characteristic({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: this.characteristic_uuid_,
+ characteristicProperties: undefined,
+ type: 'remove'
+ });
+ }
+}
+
+class FakeRemoteGATTDescriptor {
+ constructor(
+ descriptor_uuid, characteristic_uuid, service_uuid, peripheral_address) {
+ this.descriptor_uuid_ = descriptor_uuid;
+ this.characteristic_uuid_ = characteristic_uuid;
+ this.service_uuid_ = service_uuid;
+ this.peripheral_address_ = peripheral_address;
+ this.last_written_value_ = null;
+ }
+
+ // Simulate a descriptor for operation |type| with response |code| and
+ // |data|.
+ async simulateResponse(type, code, data) {
+ await test_driver.bidi.bluetooth.simulate_descriptor_response({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: this.characteristic_uuid_,
+ descriptorUuid: this.descriptor_uuid_,
+ type,
+ code,
+ data,
+ });
+ }
+
+ // Simulate a descriptor response for read operation with response |code| and
+ // |data|.
+ async simulateReadResponse(code, data) {
+ await this.simulateResponse('read', code, data);
+ }
+
+ // Simulate a descriptor response for write operation with response |code|.
+ async simulateWriteResponse(code) {
+ await this.simulateResponse('write', code);
+ }
+
+ // Sets the next read response for descriptor to |code| and |value|.
+ // |code| could be a GATT Error Response from
+ // BT 4.2 Vol 3 Part F 3.4.1.1 Error Response or a number outside that range
+ // returned by specific platforms e.g. Android returns 0x101 to signal a GATT
+ // failure.
+ // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#GATT_FAILURE
+ async setNextReadResponse(gatt_code, value = null) {
+ if (gatt_code === 0 && value === null) {
+ throw '|value| can\'t be null if read should success.';
+ }
+ if (gatt_code !== 0 && value !== null) {
+ throw '|value| must be null if read should fail.';
+ }
+
+ const remove_handler =
+ test_driver.bidi.bluetooth.descriptor_event_generated.on((event) => {
+ if (event.address != this.peripheral_address_) {
+ return;
+ }
+ remove_handler();
+ this.simulateReadResponse(gatt_code, value);
+ });
+ }
+
+ // Sets the next write response for this descriptor to |code|.
+ // |code| could be a GATT Error Response from
+ // BT 4.2 Vol 3 Part F 3.4.1.1 Error Response or a number outside that range
+ // returned by specific platforms e.g. Android returns 0x101 to signal a GATT
+ // failure.
+ async setNextWriteResponse(gatt_code) {
+ const remove_handler =
+ test_driver.bidi.bluetooth.descriptor_event_generated.on((event) => {
+ if (event.address != this.peripheral_address_) {
+ return;
+ }
+ this.last_written_value_ = {
+ lastValue: event.data,
+ lastWriteType: event.type
+ };
+ remove_handler();
+ if (event.type == 'write-with-response') {
+ this.simulateWriteResponse(gatt_code);
+ }
+ });
+ }
+
+ // Gets the last successfully written value to the descriptor.
+ // Returns null if no value has yet been written to the descriptor.
+ async getLastWrittenValue() {
+ return this.last_written_value_;
+ }
+
+ // Removes the fake GATT Descriptor from its fake characteristic.
+ async remove() {
+ await test_driver.bidi.bluetooth.simulate_descriptor({
+ address: this.peripheral_address_,
+ serviceUuid: this.service_uuid_,
+ characteristicUuid: this.characteristic_uuid_,
+ descriptorUuid: this.descriptor_uuid_,
+ type: 'remove'
+ });
+ }
}
function initializeBluetoothBidiResources() {
diff --git a/test/fixtures/wpt/resources/webidl2/lib/VERSION.md b/test/fixtures/wpt/resources/webidl2/lib/VERSION.md
index 5a3726c6c00..2614a8d194b 100644
--- a/test/fixtures/wpt/resources/webidl2/lib/VERSION.md
+++ b/test/fixtures/wpt/resources/webidl2/lib/VERSION.md
@@ -1 +1 @@
-Currently using webidl2.js@6889aee6fc7d65915ab1267825248157dbc50486.
+Currently using webidl2.js@e6d8ab852ec4e76596f6e308eb7f2efc8b613bfd.
diff --git a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js
index 7161def899c..bae0b204759 100644
--- a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js
+++ b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js
@@ -17,7 +17,7 @@ return /******/ (() => { // webpackBootstrap
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "parse": () => (/* binding */ parse)
+/* harmony export */ parse: () => (/* binding */ parse)
/* harmony export */ });
/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15);
@@ -46,11 +46,22 @@ __webpack_require__.r(__webpack_exports__);
+/** @typedef {'callbackInterface'|'dictionary'|'interface'|'mixin'|'namespace'} ExtendableInterfaces */
+/** @typedef {{ extMembers?: import("./productions/container.js").AllowedMember[]}} Extension */
+/** @typedef {Partial>} Extensions */
+
+/**
+ * Parser options.
+ * @typedef {Object} ParserOptions
+ * @property {string} [sourceName]
+ * @property {boolean} [concrete]
+ * @property {Function[]} [productions]
+ * @property {Extensions} [extensions]
+ */
+
/**
* @param {Tokeniser} tokeniser
- * @param {object} options
- * @param {boolean} [options.concrete]
- * @param {Function[]} [options.productions]
+ * @param {ParserOptions} options
*/
function parseByTokens(tokeniser, options) {
const source = tokeniser.source;
@@ -67,7 +78,9 @@ function parseByTokens(tokeniser, options) {
const callback = consume("callback");
if (!callback) return;
if (tokeniser.probe("interface")) {
- return _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__.CallbackInterface.parse(tokeniser, callback);
+ return _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__.CallbackInterface.parse(tokeniser, callback, {
+ ...options?.extensions?.callbackInterface,
+ });
}
return _productions_callback_js__WEBPACK_IMPORTED_MODULE_5__.CallbackFunction.parse(tokeniser, callback);
}
@@ -75,20 +88,32 @@ function parseByTokens(tokeniser, options) {
function interface_(opts) {
const base = consume("interface");
if (!base) return;
- const ret =
- _productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__.Mixin.parse(tokeniser, base, opts) ||
- _productions_interface_js__WEBPACK_IMPORTED_MODULE_6__.Interface.parse(tokeniser, base, opts) ||
- error("Interface has no proper body");
- return ret;
+ return (
+ _productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__.Mixin.parse(tokeniser, base, {
+ ...opts,
+ ...options?.extensions?.mixin,
+ }) ||
+ _productions_interface_js__WEBPACK_IMPORTED_MODULE_6__.Interface.parse(tokeniser, base, {
+ ...opts,
+ ...options?.extensions?.interface,
+ }) ||
+ error("Interface has no proper body")
+ );
}
function partial() {
const partial = consume("partial");
if (!partial) return;
return (
- _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser, { partial }) ||
+ _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser, {
+ partial,
+ ...options?.extensions?.dictionary,
+ }) ||
interface_({ partial }) ||
- _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser, { partial }) ||
+ _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser, {
+ partial,
+ ...options?.extensions?.namespace,
+ }) ||
error("Partial doesn't apply to anything")
);
}
@@ -107,11 +132,11 @@ function parseByTokens(tokeniser, options) {
callback() ||
interface_() ||
partial() ||
- _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser) ||
+ _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser, options?.extensions?.dictionary) ||
_productions_enum_js__WEBPACK_IMPORTED_MODULE_1__.Enum.parse(tokeniser) ||
_productions_typedef_js__WEBPACK_IMPORTED_MODULE_4__.Typedef.parse(tokeniser) ||
_productions_includes_js__WEBPACK_IMPORTED_MODULE_2__.Includes.parse(tokeniser) ||
- _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser)
+ _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser, options?.extensions?.namespace)
);
}
@@ -134,6 +159,7 @@ function parseByTokens(tokeniser, options) {
}
return defs;
}
+
const res = definitions();
if (tokeniser.position < source.length) error("Unrecognised tokens");
return res;
@@ -141,11 +167,7 @@ function parseByTokens(tokeniser, options) {
/**
* @param {string} str
- * @param {object} [options]
- * @param {*} [options.sourceName]
- * @param {boolean} [options.concrete]
- * @param {Function[]} [options.productions]
- * @return {import("./productions/base.js").Base[]}
+ * @param {ParserOptions} [options]
*/
function parse(str, options = {}) {
const tokeniser = new _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__.Tokeniser(str);
@@ -163,11 +185,11 @@ function parse(str, options = {}) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Tokeniser": () => (/* binding */ Tokeniser),
-/* harmony export */ "WebIDLParseError": () => (/* binding */ WebIDLParseError),
-/* harmony export */ "argumentNameKeywords": () => (/* binding */ argumentNameKeywords),
-/* harmony export */ "stringTypes": () => (/* binding */ stringTypes),
-/* harmony export */ "typeNameKeywords": () => (/* binding */ typeNameKeywords)
+/* harmony export */ Tokeniser: () => (/* binding */ Tokeniser),
+/* harmony export */ WebIDLParseError: () => (/* binding */ WebIDLParseError),
+/* harmony export */ argumentNameKeywords: () => (/* binding */ argumentNameKeywords),
+/* harmony export */ stringTypes: () => (/* binding */ stringTypes),
+/* harmony export */ typeNameKeywords: () => (/* binding */ typeNameKeywords)
/* harmony export */ });
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
/* harmony import */ var _productions_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -191,6 +213,7 @@ const tokenRe = {
const typeNameKeywords = [
"ArrayBuffer",
+ "SharedArrayBuffer",
"DataView",
"Int8Array",
"Int16Array",
@@ -201,6 +224,7 @@ const typeNameKeywords = [
"Uint8ClampedArray",
"BigInt64Array",
"BigUint64Array",
+ "Float16Array",
"Float32Array",
"Float64Array",
"any",
@@ -243,6 +267,8 @@ const nonRegexTerminals = [
"NaN",
"ObservableArray",
"Promise",
+ "async_iterable",
+ "async_sequence",
"bigint",
"boolean",
"byte",
@@ -327,10 +353,10 @@ function tokenise(str) {
if (result !== -1) {
if (reserved.includes(token.value)) {
const message = `${(0,_productions_helpers_js__WEBPACK_IMPORTED_MODULE_1__.unescape)(
- token.value
+ token.value,
)} is a reserved identifier and must not be used.`;
throw new WebIDLParseError(
- (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(tokens, lastIndex, null, message)
+ (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(tokens, lastIndex, null, message),
);
} else if (nonRegexTerminals.includes(token.value)) {
token.type = "inline";
@@ -414,7 +440,7 @@ class Tokeniser {
*/
error(message) {
throw new WebIDLParseError(
- (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(this.source, this.position, this.current, message)
+ (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(this.source, this.position, this.current, message),
);
}
@@ -522,8 +548,8 @@ class WebIDLParseError extends Error {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "syntaxError": () => (/* binding */ syntaxError),
-/* harmony export */ "validationError": () => (/* binding */ validationError)
+/* harmony export */ syntaxError: () => (/* binding */ syntaxError),
+/* harmony export */ validationError: () => (/* binding */ validationError)
/* harmony export */ });
/**
* @param {string} text
@@ -572,7 +598,7 @@ function error(
current,
message,
kind,
- { level = "error", autofix, ruleName } = {}
+ { level = "error", autofix, ruleName } = {},
) {
/**
* @param {number} count
@@ -606,11 +632,11 @@ function error(
source[position].type !== "eof"
? source[position].line
: source.length > 1
- ? source[position - 1].line
- : 1;
+ ? source[position - 1].line
+ : 1;
const precedingLastLine = lastLine(
- tokensToText(sliceTokens(-maxTokens), { precedes: true })
+ tokensToText(sliceTokens(-maxTokens), { precedes: true }),
);
const subsequentTokens = sliceTokens(maxTokens);
@@ -625,7 +651,7 @@ function error(
const grammaticalContext =
current && current.name
? `, ${contextType} \`${current.partial ? "partial " : ""}${contextAsText(
- current
+ current,
)}\``
: "";
const context = `${kind} error at line ${line}${inSourceName}${grammaticalContext}:\n${sourceContext}`;
@@ -659,7 +685,7 @@ function validationError(
current,
ruleName,
message,
- options = {}
+ options = {},
) {
options.ruleName = ruleName;
return error(
@@ -668,7 +694,7 @@ function validationError(
current,
message,
"Validation",
- options
+ options,
);
}
@@ -679,21 +705,21 @@ function validationError(
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "argument_list": () => (/* binding */ argument_list),
-/* harmony export */ "autoParenter": () => (/* binding */ autoParenter),
-/* harmony export */ "autofixAddExposedWindow": () => (/* binding */ autofixAddExposedWindow),
-/* harmony export */ "const_data": () => (/* binding */ const_data),
-/* harmony export */ "const_value": () => (/* binding */ const_value),
-/* harmony export */ "findLastIndex": () => (/* binding */ findLastIndex),
-/* harmony export */ "getFirstToken": () => (/* binding */ getFirstToken),
-/* harmony export */ "getLastIndentation": () => (/* binding */ getLastIndentation),
-/* harmony export */ "getMemberIndentation": () => (/* binding */ getMemberIndentation),
-/* harmony export */ "list": () => (/* binding */ list),
-/* harmony export */ "primitive_type": () => (/* binding */ primitive_type),
-/* harmony export */ "return_type": () => (/* binding */ return_type),
-/* harmony export */ "stringifier": () => (/* binding */ stringifier),
-/* harmony export */ "type_with_extended_attributes": () => (/* binding */ type_with_extended_attributes),
-/* harmony export */ "unescape": () => (/* binding */ unescape)
+/* harmony export */ argument_list: () => (/* binding */ argument_list),
+/* harmony export */ autoParenter: () => (/* binding */ autoParenter),
+/* harmony export */ autofixAddExposedWindow: () => (/* binding */ autofixAddExposedWindow),
+/* harmony export */ const_data: () => (/* binding */ const_data),
+/* harmony export */ const_value: () => (/* binding */ const_value),
+/* harmony export */ findLastIndex: () => (/* binding */ findLastIndex),
+/* harmony export */ getFirstToken: () => (/* binding */ getFirstToken),
+/* harmony export */ getLastIndentation: () => (/* binding */ getLastIndentation),
+/* harmony export */ getMemberIndentation: () => (/* binding */ getMemberIndentation),
+/* harmony export */ list: () => (/* binding */ list),
+/* harmony export */ primitive_type: () => (/* binding */ primitive_type),
+/* harmony export */ return_type: () => (/* binding */ return_type),
+/* harmony export */ stringifier: () => (/* binding */ stringifier),
+/* harmony export */ type_with_extended_attributes: () => (/* binding */ type_with_extended_attributes),
+/* harmony export */ unescape: () => (/* binding */ unescape)
/* harmony export */ });
/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
/* harmony import */ var _argument_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
@@ -816,7 +842,7 @@ function primitive_type(tokeniser) {
"boolean",
"byte",
"octet",
- "undefined"
+ "undefined",
);
if (base) {
return new _type_js__WEBPACK_IMPORTED_MODULE_0__.Type({ source, tokens: { base } });
@@ -917,7 +943,7 @@ function autofixAddExposedWindow(def) {
def.extAttrs.unshift(exposed);
} else {
autoParenter(def).extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__.ExtendedAttributes.parse(
- new _tokeniser_js__WEBPACK_IMPORTED_MODULE_5__.Tokeniser("[Exposed=Window]")
+ new _tokeniser_js__WEBPACK_IMPORTED_MODULE_5__.Tokeniser("[Exposed=Window]"),
);
const trivia = def.tokens.base.trivia;
def.extAttrs.tokens.open.trivia = trivia;
@@ -1010,7 +1036,7 @@ function autoParenter(data, parent) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Type": () => (/* binding */ Type)
+/* harmony export */ Type: () => (/* binding */ Type)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -1034,14 +1060,15 @@ function generic_type(tokeniser, typeName) {
"FrozenArray",
"ObservableArray",
"Promise",
+ "async_sequence",
"sequence",
- "record"
+ "record",
);
if (!base) {
return;
}
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(
- new Type({ source: tokeniser.source, tokens: { base } })
+ new Type({ source: tokeniser.source, tokens: { base } }),
);
ret.tokens.open =
tokeniser.consume("<") ||
@@ -1056,6 +1083,7 @@ function generic_type(tokeniser, typeName) {
ret.subtype.push(subtype);
break;
}
+ case "async_sequence":
case "sequence":
case "FrozenArray":
case "ObservableArray": {
@@ -1143,7 +1171,7 @@ function union_type(tokeniser, type) {
ret.type = type || null;
while (true) {
const typ =
- (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser) ||
+ (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser, type) ||
tokeniser.error("No type after open parenthesis or 'or' in union type");
if (typ.idlType === "any")
tokeniser.error("Type `any` cannot be included in a union type");
@@ -1157,7 +1185,7 @@ function union_type(tokeniser, type) {
}
if (ret.idlType.length < 2) {
tokeniser.error(
- "At least two types are expected in a union type but found less"
+ "At least two types are expected in a union type but found less",
);
}
tokens.close =
@@ -1208,6 +1236,26 @@ class Type extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
*validate(defs) {
yield* this.extAttrs.validate(defs);
+ if (this.idlType === "BufferSource") {
+ // XXX: For now this is a hack. Consider moving parents' extAttrs into types as the spec says:
+ // https://webidl.spec.whatwg.org/#idl-annotated-types
+ for (const extAttrs of [this.extAttrs, this.parent?.extAttrs]) {
+ for (const extAttr of extAttrs) {
+ if (extAttr.name !== "AllowShared") {
+ continue;
+ }
+ const message = `\`[AllowShared] BufferSource\` is now replaced with AllowSharedBufferSource.`;
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_3__.validationError)(
+ this.tokens.base,
+ this,
+ "migrate-allowshared",
+ message,
+ { autofix: replaceAllowShared(this, extAttr, extAttrs) },
+ );
+ }
+ }
+ }
+
if (this.idlType === "void") {
const message = `\`void\` is now replaced by \`undefined\`. Refer to the \
[relevant GitHub issue](https://github.com/whatwg/webidl/issues/60) \
@@ -1225,8 +1273,8 @@ for more information.`;
const target = this.union
? this
: typedef && typedef.type === "typedef"
- ? typedef.idlType
- : undefined;
+ ? typedef.idlType
+ : undefined;
if (target && this.nullable) {
// do not allow any dictionary
const { reference } = (0,_validators_helpers_js__WEBPACK_IMPORTED_MODULE_4__.idlTypeIncludesDictionary)(target, defs) || {};
@@ -1237,7 +1285,7 @@ for more information.`;
targetToken,
this,
"no-nullable-union-dict",
- message
+ message,
);
}
} else {
@@ -1274,7 +1322,7 @@ for more information.`;
this.idlType
),
context: this,
- }
+ },
);
return w.ts.wrap([w.ts.trivia(firstToken.trivia), ref]);
};
@@ -1287,6 +1335,23 @@ for more information.`;
}
}
+/**
+ * @param {Type} type
+ * @param {import("./extended-attributes.js").SimpleExtendedAttribute} extAttr
+ * @param {ExtendedAttributes} extAttrs
+ */
+function replaceAllowShared(type, extAttr, extAttrs) {
+ return () => {
+ const index = extAttrs.indexOf(extAttr);
+ extAttrs.splice(index, 1);
+ if (!extAttrs.length && type.tokens.base.trivia.match(/^\s$/)) {
+ type.tokens.base.trivia = ""; // (let's not remove comments)
+ }
+
+ type.tokens.base.value = "AllowSharedBufferSource";
+ };
+}
+
/**
* @param {Type} type
*/
@@ -1303,7 +1368,7 @@ function replaceVoid(type) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Base": () => (/* binding */ Base)
+/* harmony export */ Base: () => (/* binding */ Base)
/* harmony export */ });
class Base {
/**
@@ -1344,14 +1409,17 @@ class Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "dictionaryIncludesRequiredField": () => (/* binding */ dictionaryIncludesRequiredField),
-/* harmony export */ "idlTypeIncludesDictionary": () => (/* binding */ idlTypeIncludesDictionary)
+/* harmony export */ dictionaryIncludesRequiredField: () => (/* binding */ dictionaryIncludesRequiredField),
+/* harmony export */ idlTypeIncludesDictionary: () => (/* binding */ idlTypeIncludesDictionary),
+/* harmony export */ idlTypeIncludesEnforceRange: () => (/* binding */ idlTypeIncludesEnforceRange)
/* harmony export */ });
/**
+ * @typedef {import("../validator.js").Definitions} Definitions
* @typedef {import("../productions/dictionary.js").Dictionary} Dictionary
+ * @typedef {import("../../lib/productions/type").Type} Type
*
- * @param {*} idlType
- * @param {import("../validator.js").Definitions} defs
+ * @param {Type} idlType
+ * @param {Definitions} defs
* @param {object} [options]
* @param {boolean} [options.useNullableInner] use when the input idlType is nullable and you want to use its inner type
* @return {{ reference: *, dictionary: Dictionary }} the type reference that ultimately includes dictionary.
@@ -1359,7 +1427,7 @@ __webpack_require__.r(__webpack_exports__);
function idlTypeIncludesDictionary(
idlType,
defs,
- { useNullableInner } = {}
+ { useNullableInner } = {},
) {
if (!idlType.union) {
const def = defs.unique.get(idlType.idlType);
@@ -1405,8 +1473,8 @@ function idlTypeIncludesDictionary(
}
/**
- * @param {*} dict dictionary type
- * @param {import("../validator.js").Definitions} defs
+ * @param {Dictionary} dict dictionary type
+ * @param {Definitions} defs
* @return {boolean}
*/
function dictionaryIncludesRequiredField(dict, defs) {
@@ -1430,6 +1498,34 @@ function dictionaryIncludesRequiredField(dict, defs) {
return result;
}
+/**
+ * For now this only checks the most frequent cases:
+ * 1. direct inclusion of [EnforceRange]
+ * 2. typedef of that
+ *
+ * More complex cases with dictionaries and records are not covered yet.
+ *
+ * @param {Type} idlType
+ * @param {Definitions} defs
+ */
+function idlTypeIncludesEnforceRange(idlType, defs) {
+ if (idlType.union) {
+ // TODO: This should ideally be checked too
+ return false;
+ }
+
+ if (idlType.extAttrs.some((e) => e.name === "EnforceRange")) {
+ return true;
+ }
+
+ const def = defs.unique.get(idlType.idlType);
+ if (def?.type !== "typedef") {
+ return false;
+ }
+
+ return def.idlType.extAttrs.some((e) => e.name === "EnforceRange");
+}
+
/***/ }),
/* 8 */
@@ -1437,9 +1533,9 @@ function dictionaryIncludesRequiredField(dict, defs) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "ExtendedAttributeParameters": () => (/* binding */ ExtendedAttributeParameters),
-/* harmony export */ "ExtendedAttributes": () => (/* binding */ ExtendedAttributes),
-/* harmony export */ "SimpleExtendedAttribute": () => (/* binding */ SimpleExtendedAttribute)
+/* harmony export */ ExtendedAttributeParameters: () => (/* binding */ ExtendedAttributeParameters),
+/* harmony export */ ExtendedAttributes: () => (/* binding */ ExtendedAttributes),
+/* harmony export */ SimpleExtendedAttribute: () => (/* binding */ SimpleExtendedAttribute)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _array_base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
@@ -1494,7 +1590,7 @@ function extAttrListItems(tokeniser) {
}
}
tokeniser.error(
- `Expected identifiers, strings, decimals, or integers but none found`
+ `Expected identifiers, strings, decimals, or integers but none found`,
);
}
@@ -1505,7 +1601,7 @@ class ExtendedAttributeParameters extends _base_js__WEBPACK_IMPORTED_MODULE_0__.
static parse(tokeniser) {
const tokens = { assign: tokeniser.consume("=") };
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.autoParenter)(
- new ExtendedAttributeParameters({ source: tokeniser.source, tokens })
+ new ExtendedAttributeParameters({ source: tokeniser.source, tokens }),
);
ret.list = [];
if (tokens.assign) {
@@ -1603,8 +1699,8 @@ class SimpleExtendedAttribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base
const value = this.params.rhsIsList
? list
: this.params.tokens.secondaryName
- ? (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.unescape)(tokens.secondaryName.value)
- : null;
+ ? (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.unescape)(tokens.secondaryName.value)
+ : null;
return { type, value };
}
get arguments() {
@@ -1627,7 +1723,7 @@ information.`;
this,
"no-nointerfaceobject",
message,
- { level: "warning" }
+ { level: "warning" },
);
} else if (renamedLegacies.has(name)) {
const message = `\`[${name}]\` extended attribute is a legacy feature \
@@ -1652,7 +1748,7 @@ information.`;
w.ts.wrap([
w.ts.extendedAttributeReference(this.name),
this.params.write(w),
- ])
+ ]),
),
w.token(this.tokens.separator),
]);
@@ -1687,12 +1783,12 @@ class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__.Arr
...(0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.list)(tokeniser, {
parser: SimpleExtendedAttribute.parse,
listName: "extended attribute",
- })
+ }),
);
tokens.close =
tokeniser.consume("]") ||
tokeniser.error(
- "Expected a closing token for the extended attribute list"
+ "Expected a closing token for the extended attribute list",
);
if (!ret.length) {
tokeniser.unconsume(tokens.close.index);
@@ -1700,7 +1796,7 @@ class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__.Arr
}
if (tokeniser.probe("[")) {
tokeniser.error(
- "Illegal double extended attribute lists, consider merging them"
+ "Illegal double extended attribute lists, consider merging them",
);
}
return ret;
@@ -1730,7 +1826,7 @@ class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__.Arr
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "ArrayBase": () => (/* binding */ ArrayBase)
+/* harmony export */ ArrayBase: () => (/* binding */ ArrayBase)
/* harmony export */ });
class ArrayBase extends Array {
constructor({ source, tokens }) {
@@ -1750,8 +1846,8 @@ class ArrayBase extends Array {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Eof": () => (/* binding */ Eof),
-/* harmony export */ "WrappedToken": () => (/* binding */ WrappedToken)
+/* harmony export */ Eof: () => (/* binding */ Eof),
+/* harmony export */ WrappedToken: () => (/* binding */ WrappedToken)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -1775,6 +1871,10 @@ class WrappedToken extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
};
}
+ get type() {
+ return this.tokens.value.type;
+ }
+
get value() {
return (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.unescape)(this.tokens.value.value);
}
@@ -1811,7 +1911,7 @@ class Eof extends WrappedToken {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Argument": () => (/* binding */ Argument)
+/* harmony export */ Argument: () => (/* binding */ Argument)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _default_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12);
@@ -1837,7 +1937,7 @@ class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/** @type {Base["tokens"]} */
const tokens = {};
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.autoParenter)(
- new Argument({ source: tokeniser.source, tokens })
+ new Argument({ source: tokeniser.source, tokens }),
);
ret.extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__.ExtendedAttributes.parse(tokeniser);
tokens.optional = tokeniser.consume("optional");
@@ -1887,7 +1987,7 @@ class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
this.tokens.name,
this,
"no-nullable-dict-arg",
- message
+ message,
);
} else if (!this.optional) {
if (
@@ -1903,7 +2003,7 @@ class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
message,
{
autofix: autofixDictionaryArgumentOptionality(this),
- }
+ },
);
}
} else if (!this.default) {
@@ -1915,7 +2015,7 @@ class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
message,
{
autofix: autofixOptionalDictionaryDefaultValue(this),
- }
+ },
);
}
}
@@ -1977,7 +2077,7 @@ function autofixOptionalDictionaryDefaultValue(arg) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Default": () => (/* binding */ Default)
+/* harmony export */ Default: () => (/* binding */ Default)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -2049,7 +2149,7 @@ class Default extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Operation": () => (/* binding */ Operation)
+/* harmony export */ Operation: () => (/* binding */ Operation)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -2060,17 +2160,15 @@ __webpack_require__.r(__webpack_exports__);
class Operation extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/**
- * @typedef {import("../tokeniser.js").Token} Token
- *
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {object} [options]
- * @param {Token} [options.special]
- * @param {Token} [options.regular]
+ * @param {import("../tokeniser.js").Token} [options.special]
+ * @param {import("../tokeniser.js").Token} [options.regular]
*/
static parse(tokeniser, { special, regular } = {}) {
const tokens = { special };
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(
- new Operation({ source: tokeniser.source, tokens })
+ new Operation({ source: tokeniser.source, tokens }),
);
if (special && special.value === "stringifier") {
tokens.termination = tokeniser.consume(";");
@@ -2121,6 +2219,15 @@ class Operation extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
yield (0,_error_js__WEBPACK_IMPORTED_MODULE_2__.validationError)(this.tokens.open, this, "incomplete-op", message);
}
if (this.idlType) {
+ if (this.idlType.generic === "async_sequence") {
+ const message = `async_sequence types cannot be returned by an operation.`;
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_2__.validationError)(
+ this.idlType.tokens.base,
+ this,
+ "async-sequence-idl-to-js",
+ message,
+ );
+ }
yield* this.idlType.validate(defs);
}
for (const argument of this.arguments) {
@@ -2149,7 +2256,7 @@ class Operation extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
...body,
w.token(this.tokens.termination),
]),
- { data: this, parent }
+ { data: this, parent },
);
}
}
@@ -2161,7 +2268,7 @@ class Operation extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Attribute": () => (/* binding */ Attribute)
+/* harmony export */ Attribute: () => (/* binding */ Attribute)
/* harmony export */ });
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
/* harmony import */ var _validators_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
@@ -2182,12 +2289,12 @@ class Attribute extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
*/
static parse(
tokeniser,
- { special, noInherit = false, readonly = false } = {}
+ { special, noInherit = false, readonly = false } = {},
) {
const start_position = tokeniser.position;
const tokens = { special };
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.autoParenter)(
- new Attribute({ source: tokeniser.source, tokens })
+ new Attribute({ source: tokeniser.source, tokens }),
);
if (!special && !noInherit) {
tokens.special = tokeniser.consume("inherit");
@@ -2237,32 +2344,34 @@ class Attribute extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
yield* this.extAttrs.validate(defs);
yield* this.idlType.validate(defs);
- switch (this.idlType.generic) {
- case "sequence":
- case "record": {
- const message = `Attributes cannot accept ${this.idlType.generic} types.`;
- yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(
- this.tokens.name,
- this,
- "attr-invalid-type",
- message
- );
- break;
+ if (
+ ["async_sequence", "sequence", "record"].includes(this.idlType.generic)
+ ) {
+ const message = `Attributes cannot accept ${this.idlType.generic} types.`;
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(
+ this.tokens.name,
+ this,
+ "attr-invalid-type",
+ message,
+ );
+ }
+
+ {
+ const { reference } = (0,_validators_helpers_js__WEBPACK_IMPORTED_MODULE_1__.idlTypeIncludesDictionary)(this.idlType, defs) || {};
+ if (reference) {
+ const targetToken = (this.idlType.union ? reference : this.idlType)
+ .tokens.base;
+ const message = "Attributes cannot accept dictionary types.";
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(targetToken, this, "attr-invalid-type", message);
}
- default: {
- const { reference } =
- (0,_validators_helpers_js__WEBPACK_IMPORTED_MODULE_1__.idlTypeIncludesDictionary)(this.idlType, defs) || {};
- if (reference) {
- const targetToken = (this.idlType.union ? reference : this.idlType)
- .tokens.base;
- const message = "Attributes cannot accept dictionary types.";
- yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(
- targetToken,
- this,
- "attr-invalid-type",
- message
- );
- }
+ }
+
+ if (this.readonly) {
+ if ((0,_validators_helpers_js__WEBPACK_IMPORTED_MODULE_1__.idlTypeIncludesEnforceRange)(this.idlType, defs)) {
+ const targetToken = this.idlType.tokens.base;
+ const message =
+ "Readonly attributes cannot accept [EnforceRange] extended attribute.";
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(targetToken, this, "attr-invalid-type", message);
}
}
}
@@ -2280,7 +2389,7 @@ class Attribute extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
w.name_token(this.tokens.name, { data: this, parent }),
w.token(this.tokens.termination),
]),
- { data: this, parent }
+ { data: this, parent },
);
}
}
@@ -2292,8 +2401,8 @@ class Attribute extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Enum": () => (/* binding */ Enum),
-/* harmony export */ "EnumValue": () => (/* binding */ EnumValue)
+/* harmony export */ Enum: () => (/* binding */ Enum),
+/* harmony export */ EnumValue: () => (/* binding */ EnumValue)
/* harmony export */ });
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
@@ -2327,7 +2436,7 @@ class EnumValue extends _token_js__WEBPACK_IMPORTED_MODULE_1__.WrappedToken {
w.ts.trivia(this.tokens.value.trivia),
w.ts.definition(
w.ts.wrap(['"', w.ts.name(this.value, { data: this, parent }), '"']),
- { data: this, parent }
+ { data: this, parent },
),
w.token(this.tokens.separator),
]);
@@ -2388,7 +2497,7 @@ class Enum extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
w.token(this.tokens.close),
w.token(this.tokens.termination),
]),
- { data: this }
+ { data: this },
);
}
}
@@ -2400,7 +2509,7 @@ class Enum extends _base_js__WEBPACK_IMPORTED_MODULE_2__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Includes": () => (/* binding */ Includes)
+/* harmony export */ Includes: () => (/* binding */ Includes)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -2451,7 +2560,7 @@ class Includes extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.reference_token(this.tokens.mixin, this),
w.token(this.tokens.termination),
]),
- { data: this }
+ { data: this },
);
}
}
@@ -2463,7 +2572,7 @@ class Includes extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Typedef": () => (/* binding */ Typedef)
+/* harmony export */ Typedef: () => (/* binding */ Typedef)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -2516,7 +2625,7 @@ class Typedef extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.name_token(this.tokens.name, { data: this }),
w.token(this.tokens.termination),
]),
- { data: this }
+ { data: this },
);
}
}
@@ -2528,10 +2637,12 @@ class Typedef extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "CallbackFunction": () => (/* binding */ CallbackFunction)
+/* harmony export */ CallbackFunction: () => (/* binding */ CallbackFunction)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
+/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
+
@@ -2542,7 +2653,7 @@ class CallbackFunction extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
static parse(tokeniser, base) {
const tokens = { base };
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(
- new CallbackFunction({ source: tokeniser.source, tokens })
+ new CallbackFunction({ source: tokeniser.source, tokens }),
);
tokens.name =
tokeniser.consumeKind("identifier") ||
@@ -2573,6 +2684,18 @@ class CallbackFunction extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
*validate(defs) {
yield* this.extAttrs.validate(defs);
+ for (const arg of this.arguments) {
+ yield* arg.validate(defs);
+ if (arg.idlType.generic === "async_sequence") {
+ const message = `async_sequence types cannot be returned as a callback argument.`;
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_2__.validationError)(
+ arg.tokens.name,
+ arg,
+ "async-sequence-idl-to-js",
+ message,
+ );
+ }
+ }
yield* this.idlType.validate(defs);
}
@@ -2590,7 +2713,7 @@ class CallbackFunction extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.close),
w.token(this.tokens.termination),
]),
- { data: this }
+ { data: this },
);
}
}
@@ -2602,7 +2725,7 @@ class CallbackFunction extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Interface": () => (/* binding */ Interface)
+/* harmony export */ Interface: () => (/* binding */ Interface)
/* harmony export */ });
/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20);
/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14);
@@ -2643,8 +2766,12 @@ function static_member(tokeniser) {
class Interface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
+ * @param {import("../tokeniser.js").Token} base
+ * @param {object} [options]
+ * @param {import("./container.js").AllowedMember[]} [options.extMembers]
+ * @param {import("../tokeniser.js").Token|null} [options.partial]
*/
- static parse(tokeniser, base, { partial = null } = {}) {
+ static parse(tokeniser, base, { extMembers = [], partial = null } = {}) {
const tokens = { partial, base };
return _container_js__WEBPACK_IMPORTED_MODULE_0__.Container.parse(
tokeniser,
@@ -2652,6 +2779,7 @@ class Interface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
{
inheritable: !partial,
allowedMembers: [
+ ...extMembers,
[_constant_js__WEBPACK_IMPORTED_MODULE_3__.Constant.parse],
[_constructor_js__WEBPACK_IMPORTED_MODULE_8__.Constructor.parse],
[static_member],
@@ -2660,7 +2788,7 @@ class Interface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
[_attribute_js__WEBPACK_IMPORTED_MODULE_1__.Attribute.parse],
[_operation_js__WEBPACK_IMPORTED_MODULE_2__.Operation.parse],
],
- }
+ },
);
}
@@ -2686,11 +2814,11 @@ for more information.`;
message,
{
autofix: (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.autofixAddExposedWindow)(this),
- }
+ },
);
}
const oldConstructors = this.extAttrs.filter(
- (extAttr) => extAttr.name === "Constructor"
+ (extAttr) => extAttr.name === "Constructor",
);
for (const constructor of oldConstructors) {
const message = `Constructors should now be represented as a \`constructor()\` operation on the interface \
@@ -2704,14 +2832,14 @@ for more information.`;
message,
{
autofix: autofixConstructor(this, constructor),
- }
+ },
);
}
const isGlobal = this.extAttrs.some((extAttr) => extAttr.name === "Global");
if (isGlobal) {
const factoryFunctions = this.extAttrs.filter(
- (extAttr) => extAttr.name === "LegacyFactoryFunction"
+ (extAttr) => extAttr.name === "LegacyFactoryFunction",
);
for (const named of factoryFunctions) {
const message = `Interfaces marked as \`[Global]\` cannot have factory functions.`;
@@ -2719,12 +2847,12 @@ for more information.`;
named.tokens.name,
this,
"no-constructible-global",
- message
+ message,
);
}
const constructors = this.members.filter(
- (member) => member.type === "constructor"
+ (member) => member.type === "constructor",
);
for (const named of constructors) {
const message = `Interfaces marked as \`[Global]\` cannot have constructors.`;
@@ -2732,7 +2860,7 @@ for more information.`;
named.tokens.base,
this,
"no-constructible-global",
- message
+ message,
);
}
}
@@ -2748,13 +2876,13 @@ function autofixConstructor(interfaceDef, constructorExtAttr) {
interfaceDef = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.autoParenter)(interfaceDef);
return () => {
const indentation = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.getLastIndentation)(
- interfaceDef.extAttrs.tokens.open.trivia
+ interfaceDef.extAttrs.tokens.open.trivia,
);
const memberIndent = interfaceDef.members.length
? (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.getLastIndentation)((0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.getFirstToken)(interfaceDef.members[0]).trivia)
: (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.getMemberIndentation)(indentation);
const constructorOp = _constructor_js__WEBPACK_IMPORTED_MODULE_8__.Constructor.parse(
- new _tokeniser_js__WEBPACK_IMPORTED_MODULE_9__.Tokeniser(`\n${memberIndent}constructor();`)
+ new _tokeniser_js__WEBPACK_IMPORTED_MODULE_9__.Tokeniser(`\n${memberIndent}constructor();`),
);
constructorOp.extAttrs = new _extended_attributes_js__WEBPACK_IMPORTED_MODULE_10__.ExtendedAttributes({
source: interfaceDef.source,
@@ -2764,7 +2892,7 @@ function autofixConstructor(interfaceDef, constructorExtAttr) {
const existingIndex = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_5__.findLastIndex)(
interfaceDef.members,
- (m) => m.type === "constructor"
+ (m) => m.type === "constructor",
);
interfaceDef.members.splice(existingIndex + 1, 0, constructorOp);
@@ -2793,7 +2921,7 @@ function autofixConstructor(interfaceDef, constructorExtAttr) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Container": () => (/* binding */ Container)
+/* harmony export */ Container: () => (/* binding */ Container)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
@@ -2816,6 +2944,19 @@ function inheritance(tokeniser) {
return { colon, inheritance };
}
+/**
+ * Parser callback.
+ * @callback ParserCallback
+ * @param {import("../tokeniser.js").Tokeniser} tokeniser
+ * @param {...*} args
+ */
+
+/**
+ * A parser callback and optional option object.
+ * @typedef AllowedMember
+ * @type {[ParserCallback, object?]}
+ */
+
class Container extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
@@ -2889,7 +3030,7 @@ class Container extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.colon),
w.ts.trivia(this.tokens.inheritance.trivia),
w.ts.inheritance(
- w.reference(this.tokens.inheritance.value, { context: this })
+ w.reference(this.tokens.inheritance.value, { context: this }),
),
]);
};
@@ -2908,7 +3049,7 @@ class Container extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.close),
w.token(this.tokens.termination),
]),
- { data: this }
+ { data: this },
);
}
}
@@ -2920,7 +3061,7 @@ class Container extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Constant": () => (/* binding */ Constant)
+/* harmony export */ Constant: () => (/* binding */ Constant)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
@@ -2989,7 +3130,7 @@ class Constant extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.value),
w.token(this.tokens.termination),
]),
- { data: this, parent }
+ { data: this, parent },
);
}
}
@@ -3001,21 +3142,23 @@ class Constant extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "IterableLike": () => (/* binding */ IterableLike)
+/* harmony export */ IterableLike: () => (/* binding */ IterableLike)
/* harmony export */ });
-/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
-/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
+/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
+/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
+
-class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
+class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_1__.Base {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
static parse(tokeniser) {
const start_position = tokeniser.position;
- const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(
- new IterableLike({ source: tokeniser.source, tokens: {} })
+ const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_2__.autoParenter)(
+ new IterableLike({ source: tokeniser.source, tokens: {} }),
);
const { tokens } = ret;
tokens.readonly = tokeniser.consume("readonly");
@@ -3025,8 +3168,8 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
tokens.base = tokens.readonly
? tokeniser.consume("maplike", "setlike")
: tokens.async
- ? tokeniser.consume("iterable")
- : tokeniser.consume("iterable", "maplike", "setlike");
+ ? tokeniser.consume("iterable")
+ : tokeniser.consume("iterable", "async_iterable", "maplike", "setlike");
if (!tokens.base) {
tokeniser.unconsume(start_position);
return;
@@ -3034,14 +3177,16 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
const { type } = ret;
const secondTypeRequired = type === "maplike";
- const secondTypeAllowed = secondTypeRequired || type === "iterable";
- const argumentAllowed = ret.async && type === "iterable";
+ const secondTypeAllowed =
+ secondTypeRequired || type === "iterable" || type === "async_iterable";
+ const argumentAllowed =
+ type === "async_iterable" || (ret.async && type === "iterable");
tokens.open =
tokeniser.consume("<") ||
tokeniser.error(`Missing less-than sign \`<\` in ${type} declaration`);
const first =
- (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser) ||
+ (0,_helpers_js__WEBPACK_IMPORTED_MODULE_2__.type_with_extended_attributes)(tokeniser) ||
tokeniser.error(`Missing a type argument in ${type} declaration`);
ret.idlType = [first];
ret.arguments = [];
@@ -3049,7 +3194,7 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
if (secondTypeAllowed) {
first.tokens.separator = tokeniser.consume(",");
if (first.tokens.separator) {
- ret.idlType.push((0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser));
+ ret.idlType.push((0,_helpers_js__WEBPACK_IMPORTED_MODULE_2__.type_with_extended_attributes)(tokeniser));
} else if (secondTypeRequired) {
tokeniser.error(`Missing second type argument in ${type} declaration`);
}
@@ -3062,7 +3207,7 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
if (tokeniser.probe("(")) {
if (argumentAllowed) {
tokens.argsOpen = tokeniser.consume("(");
- ret.arguments.push(...(0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.argument_list)(tokeniser));
+ ret.arguments.push(...(0,_helpers_js__WEBPACK_IMPORTED_MODULE_2__.argument_list)(tokeniser));
tokens.argsClose =
tokeniser.consume(")") ||
tokeniser.error("Unterminated async iterable argument list");
@@ -3089,6 +3234,18 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
}
*validate(defs) {
+ if (this.async && this.type === "iterable") {
+ const message = "`async iterable` is now changed to `async_iterable`.";
+ yield (0,_error_js__WEBPACK_IMPORTED_MODULE_0__.validationError)(
+ this.tokens.async,
+ this,
+ "obsolete-async-iterable-syntax",
+ message,
+ {
+ autofix: autofixAsyncIterableSyntax(this),
+ },
+ );
+ }
for (const type of this.idlType) {
yield* type.validate(defs);
}
@@ -3113,11 +3270,26 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.argsClose),
w.token(this.tokens.termination),
]),
- { data: this, parent: this.parent }
+ { data: this, parent: this.parent },
);
}
}
+/**
+ * @param {IterableLike} iterableLike
+ */
+function autofixAsyncIterableSyntax(iterableLike) {
+ return () => {
+ const async = iterableLike.tokens.async;
+ iterableLike.tokens.base = {
+ ...async,
+ type: "async_iterable",
+ value: "async_iterable",
+ };
+ delete iterableLike.tokens.async;
+ };
+}
+
/***/ }),
/* 23 */
@@ -3125,7 +3297,7 @@ class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "checkInterfaceMemberDuplication": () => (/* binding */ checkInterfaceMemberDuplication)
+/* harmony export */ checkInterfaceMemberDuplication: () => (/* binding */ checkInterfaceMemberDuplication)
/* harmony export */ });
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
@@ -3164,7 +3336,7 @@ function* checkInterfaceMemberDuplication(defs, i) {
addition.tokens.name,
ext,
"no-cross-overload",
- message
+ message,
);
}
}
@@ -3185,10 +3357,10 @@ function* checkInterfaceMemberDuplication(defs, i) {
const ops = getOperations(i);
return {
statics: new Set(
- ops.filter((op) => op.special === "static").map((op) => op.name)
+ ops.filter((op) => op.special === "static").map((op) => op.name),
),
nonstatics: new Set(
- ops.filter((op) => op.special !== "static").map((op) => op.name)
+ ops.filter((op) => op.special !== "static").map((op) => op.name),
),
};
}
@@ -3201,7 +3373,7 @@ function* checkInterfaceMemberDuplication(defs, i) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Constructor": () => (/* binding */ Constructor)
+/* harmony export */ Constructor: () => (/* binding */ Constructor)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -3255,7 +3427,7 @@ class Constructor extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
w.token(this.tokens.close),
w.token(this.tokens.termination),
]),
- { data: this, parent }
+ { data: this, parent },
);
}
}
@@ -3267,7 +3439,7 @@ class Constructor extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Mixin": () => (/* binding */ Mixin)
+/* harmony export */ Mixin: () => (/* binding */ Mixin)
/* harmony export */ });
/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20);
/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(21);
@@ -3282,14 +3454,13 @@ __webpack_require__.r(__webpack_exports__);
class Mixin extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
/**
- * @typedef {import("../tokeniser.js").Token} Token
- *
* @param {import("../tokeniser.js").Tokeniser} tokeniser
- * @param {Token} base
+ * @param {import("../tokeniser.js").Token} base
* @param {object} [options]
- * @param {Token} [options.partial]
+ * @param {import("./container.js").AllowedMember[]} [options.extMembers]
+ * @param {import("../tokeniser.js").Token} [options.partial]
*/
- static parse(tokeniser, base, { partial } = {}) {
+ static parse(tokeniser, base, { extMembers = [], partial } = {}) {
const tokens = { partial, base };
tokens.mixin = tokeniser.consume("mixin");
if (!tokens.mixin) {
@@ -3300,12 +3471,13 @@ class Mixin extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
new Mixin({ source: tokeniser.source, tokens }),
{
allowedMembers: [
+ ...extMembers,
[_constant_js__WEBPACK_IMPORTED_MODULE_1__.Constant.parse],
[_helpers_js__WEBPACK_IMPORTED_MODULE_4__.stringifier],
[_attribute_js__WEBPACK_IMPORTED_MODULE_2__.Attribute.parse, { noInherit: true }],
[_operation_js__WEBPACK_IMPORTED_MODULE_3__.Operation.parse, { regular: true }],
],
- }
+ },
);
}
@@ -3321,7 +3493,7 @@ class Mixin extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Dictionary": () => (/* binding */ Dictionary)
+/* harmony export */ Dictionary: () => (/* binding */ Dictionary)
/* harmony export */ });
/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20);
/* harmony import */ var _field_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27);
@@ -3332,9 +3504,10 @@ class Dictionary extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {object} [options]
+ * @param {import("./container.js").AllowedMember[]} [options.extMembers]
* @param {import("../tokeniser.js").Token} [options.partial]
*/
- static parse(tokeniser, { partial } = {}) {
+ static parse(tokeniser, { extMembers = [], partial } = {}) {
const tokens = { partial };
tokens.base = tokeniser.consume("dictionary");
if (!tokens.base) {
@@ -3345,8 +3518,8 @@ class Dictionary extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
new Dictionary({ source: tokeniser.source, tokens }),
{
inheritable: !partial,
- allowedMembers: [[_field_js__WEBPACK_IMPORTED_MODULE_1__.Field.parse]],
- }
+ allowedMembers: [...extMembers, [_field_js__WEBPACK_IMPORTED_MODULE_1__.Field.parse]],
+ },
);
}
@@ -3362,7 +3535,7 @@ class Dictionary extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Field": () => (/* binding */ Field)
+/* harmony export */ Field: () => (/* binding */ Field)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
@@ -3424,7 +3597,7 @@ class Field extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
this.default ? this.default.write(w) : "",
w.token(this.tokens.termination),
]),
- { data: this, parent }
+ { data: this, parent },
);
}
}
@@ -3436,7 +3609,7 @@ class Field extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Namespace": () => (/* binding */ Namespace)
+/* harmony export */ Namespace: () => (/* binding */ Namespace)
/* harmony export */ });
/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20);
/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14);
@@ -3455,9 +3628,10 @@ class Namespace extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {object} [options]
+ * @param {import("./container.js").AllowedMember[]} [options.extMembers]
* @param {import("../tokeniser.js").Token} [options.partial]
*/
- static parse(tokeniser, { partial } = {}) {
+ static parse(tokeniser, { extMembers = [], partial } = {}) {
const tokens = { partial };
tokens.base = tokeniser.consume("namespace");
if (!tokens.base) {
@@ -3468,11 +3642,12 @@ class Namespace extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
new Namespace({ source: tokeniser.source, tokens }),
{
allowedMembers: [
+ ...extMembers,
[_attribute_js__WEBPACK_IMPORTED_MODULE_1__.Attribute.parse, { noInherit: true, readonly: true }],
[_constant_js__WEBPACK_IMPORTED_MODULE_5__.Constant.parse],
[_operation_js__WEBPACK_IMPORTED_MODULE_2__.Operation.parse, { regular: true }],
],
- }
+ },
);
}
@@ -3497,7 +3672,7 @@ for more information.`;
message,
{
autofix: (0,_helpers_js__WEBPACK_IMPORTED_MODULE_4__.autofixAddExposedWindow)(this),
- }
+ },
);
}
yield* super.validate(defs);
@@ -3511,7 +3686,7 @@ for more information.`;
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "CallbackInterface": () => (/* binding */ CallbackInterface)
+/* harmony export */ CallbackInterface: () => (/* binding */ CallbackInterface)
/* harmony export */ });
/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20);
/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13);
@@ -3523,8 +3698,11 @@ __webpack_require__.r(__webpack_exports__);
class CallbackInterface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Container {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
+ * @param {*} callback
+ * @param {object} [options]
+ * @param {import("./container.js").AllowedMember[]} [options.extMembers]
*/
- static parse(tokeniser, callback, { partial = null } = {}) {
+ static parse(tokeniser, callback, { extMembers = [] } = {}) {
const tokens = { callback };
tokens.base = tokeniser.consume("interface");
if (!tokens.base) {
@@ -3534,12 +3712,12 @@ class CallbackInterface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Conta
tokeniser,
new CallbackInterface({ source: tokeniser.source, tokens }),
{
- inheritable: !partial,
allowedMembers: [
+ ...extMembers,
[_constant_js__WEBPACK_IMPORTED_MODULE_2__.Constant.parse],
[_operation_js__WEBPACK_IMPORTED_MODULE_1__.Operation.parse, { regular: true }],
],
- }
+ },
);
}
@@ -3555,8 +3733,8 @@ class CallbackInterface extends _container_js__WEBPACK_IMPORTED_MODULE_0__.Conta
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "Writer": () => (/* binding */ Writer),
-/* harmony export */ "write": () => (/* binding */ write)
+/* harmony export */ Writer: () => (/* binding */ Writer),
+/* harmony export */ write: () => (/* binding */ write)
/* harmony export */ });
function noop(arg) {
return arg;
@@ -3640,7 +3818,7 @@ function write(ast, { templates: ts = templates } = {}) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "validate": () => (/* binding */ validate)
+/* harmony export */ validate: () => (/* binding */ validate)
/* harmony export */ });
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
@@ -3797,14 +3975,14 @@ function validate(ast) {
/******/
/************************************************************************/
var __webpack_exports__ = {};
-// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
(() => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "WebIDLParseError": () => (/* reexport safe */ _lib_tokeniser_js__WEBPACK_IMPORTED_MODULE_3__.WebIDLParseError),
-/* harmony export */ "parse": () => (/* reexport safe */ _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__.parse),
-/* harmony export */ "validate": () => (/* reexport safe */ _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__.validate),
-/* harmony export */ "write": () => (/* reexport safe */ _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__.write)
+/* harmony export */ WebIDLParseError: () => (/* reexport safe */ _lib_tokeniser_js__WEBPACK_IMPORTED_MODULE_3__.WebIDLParseError),
+/* harmony export */ parse: () => (/* reexport safe */ _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__.parse),
+/* harmony export */ validate: () => (/* reexport safe */ _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__.validate),
+/* harmony export */ write: () => (/* reexport safe */ _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__.write)
/* harmony export */ });
/* harmony import */ var _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30);
diff --git a/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html b/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html
new file mode 100644
index 00000000000..fbab7cdedfa
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html
@@ -0,0 +1,27 @@
+
+
+Service Worker: addRoutes() executes in installing
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html
index 8a2a6ff25c8..a02f8e9ca6f 100644
--- a/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html
@@ -97,7 +97,7 @@
.then(function() {
frame.remove();
});
- }, 'Test for the waiting worker claims a client which is using the the ' +
+ }, 'Test for the waiting worker claims a client which is using the ' +
'same registration');
diff --git a/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html
new file mode 100644
index 00000000000..ba597d893d3
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html
@@ -0,0 +1,129 @@
+
+Service Worker: Client.url is Window creation URL tests
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/intercepted-referrer.https.html b/test/fixtures/wpt/service-workers/service-worker/intercepted-referrer.https.html
new file mode 100644
index 00000000000..72d78945139
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/intercepted-referrer.https.html
@@ -0,0 +1,51 @@
+
+
+Service Worker intercepted navigation preserves document.referrer
+
+
+
+
+
+Service Worker intercepted navigation preserves document.referrer
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/add-routes.js b/test/fixtures/wpt/service-workers/service-worker/resources/add-routes.js
new file mode 100644
index 00000000000..796acd19c12
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/resources/add-routes.js
@@ -0,0 +1,37 @@
+let globalAddRoutes;
+let addRoutesError = {};
+
+self.addEventListener('install', event => {
+ globalAddRoutes = event.addRoutes.bind(event);
+ globalAddRoutes([
+ {
+ condition: { urlPattern: '/', runningStatus: 'not-running' },
+ source: 'network',
+ },
+ ])
+ .then(() => {
+ addRoutesError.install = null;
+ })
+ .catch(error => {
+ addRoutesError.install = error;
+ });
+});
+
+self.addEventListener('activate', event => {
+ globalAddRoutes([
+ {
+ condition: { urlPattern: '/', runningStatus: 'not-running' },
+ source: 'network',
+ },
+ ])
+ .then(() => {
+ addRoutesError.activate = null;
+ })
+ .catch(error => {
+ addRoutesError.activate = error;
+ });
+});
+
+self.addEventListener('message', event => {
+ event.ports[0].postMessage(addRoutesError);
+});
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html
new file mode 100644
index 00000000000..db2b9e5bbd9
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html
@@ -0,0 +1,85 @@
+
+Service Worker: Client.url is Window creation URL iframe resource
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js
new file mode 100644
index 00000000000..013d9be4cae
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js
@@ -0,0 +1,24 @@
+// This is a service worker script used by the client-url-creation-url test.
+// It exists only to look up the client URL of the test iframe and send it back
+// to the test page.
+addEventListener('message', message_event => {
+ const port = message_event.data.port;
+
+ const async_work = async () => {
+ try {
+ const clients = await self.clients.matchAll();
+
+ // In our test there should be exactly one client that is our test
+ // navigation iframe.
+ if (clients.length == 1) {
+ const client = clients[0];
+ port.postMessage(client.url);
+ } else {
+ port.postMessage(`error: expected 1 client, not ${clients.length}`);
+ }
+ } catch (error) {
+ port.postMessage(`error: ${error.message}`);
+ }
+ };
+ message_event.waitUntil(async_work());
+});
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/intercepted-referrer-sw.js b/test/fixtures/wpt/service-workers/service-worker/resources/intercepted-referrer-sw.js
new file mode 100644
index 00000000000..f0246c8dbe4
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/resources/intercepted-referrer-sw.js
@@ -0,0 +1,35 @@
+self.addEventListener('install', event => {
+ // Activate immediately to simplify the test.
+ event.waitUntil(self.skipWaiting());
+});
+
+self.addEventListener('activate', event => {
+ // Make sure the very next navigation is controlled by this SW.
+ event.waitUntil(self.clients.claim());
+});
+
+self.addEventListener('fetch', event => {
+ // Only handle top-level navigations within our scope.
+ if (event.request.mode === 'navigate') {
+ const html = `
+
+ SW Intercepted Page
+
+ SW-synthesized page
+ This page was served by a Service Worker via respondWith().
`;
+
+ event.respondWith(new Response(html, {
+ headers: { 'Content-Type': 'text/html; charset=utf-8' }
+ }));
+ }
+ // Otherwise, fall through to network.
+});
diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/testharness-helpers.js b/test/fixtures/wpt/service-workers/service-worker/resources/testharness-helpers.js
index b1a5b960e06..5f93a25438a 100644
--- a/test/fixtures/wpt/service-workers/service-worker/resources/testharness-helpers.js
+++ b/test/fixtures/wpt/service-workers/service-worker/resources/testharness-helpers.js
@@ -14,7 +14,7 @@
// 2.1 |a.p| is weakly equal to |b.p| for all own properties |p| of |a|.
// 2.2 Every own property of |b| is an own property of |a|.
//
-// This is a replacement for the the version of assert_object_equals() in
+// This is a replacement for the version of assert_object_equals() in
// testharness.js. The latter doesn't handle own properties correctly. I.e. if
// |a.p| is not an own property, it still requires that |b.p| be an own
// property.
diff --git a/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html b/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html
index e32436da41b..f554bf7c2ec 100644
--- a/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html
+++ b/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html
@@ -56,10 +56,12 @@
assert_equals(entry.workerStart, 0, description);
assert_equals(entry.workerCacheLookupStart, 0, description);
assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description);
+ assert_greater_than(entry.encodedBodySize, 0, description);
break;
case 'cache':
assert_equals(entry.workerStart, 0, description);
assert_greater_than_equal(entry.workerCacheLookupStart, entry.workerRouterEvaluationStart, description);
+ assert_greater_than(entry.encodedBodySize, 0, description);
if (entry.workerFinalSourceType === 'cache') {
assert_equals(entry.fetchStart, entry.responseStart, description);
assert_less_than_equal(entry.workerCacheLookupStart, entry.responseStart, description);
@@ -68,8 +70,9 @@
assert_less_than_equal(entry.workerCacheLookupStart, entry.fetchStart, description);
}
break;
- case 'race-network-and-fetch':
+ case 'race-network-and-fetch-handler':
assert_equals(entry.workerCacheLookupStart, 0, description);
+ assert_greater_than(entry.encodedBodySize, 0, description);
if (entry.workerFinalSourceType === 'network') {
assert_equals(entry.workerStart, 0, description);
assert_less_than_equal(entry.workerRouterEvaluationStart, entry.fetchStart, description);
@@ -79,6 +82,8 @@
}
break;
case 'fetch-event':
+ assert_greater_than(entry.encodedBodySize, 0, description);
+ break;
case '': // i.e. no matching rules
assert_equals(entry.workerCacheLookupStart, 0, description);
assert_greater_than_equal(entry.workerStart, entry.workerRouterEvaluationStart, description);
@@ -261,7 +266,7 @@
test_resource_timing({
performance: iframe.contentWindow.performance,
url: url,
- matched_source_type: 'race-network-and-fetch',
+ matched_source_type: 'race-network-and-fetch-handler',
final_source_type: 'fetch-event',
description: "race as source on main resource, and fetch-event wins"
});
@@ -280,7 +285,7 @@
test_resource_timing({
performance: iframe.contentWindow.performance,
url: url,
- matched_source_type: 'race-network-and-fetch',
+ matched_source_type: 'race-network-and-fetch-handler',
final_source_type: 'network',
description: "race as source on main resource, and network wins"
});
@@ -301,7 +306,7 @@
test_resource_timing({
performance: iframe.contentWindow.performance,
url: `${RACE_ROUTE}${subresource}`,
- matched_source_type: 'race-network-and-fetch',
+ matched_source_type: 'race-network-and-fetch-handler',
final_source_type: 'fetch-event',
description: "race as source on subresource and fetch wins"
});
@@ -323,7 +328,7 @@
test_resource_timing({
performance: iframe.contentWindow.performance,
url: `${RACE_ROUTE}${subresource}`,
- matched_source_type: 'race-network-and-fetch',
+ matched_source_type: 'race-network-and-fetch-handler',
final_source_type: 'network',
description: "race as source on subresource and network wins"
});
diff --git a/test/fixtures/wpt/service-workers/service-worker/unregister-immediately-before-installed.https.html b/test/fixtures/wpt/service-workers/service-worker/unregister-immediately-before-installed.https.html
index 79cdaf062dc..c56674c0fb1 100644
--- a/test/fixtures/wpt/service-workers/service-worker/unregister-immediately-before-installed.https.html
+++ b/test/fixtures/wpt/service-workers/service-worker/unregister-immediately-before-installed.https.html
@@ -16,7 +16,7 @@
// worker's state to 'redundant'.
promise_test(async test => {
- // This test keeps the the service worker in the 'parsed' state by using a
+ // This test keeps the service worker in the 'parsed' state by using a
// script with an infinite loop.
const script_url = 'resources/onparse-infiniteloop-worker.js';
const scope_url =
@@ -34,7 +34,7 @@
}, 'Clear-Site-Data must abort service worker registration.');
promise_test(async test => {
- // This test keeps the the service worker in the 'installing' state by using a
+ // This test keeps the service worker in the 'installing' state by using a
// script with an install event waitUntil() promise that never resolves.
const script_url = 'resources/oninstall-waituntil-forever.js';
const scope_url =
diff --git a/test/fixtures/wpt/service-workers/service-worker/unregister-immediately.https.html b/test/fixtures/wpt/service-workers/service-worker/unregister-immediately.https.html
index 54be40a5452..c6a91f8e235 100644
--- a/test/fixtures/wpt/service-workers/service-worker/unregister-immediately.https.html
+++ b/test/fixtures/wpt/service-workers/service-worker/unregister-immediately.https.html
@@ -16,7 +16,7 @@
// active worker's controlled clients to unload.
promise_test(async test => {
- // This test keeps the the service worker in the 'activating' state by using a
+ // This test keeps the service worker in the 'activating' state by using a
// script with an activate event waitUntil() promise that never resolves.
const script_url = 'resources/onactivate-waituntil-forever.js';
const scope_url =
diff --git a/test/fixtures/wpt/service-workers/service-worker/windowclient-navigate.https.html b/test/fixtures/wpt/service-workers/service-worker/windowclient-navigate.https.html
index ad60f786363..8c1dcad5b65 100644
--- a/test/fixtures/wpt/service-workers/service-worker/windowclient-navigate.https.html
+++ b/test/fixtures/wpt/service-workers/service-worker/windowclient-navigate.https.html
@@ -48,7 +48,7 @@
});
navigateTest({
- description: 'cross orgin url',
+ description: 'cross origin url',
destUrl: CROSS_ORIGIN_URL,
expected: null
});
diff --git a/test/fixtures/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js b/test/fixtures/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
index ee9202777e7..9dc345579d3 100644
--- a/test/fixtures/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
+++ b/test/fixtures/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
@@ -17,6 +17,9 @@ promise_test(async t => {
await indexedDbOpenRequest(t, bucket.indexedDB, dbname, (db_to_upgrade) => {
db_to_upgrade.createObjectStore(objectStoreName);
});
+ t.add_cleanup(() => {
+ db.close();
+ });
const txn = db.transaction(objectStoreName, 'readwrite');
const buffer = new ArrayBuffer(arraySize);
@@ -34,8 +37,5 @@ promise_test(async t => {
type: 'binary/random'
}), 2);
- await promise_rejects_dom(
- t, 'QuotaExceededError', transactionPromise(txn));
-
- db.close();
+ await promise_rejects_quotaexceedederror(t, transactionPromise(txn), null, null);
}, 'IDB respects bucket quota');
diff --git a/test/fixtures/wpt/storage/estimate-usage-details-indexeddb.https.tentative.any.js b/test/fixtures/wpt/storage/estimate-usage-details-indexeddb.https.tentative.any.js
index 551cede9c6d..d89a78e0956 100644
--- a/test/fixtures/wpt/storage/estimate-usage-details-indexeddb.https.tentative.any.js
+++ b/test/fixtures/wpt/storage/estimate-usage-details-indexeddb.https.tentative.any.js
@@ -16,7 +16,6 @@ promise_test(async t => {
const objectStoreName = 'store';
const dbname = self.location.pathname;
- await indexedDB.deleteDatabase(dbname);
let usageAfterWrite, usageBeforeWrite;
// TODO(crbug.com/906867): Refactor this test to better deal with db/log
// compaction flakiness
@@ -32,6 +31,7 @@ promise_test(async t => {
// builds that fail); all it takes is one iteration without compaction for
// this to pass.
for (let i = 0; i < 10; i++) {
+ indexedDB.deleteDatabase(dbname);
const db = await createDB(dbname, objectStoreName, t);
let estimate = await navigator.storage.estimate();
diff --git a/test/fixtures/wpt/storage/partitioned-estimate-usage-details-caches.tentative.https.sub.html b/test/fixtures/wpt/storage/partitioned-estimate-usage-details-caches.tentative.https.sub.html
index dc2af7c213c..4954a996f22 100644
--- a/test/fixtures/wpt/storage/partitioned-estimate-usage-details-caches.tentative.https.sub.html
+++ b/test/fixtures/wpt/storage/partitioned-estimate-usage-details-caches.tentative.https.sub.html
@@ -7,9 +7,12 @@
diff --git a/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-indexeddb-helper-frame.html b/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-indexeddb-helper-frame.html
index fd2cfb669bd..10f5b956b8b 100644
--- a/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-indexeddb-helper-frame.html
+++ b/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-indexeddb-helper-frame.html
@@ -2,12 +2,22 @@
Helper frame
+
+
diff --git a/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-service-workers-helper-frame.html b/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-service-workers-helper-frame.html
index 25d7554868f..0bf7bebf2bb 100644
--- a/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-service-workers-helper-frame.html
+++ b/test/fixtures/wpt/storage/resources/partitioned-estimate-usage-details-service-workers-helper-frame.html
@@ -2,14 +2,24 @@
Helper frame
+
+
diff --git a/test/fixtures/wpt/websockets/Create-blocked-port.any.js b/test/fixtures/wpt/websockets/Create-blocked-port.any.js
index b8e3e26445e..55620d3128d 100644
--- a/test/fixtures/wpt/websockets/Create-blocked-port.any.js
+++ b/test/fixtures/wpt/websockets/Create-blocked-port.any.js
@@ -11,6 +11,7 @@ async_test(t => {
// list of bad ports according to
// https://fetch.spec.whatwg.org/#port-blocking
[
+ 0,
1, // tcpmux
7, // echo
9, // discard
@@ -49,6 +50,7 @@ async_test(t => {
137, // netbios-ns
139, // netbios-ssn
143, // imap2
+ 161, // snmp
179, // bgp
389, // ldap
427, // afp (alternate)
@@ -80,6 +82,8 @@ async_test(t => {
3659, // apple-sasl
4045, // lockd
4190, // sieve
+ 5060, // sip
+ 5061, // sips
6000, // x11
6566, // sane-port
6665, // irc (alternate)
diff --git a/test/fixtures/wpt/websockets/WEB_FEATURES.yml b/test/fixtures/wpt/websockets/WEB_FEATURES.yml
new file mode 100644
index 00000000000..6ca9ddf4301
--- /dev/null
+++ b/test/fixtures/wpt/websockets/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: websockets
+ files: "**"
diff --git a/test/fixtures/wpt/websockets/stream/tentative/remote-close.any.js b/test/fixtures/wpt/websockets/stream/tentative/remote-close.any.js
index b7fd321914a..c3e7ad5f9fb 100644
--- a/test/fixtures/wpt/websockets/stream/tentative/remote-close.any.js
+++ b/test/fixtures/wpt/websockets/stream/tentative/remote-close.any.js
@@ -48,7 +48,8 @@ promise_test(async t => {
const closedError = await wss.closed.then(t.unreached_func('closed should reject'), e => e);
assert_equals(closedError.constructor, WebSocketError, 'error should be WebSocketError');
assert_equals(closedError.closeCode, 4567, 'closeCode should be set');
- promise_rejects_js(t, WebSocketError, writePromise, 'write() should reject');
+ await promise_rejects_dom(
+ t, 'InvalidStateError', writePromise, 'write() should reject');
}, 'close with unwritten data should not be considered clean');
promise_test(async t => {
diff --git a/test/fixtures/wpt/websockets/stream/tentative/write.any.js b/test/fixtures/wpt/websockets/stream/tentative/write.any.js
new file mode 100644
index 00000000000..7f859e12579
--- /dev/null
+++ b/test/fixtures/wpt/websockets/stream/tentative/write.any.js
@@ -0,0 +1,111 @@
+// META: script=../../constants.sub.js
+// META: script=resources/url-constants.js
+// META: script=/common/gc.js
+// META: global=window,worker
+// META: variant=?default
+// META: variant=?wss
+// META: variant=?wpt_flags=h2
+
+'use strict';
+
+const GOODBYE_MESSAGE = 'Goodbye'; // Must match echo_exit_wsh.py
+
+// This message needs to be large enough that writing it cannot complete
+// synchronously, and to fill up the TCP send buffer and any user agent internal
+// send buffers so that the user agent has to receive the "Close" frame from the
+// server before it can complete sending this message.
+const BIG_MESSAGE_SIZE = 8 * 1024 * 1024;
+
+// Common setup used by two tests. Sends a "Goodbye" message to tell the server
+// to close the WebSocket, and immediately afterwards a big message that cannot
+// be completely sent before the connection closes. Waits for the "Goodbye"
+// message to be sent and the connection to be closed before returning. `t` is
+// the test object provided by promse_test.
+async function sendGoodbyeThenBigMessage(t) {
+ const wss = new WebSocketStream(BASEURL + '/echo_exit');
+ const { writable } = await wss.opened;
+ const writer = writable.getWriter();
+ const bigMessage = new Uint8Array(BIG_MESSAGE_SIZE);
+ const goodbyePromise = writer.write(GOODBYE_MESSAGE);
+ const bigMessagePromise = writer.write(bigMessage);
+ await goodbyePromise;
+ // testharness.js doesn't know about WebSocketError yet.
+ await wss.closed.then(
+ t.unreached_func('closed promise should reject'),
+ e => assert_equals(
+ e.constructor, WebSocketError,
+ 'a WebSocketError should be thrown'));
+ return { writer, bigMessagePromise };
+}
+
+promise_test(async t => {
+ const { writer, bigMessagePromise } = await sendGoodbyeThenBigMessage(t);
+ await promise_rejects_dom(
+ t, 'InvalidStateError', bigMessagePromise,
+ 'write() should reject with an InvalidStateError');
+ const invalidStateError = await bigMessagePromise.then(
+ t.unreached_func('write() promise should reject'), e => e);
+ await promise_rejects_exactly(
+ t, invalidStateError, writer.write('word'),
+ 'stream should be errored with same object');
+}, 'a write that was incomplete at close time should reject');
+
+promise_test(async t => {
+ const { bigMessagePromise } = await sendGoodbyeThenBigMessage(t);
+ // For some reason 5 is the magic number that causes garbage collection to
+ // really really collect garbage.
+ for (let i = 0; i < 5; ++i) {
+ await garbageCollect();
+ }
+ await promise_rejects_dom(
+ t, 'InvalidStateError', bigMessagePromise,
+ 'write() should reject with an InvalidStateError');
+}, 'garbage collection after close with a pending write promise should not ' +
+ 'crash');
+
+promise_test(async t => {
+ const wss = new WebSocketStream(ECHOURL);
+ const { writable } = await wss.opened;
+ const writer = writable.getWriter();
+ const cannotStringify = { toString() { return this; } };
+ await promise_rejects_js(
+ t, TypeError, writer.write(cannotStringify), 'write() should reject');
+}, 'writing a value that cannot be stringified should cause a rejection');
+
+promise_test(async t => {
+ const wss = new WebSocketStream(ECHOURL);
+ const { writable } = await wss.opened;
+ const writer = writable.getWriter();
+ const buffer = new ArrayBuffer(1024, { maxByteLength: 65536 });
+ await promise_rejects_js(
+ t, TypeError, writer.write(buffer), 'write() should reject');
+}, 'writing a resizable ArrayBuffer should be rejected');
+
+promise_test(async t => {
+ const wss = new WebSocketStream(ECHOURL);
+ const { writable } = await wss.opened;
+ const writer = writable.getWriter();
+ const memory = new WebAssembly.Memory({
+ initial: 4096,
+ maximum: 65536,
+ shared: true,
+ });
+ const view = new Uint8Array(memory.buffer);
+ await promise_rejects_js(
+ t, TypeError, writer.write(view), 'write() should reject');
+}, 'writing a view on a shared buffer should be rejected');
+
+promise_test(async () => {
+ let wss = new WebSocketStream(ECHOURL);
+ let { writable } = await wss.opened;
+ let writer = writable.getWriter();
+ wss = writable = null;
+ const promises = [];
+ for (let i = 0; i < 20; ++i) {
+ promises.push(writer.write(new Uint8Array(100000)));
+ }
+ writer = null;
+ for (let i = 0; i < 5; ++i) {
+ await garbageCollect();
+ }
+}, 'Garbage collecting a WebSocket stream doesn\'t crash while write promise is pending');
diff --git a/test/fixtures/wpt/xhr/WEB_FEATURES.yml b/test/fixtures/wpt/xhr/WEB_FEATURES.yml
new file mode 100644
index 00000000000..07f9d430181
--- /dev/null
+++ b/test/fixtures/wpt/xhr/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: xhr
+ files: "**"
diff --git a/test/fixtures/wpt/xhr/formdata/append.any.js b/test/fixtures/wpt/xhr/formdata/append.any.js
index fb365618d20..6871f69df59 100644
--- a/test/fixtures/wpt/xhr/formdata/append.any.js
+++ b/test/fixtures/wpt/xhr/formdata/append.any.js
@@ -19,13 +19,13 @@
assert_equals(create_formdata(['key', null], ['key', 'value1']).get('key'), "null");
}, 'testFormDataAppendNull2');
test(function() {
- var before = new Date(new Date().getTime() - 2000); // two seconds ago, in case there's clock drift
+ var before = new Date(new Date().getTime() - 2000).getTime(); // two seconds ago, in case there's clock drift
var fd = create_formdata(['key', new Blob(), 'blank.txt']).get('key');
assert_equals(fd.name, "blank.txt");
assert_equals(fd.type, "");
assert_equals(fd.size, 0);
assert_greater_than_equal(fd.lastModified, before);
- assert_less_than_equal(fd.lastModified, new Date());
+ assert_less_than_equal(fd.lastModified, new Date().getTime());
}, 'testFormDataAppendEmptyBlob');
function create_formdata() {
diff --git a/test/fixtures/wpt/xhr/resources/redirect.py b/test/fixtures/wpt/xhr/resources/redirect.py
index 3839b635e02..e2786b45031 100644
--- a/test/fixtures/wpt/xhr/resources/redirect.py
+++ b/test/fixtures/wpt/xhr/resources/redirect.py
@@ -1,10 +1,15 @@
import time
+from urllib.parse import parse_qs
from wptserve.utils import isomorphic_encode
def main(request, response):
code = int(request.GET.first(b"code", 302))
location = request.GET.first(b"location", isomorphic_encode(request.url_parts.path + u"?followed"))
+ if location:
+ location = parse_qs(u"location=" + location.decode(u"UTF-8"))[u"location"][0]
+ if location.startswith(u"redirect.py"):
+ location += u"&code=" + str(code)
if b"delay" in request.GET:
delay = float(request.GET.first(b"delay"))
diff --git a/test/fixtures/wpt/xhr/send-redirect.htm b/test/fixtures/wpt/xhr/send-redirect.htm
index 7d73f0f64cc..de3899f5e5d 100644
--- a/test/fixtures/wpt/xhr/send-redirect.htm
+++ b/test/fixtures/wpt/xhr/send-redirect.htm
@@ -10,36 +10,73 @@