diff options
379 files changed, 13966 insertions, 2158 deletions
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 36aca206776..91a7c5e8f8f 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -114105,6 +114105,18 @@ {} ] ], + "css/css-contain/contain-size-scrollbars-004.html": [ + [ + "css/css-contain/contain-size-scrollbars-004.html", + [ + [ + "/css/css-contain/reference/contain-size-scrollbars-004-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-contain/contain-size-select-001.html": [ [ "css/css-contain/contain-size-select-001.html", @@ -135439,6 +135451,30 @@ {} ] ], + "css/css-overflow/overflow-body-propagation-005.html": [ + [ + "css/css-overflow/overflow-body-propagation-005.html", + [ + [ + "/css/css-overflow/reference/overflow-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-overflow/overflow-body-propagation-006.html": [ + [ + "css/css-overflow/overflow-body-propagation-006.html", + [ + [ + "/css/css-overflow/reference/overflow-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-overflow/webkit-line-clamp-001.html": [ [ "css/css-overflow/webkit-line-clamp-001.html", @@ -143891,6 +143927,18 @@ {} ] ], + "css/css-tables/box-shadow-001.html": [ + [ + "css/css-tables/box-shadow-001.html", + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "css/css-tables/calc-percent-plus-0px-auto.html": [ [ "css/css-tables/calc-percent-plus-0px-auto.html", @@ -152391,6 +152439,18 @@ {} ] ], + "css/css-text/white-space/eol-spaces-bidi-001.html": [ + [ + "css/css-text/white-space/eol-spaces-bidi-001.html", + [ + [ + "/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text/white-space/line-edge-white-space-collapse-001.html": [ [ "css/css-text/white-space/line-edge-white-space-collapse-001.html", @@ -206217,6 +206277,18 @@ {} ] ], + "svg/text/reftests/dominant-baseline-hanging-small-font-size.svg": [ + [ + "svg/text/reftests/dominant-baseline-hanging-small-font-size.svg", + [ + [ + "/svg/embedded/reference/green-rect-100x100.svg", + "==" + ] + ], + {} + ] + ], "svg/text/reftests/text-clipped-offscreen-move-onscreen.html": [ [ "svg/text/reftests/text-clipped-offscreen-move-onscreen.html", @@ -214038,9 +214110,6 @@ "common/security-features/tools/util.py": [ [] ], - "common/sleep.py": [ - [] - ], "common/slow.py": [ [] ], @@ -244152,6 +244221,9 @@ "css/css-contain/reference/contain-size-scrollbars-001-ref.html": [ [] ], + "css/css-contain/reference/contain-size-scrollbars-004-ref.html": [ + [] + ], "css/css-contain/reference/contain-size-select-001-ref.html": [ [] ], @@ -255858,6 +255930,9 @@ "css/css-text/white-space/reference/control-chars-000-ref.html": [ [] ], + "css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html": [ + [] + ], "css/css-text/white-space/reference/line-edge-white-space-collapse-001-ref.html": [ [] ], @@ -266418,6 +266493,9 @@ "fetch/metadata/resources/xslt-test.sub.xml": [ [] ], + "fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.sub.headers": [ + [] + ], "fetch/nosniff/importscripts.js": [ [] ], @@ -267912,6 +267990,9 @@ "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/non-automated/discard_iframe_history_2-3.html": [ [] ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html": [ + [] + ], "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [ [] ], @@ -273867,43 +273948,79 @@ "images/yellow75.png": [ [] ], - "import-maps/@std/__dir__.headers": [ + "import-maps/README.md": [ + [] + ], + "import-maps/builtin-support.tentative/@std/__dir__.headers": [ [] ], - "import-maps/@std/blank": [ + "import-maps/builtin-support.tentative/@std/blank": [ [] ], - "import-maps/@std/none": [ + "import-maps/builtin-support.tentative/@std/none": [ [] ], - "import-maps/README.md": [ + "import-maps/builtin-support.tentative/bare/__dir__.headers": [ [] ], - "import-maps/bare/__dir__.headers": [ + "import-maps/builtin-support.tentative/bare/blank": [ [] ], - "import-maps/bare/bare": [ + "import-maps/builtin-support.tentative/bare/none": [ [] ], - "import-maps/bare/blank": [ + "import-maps/builtin-support.tentative/bare/std-blank": [ [] ], - "import-maps/bare/cross-origin-bare": [ + "import-maps/builtin-support.tentative/bare/std-none": [ [] ], - "import-maps/bare/none": [ + "import-maps/builtin-support.tentative/imported/resources/helpers/parsing.js": [ [] ], - "import-maps/bare/std-blank": [ + "import-maps/builtin-support.tentative/imported/resources/parsing-addresses.js": [ [] ], - "import-maps/bare/std-none": [ + "import-maps/builtin-support.tentative/imported/resources/parsing-schema.js": [ [] ], - "import-maps/bare/to-bare": [ + "import-maps/builtin-support.tentative/imported/resources/parsing-scope-keys.js": [ [] ], - "import-maps/bare/to-data": [ + "import-maps/builtin-support.tentative/imported/resources/parsing-specifier-keys.js": [ + [] + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-builtins.js": [ + [] + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-not-yet-implemented.js": [ + [] + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-scopes.js": [ + [] + ], + "import-maps/builtin-support.tentative/imported/resources/resolving.js": [ + [] + ], + "import-maps/builtin-support.tentative/static-import.js": [ + [] + ], + "import-maps/core/bare/__dir__.headers": [ + [] + ], + "import-maps/core/bare/bare": [ + [] + ], + "import-maps/core/bare/cross-origin-bare": [ + [] + ], + "import-maps/core/bare/to-bare": [ + [] + ], + "import-maps/core/bare/to-data": [ + [] + ], + "import-maps/core/static-import.js": [ [] ], "import-maps/imported/resources/helpers/parsing.js": [ @@ -273921,12 +274038,6 @@ "import-maps/imported/resources/parsing-specifier-keys.js": [ [] ], - "import-maps/imported/resources/resolving-builtins.js": [ - [] - ], - "import-maps/imported/resources/resolving-not-yet-implemented.js": [ - [] - ], "import-maps/imported/resources/resolving-scopes.js": [ [] ], @@ -273948,9 +274059,6 @@ "import-maps/resources/test-helper.js": [ [] ], - "import-maps/static-import.js": [ - [] - ], "inert/frame/button.html": [ [] ], @@ -273984,6 +274092,9 @@ "infrastructure/assumptions/tools/build.sh": [ [] ], + "infrastructure/metadata/infrastructure/assumptions/ahem.html.ini": [ + [] + ], "infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini": [ [] ], @@ -274065,6 +274176,9 @@ "infrastructure/metadata/infrastructure/testdriver/actions/elementPosition.html.ini": [ [] ], + "infrastructure/metadata/infrastructure/testdriver/actions/elementTiming.html.ini": [ + [] + ], "infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini": [ [] ], @@ -274074,6 +274188,9 @@ "infrastructure/metadata/infrastructure/testdriver/actions/pause.html.ini": [ [] ], + "infrastructure/metadata/infrastructure/testdriver/bless.html.ini": [ + [] + ], "infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini": [ [] ], @@ -274251,6 +274368,9 @@ "interfaces/css-regions.idl": [ [] ], + "interfaces/css-shadow-parts.idl": [ + [] + ], "interfaces/css-transitions.idl": [ [] ], @@ -276516,6 +276636,21 @@ "portals/csp/resources/frame-src.sub.html.sub.headers": [ [] ], + "portals/history/resources/inner-iframe.html": [ + [] + ], + "portals/history/resources/portal-harness.js": [ + [] + ], + "portals/history/resources/portal-manipulate-history-with-subframes.sub.html": [ + [] + ], + "portals/history/resources/portal-manipulate-history.html": [ + [] + ], + "portals/history/resources/run-test-in-portal.js": [ + [] + ], "portals/portals-referrer-inherit-header.html.headers": [ [] ], @@ -279021,6 +279156,9 @@ "resource-timing/resources/worker_with_images.js": [ [] ], + "resource-timing/sleep.py": [ + [] + ], "resource-timing/test_resource_timing.js": [ [] ], @@ -285882,6 +286020,9 @@ "tools/wpt/requirements.txt": [ [] ], + "tools/wpt/revlist.py": [ + [] + ], "tools/wpt/run.py": [ [] ], @@ -285894,6 +286035,9 @@ "tools/wpt/tests/test_browser.py": [ [] ], + "tools/wpt/tests/test_revlist.py": [ + [] + ], "tools/wpt/tests/test_run.py": [ [] ], @@ -287349,6 +287493,9 @@ "web-nfc/resources/nfc-helpers.js": [ [] ], + "web-nfc/resources/support-iframe.html": [ + [] + ], "web-share/META.yml": [ [] ], @@ -287907,12 +288054,18 @@ "webgpu/framework/url_query.js": [ [] ], + "webgpu/framework/util/async_mutex.js": [ + [] + ], "webgpu/framework/util/index.js": [ [] ], "webgpu/framework/util/stack.js": [ [] ], + "webgpu/framework/util/timeout.js": [ + [] + ], "webgpu/framework/version.js": [ [] ], @@ -287952,6 +288105,9 @@ "webgpu/suites/cts/command_buffer/render/rendering.spec.js": [ [] ], + "webgpu/suites/cts/command_buffer/render/storeop.spec.js": [ + [] + ], "webgpu/suites/cts/examples.spec.js": [ [] ], @@ -287964,6 +288120,63 @@ "webgpu/suites/cts/index.js": [ [] ], + "webgpu/suites/cts/validation/createBindGroup.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/createBindGroupLayout.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/createPipelineLayout.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/createRenderPipeline.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/createTexture.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/createView.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/error_scope.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/fences.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/queue_submit.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/render_pass.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/render_pass_descriptor.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setBindGroup.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setBlendColor.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setScissorRect.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setStencilReference.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setVertexBuffer.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/setViewport.spec.js": [ + [] + ], + "webgpu/suites/cts/validation/validation_test.js": [ + [] + ], + "webgpu/suites/cts/validation/vertex_input.spec.js": [ + [] + ], "webmessaging/META.yml": [ [] ], @@ -296276,6 +296489,144 @@ {} ] ], + "IndexedDB/blob-contenttype.any.js": [ + [ + "IndexedDB/blob-contenttype.any.html", + { + "script_metadata": [ + [ + "title", + "Blob Content Type" + ], + [ + "script", + "support.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "IndexedDB/blob-contenttype.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Blob Content Type" + ], + [ + "script", + "support.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "IndexedDB/blob-delete-objectstore-db.any.js": [ + [ + "IndexedDB/blob-delete-objectstore-db.any.html", + { + "script_metadata": [ + [ + "title", + "Blob Delete Object Store" + ], + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/blob-delete-objectstore-db.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Blob Delete Object Store" + ], + [ + "script", + "support.js" + ] + ] + } + ] + ], + "IndexedDB/blob-valid-after-deletion.any.js": [ + [ + "IndexedDB/blob-valid-after-deletion.any.html", + { + "script_metadata": [ + [ + "title", + "Blob Valid After Deletion" + ], + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/blob-valid-after-deletion.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Blob Valid After Deletion" + ], + [ + "script", + "support.js" + ] + ] + } + ] + ], + "IndexedDB/blob-valid-before-commit.any.js": [ + [ + "IndexedDB/blob-valid-before-commit.any.html", + { + "script_metadata": [ + [ + "title", + "Blob Valid Before Commit" + ], + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/blob-valid-before-commit.any.worker.html", + { + "script_metadata": [ + [ + "title", + "Blob Valid Before Commit" + ], + [ + "script", + "support.js" + ] + ] + } + ] + ], "IndexedDB/clone-before-keypath-eval.html": [ [ "IndexedDB/clone-before-keypath-eval.html", @@ -309329,6 +309680,262 @@ {} ] ], + "compression/compression-bad-chunks.any.js": [ + [ + "compression/compression-bad-chunks.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-bad-chunks.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ] + ], + "compression/compression-including-empty-chunk.any.js": [ + [ + "compression/compression-including-empty-chunk.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-including-empty-chunk.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "compression/compression-multiple-chunks.any.js": [ + [ + "compression/compression-multiple-chunks.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "compression/compression-multiple-chunks.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ], + [ + "script", + "pako/pako_inflate.min.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "compression/compression-output-length.any.js": [ + [ + "compression/compression-output-length.any.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.serviceworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.sharedworker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ], + [ + "compression/compression-output-length.any.worker.html", + { + "script_metadata": [ + [ + "global", + "worker" + ] + ] + } + ] + ], "compression/compression-stream.any.js": [ [ "compression/compression-stream.any.html", @@ -321025,6 +321632,12 @@ {} ] ], + "css/css-overflow/outline-with-opacity-crash.html": [ + [ + "css/css-overflow/outline-with-opacity-crash.html", + {} + ] + ], "css/css-overflow/overflow-abpos-transform.html": [ [ "css/css-overflow/overflow-abpos-transform.html", @@ -322597,6 +323210,12 @@ {} ] ], + "css/css-shadow-parts/idlharness.html": [ + [ + "css/css-shadow-parts/idlharness.html", + {} + ] + ], "css/css-shadow-parts/inner-host.html": [ [ "css/css-shadow-parts/inner-host.html", @@ -322681,6 +323300,30 @@ {} ] ], + "css/css-shadow-parts/simple-important-important.html": [ + [ + "css/css-shadow-parts/simple-important-important.html", + {} + ] + ], + "css/css-shadow-parts/simple-important-inline.html": [ + [ + "css/css-shadow-parts/simple-important-inline.html", + {} + ] + ], + "css/css-shadow-parts/simple-important.html": [ + [ + "css/css-shadow-parts/simple-important.html", + {} + ] + ], + "css/css-shadow-parts/simple-inline.html": [ + [ + "css/css-shadow-parts/simple-inline.html", + {} + ] + ], "css/css-shadow-parts/simple.html": [ [ "css/css-shadow-parts/simple.html", @@ -350274,6 +350917,254 @@ {} ] ], + "fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html", + { + "timeout": "long" + } + ] + ], + "fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html", + { + "testdriver": true + } + ] + ], + "fetch/metadata/sec-fetch-dest/frame.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/frame.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html", + { + "testdriver": true + } + ] + ], + "fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/navigation.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/navigation.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html", + { + "testdriver": true + } + ] + ], + "fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html", + { + "timeout": "long" + } + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/script.tentative.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/script.tentative.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html", + { + "testdriver": true + } + ] + ], + "fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html", + { + "testdriver": true + } + ] + ], + "fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html", + {} + ] + ], + "fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html": [ + [ + "fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html", + {} + ] + ], "fetch/metadata/serviceworker.tentative.https.sub.html": [ [ "fetch/metadata/serviceworker.tentative.https.sub.html", @@ -352772,6 +353663,12 @@ {} ] ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html": [ + [ + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html", + {} + ] + ], "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html": [ [ "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html", @@ -352791,6 +353688,12 @@ } ] ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html": [ + [ + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html", + {} + ] + ], "html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html": [ [ "html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html", @@ -359037,6 +359940,24 @@ {} ] ], + "html/semantics/forms/form-submission-0/form-double-submit-2.html": [ + [ + "html/semantics/forms/form-submission-0/form-double-submit-2.html", + {} + ] + ], + "html/semantics/forms/form-submission-0/form-double-submit-3.html": [ + [ + "html/semantics/forms/form-submission-0/form-double-submit-3.html", + {} + ] + ], + "html/semantics/forms/form-submission-0/form-double-submit.html": [ + [ + "html/semantics/forms/form-submission-0/form-double-submit.html", + {} + ] + ], "html/semantics/forms/form-submission-0/form-submission-algorithm.html": [ [ "html/semantics/forms/form-submission-0/form-submission-algorithm.html", @@ -364862,6 +365783,12 @@ {} ] ], + "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html": [ + [ + "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html", + {} + ] + ], "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js": [ [ "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.html", @@ -365870,155 +366797,213 @@ {} ] ], - "import-maps/bare.sub.tentative.html": [ + "import-maps/builtin-support.tentative/bare.sub.tentative.html": [ [ - "import-maps/bare.sub.tentative.html", + "import-maps/builtin-support.tentative/bare.sub.tentative.html", { "timeout": "long" } ] ], - "import-maps/builtin-empty.tentative.html": [ + "import-maps/builtin-support.tentative/builtin-empty.tentative.html": [ [ - "import-maps/builtin-empty.tentative.html", + "import-maps/builtin-support.tentative/builtin-empty.tentative.html", {} ] ], - "import-maps/builtin-import-scheme.tentative.html": [ + "import-maps/builtin-support.tentative/builtin-import-scheme.tentative.html": [ [ - "import-maps/builtin-import-scheme.tentative.html", + "import-maps/builtin-support.tentative/builtin-import-scheme.tentative.html", {} ] ], - "import-maps/builtin.tentative.html": [ + "import-maps/builtin-support.tentative/builtin.tentative.html": [ [ - "import-maps/builtin.tentative.html", + "import-maps/builtin-support.tentative/builtin.tentative.html", {} ] ], - "import-maps/csp/applied-to-target-dynamic.sub.tentative.html": [ + "import-maps/builtin-support.tentative/data.sub.tentative.html": [ [ - "import-maps/csp/applied-to-target-dynamic.sub.tentative.html", + "import-maps/builtin-support.tentative/data.sub.tentative.html", + { + "timeout": "long" + } + ] + ], + "import-maps/builtin-support.tentative/fallback-disallowed.sub.tentative.html": [ + [ + "import-maps/builtin-support.tentative/fallback-disallowed.sub.tentative.html", + { + "timeout": "long" + } + ] + ], + "import-maps/builtin-support.tentative/fallback.sub.tentative.html": [ + [ + "import-maps/builtin-support.tentative/fallback.sub.tentative.html", + { + "timeout": "long" + } + ] + ], + "import-maps/builtin-support.tentative/http.sub.tentative.html": [ + [ + "import-maps/builtin-support.tentative/http.sub.tentative.html", {} ] ], - "import-maps/csp/applied-to-target.sub.tentative.html": [ + "import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html": [ [ - "import-maps/csp/applied-to-target.sub.tentative.html", + "import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html", {} ] ], - "import-maps/csp/hash-failure.tentative.html": [ + "import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html": [ [ - "import-maps/csp/hash-failure.tentative.html", + "import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html", {} ] ], - "import-maps/csp/hash.tentative.html": [ + "import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html": [ [ - "import-maps/csp/hash.tentative.html", + "import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html", {} ] ], - "import-maps/csp/nonce-failure.tentative.html": [ + "import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html": [ [ - "import-maps/csp/nonce-failure.tentative.html", + "import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html", {} ] ], - "import-maps/csp/nonce.tentative.html": [ + "import-maps/builtin-support.tentative/imported/resolving-builtins.tentative.html": [ [ - "import-maps/csp/nonce.tentative.html", + "import-maps/builtin-support.tentative/imported/resolving-builtins.tentative.html", {} ] ], - "import-maps/csp/unsafe-inline.tentative.html": [ + "import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html": [ [ - "import-maps/csp/unsafe-inline.tentative.html", + "import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html", {} ] ], - "import-maps/data.sub.tentative.html": [ + "import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html": [ [ - "import-maps/data.sub.tentative.html", - { - "timeout": "long" - } + "import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html", + {} + ] + ], + "import-maps/builtin-support.tentative/imported/resolving.tentative.html": [ + [ + "import-maps/builtin-support.tentative/imported/resolving.tentative.html", + {} ] ], - "import-maps/fallback-disallowed.sub.tentative.html": [ + "import-maps/core/bare.sub.tentative.html": [ [ - "import-maps/fallback-disallowed.sub.tentative.html", + "import-maps/core/bare.sub.tentative.html", { "timeout": "long" } ] ], - "import-maps/fallback.sub.tentative.html": [ + "import-maps/core/data.sub.tentative.html": [ [ - "import-maps/fallback.sub.tentative.html", + "import-maps/core/data.sub.tentative.html", { "timeout": "long" } ] ], - "import-maps/http.sub.tentative.html": [ + "import-maps/core/http.sub.tentative.html": [ [ - "import-maps/http.sub.tentative.html", + "import-maps/core/http.sub.tentative.html", {} ] ], - "import-maps/imported/parsing-addresses.tentative.html": [ + "import-maps/core/module-map-key.tentative.html": [ [ - "import-maps/imported/parsing-addresses.tentative.html", + "import-maps/core/module-map-key.tentative.html", {} ] ], - "import-maps/imported/parsing-schema.tentative.html": [ + "import-maps/csp/applied-to-target-dynamic.sub.tentative.html": [ [ - "import-maps/imported/parsing-schema.tentative.html", + "import-maps/csp/applied-to-target-dynamic.sub.tentative.html", {} ] ], - "import-maps/imported/parsing-scope-keys.tentative.html": [ + "import-maps/csp/applied-to-target.sub.tentative.html": [ [ - "import-maps/imported/parsing-scope-keys.tentative.html", + "import-maps/csp/applied-to-target.sub.tentative.html", {} ] ], - "import-maps/imported/parsing-specifier-keys.tentative.html": [ + "import-maps/csp/hash-failure.tentative.html": [ [ - "import-maps/imported/parsing-specifier-keys.tentative.html", + "import-maps/csp/hash-failure.tentative.html", {} ] ], - "import-maps/imported/resolving-builtins.tentative.html": [ + "import-maps/csp/hash.tentative.html": [ [ - "import-maps/imported/resolving-builtins.tentative.html", + "import-maps/csp/hash.tentative.html", {} ] ], - "import-maps/imported/resolving-not-yet-implemented.tentative.html": [ + "import-maps/csp/nonce-failure.tentative.html": [ [ - "import-maps/imported/resolving-not-yet-implemented.tentative.html", + "import-maps/csp/nonce-failure.tentative.html", {} ] ], - "import-maps/imported/resolving-scopes.tentative.html": [ + "import-maps/csp/nonce.tentative.html": [ [ - "import-maps/imported/resolving-scopes.tentative.html", + "import-maps/csp/nonce.tentative.html", {} ] ], - "import-maps/imported/resolving.tentative.html": [ + "import-maps/csp/unsafe-inline.tentative.html": [ [ - "import-maps/imported/resolving.tentative.html", + "import-maps/csp/unsafe-inline.tentative.html", + {} + ] + ], + "import-maps/imported/parsing-addresses.tentative.html": [ + [ + "import-maps/imported/parsing-addresses.tentative.html", + {} + ] + ], + "import-maps/imported/parsing-schema.tentative.html": [ + [ + "import-maps/imported/parsing-schema.tentative.html", {} ] ], - "import-maps/module-map-key.tentative.html": [ + "import-maps/imported/parsing-scope-keys.tentative.html": [ + [ + "import-maps/imported/parsing-scope-keys.tentative.html", + {} + ] + ], + "import-maps/imported/parsing-specifier-keys.tentative.html": [ + [ + "import-maps/imported/parsing-specifier-keys.tentative.html", + {} + ] + ], + "import-maps/imported/resolving-scopes.tentative.html": [ [ - "import-maps/module-map-key.tentative.html", + "import-maps/imported/resolving-scopes.tentative.html", + {} + ] + ], + "import-maps/imported/resolving.tentative.html": [ + [ + "import-maps/imported/resolving.tentative.html", {} ] ], @@ -366587,6 +367572,12 @@ {} ] ], + "intersection-observer/document-scrolling-element-root.html": [ + [ + "intersection-observer/document-scrolling-element-root.html", + {} + ] + ], "intersection-observer/edge-inclusive-intersection.html": [ [ "intersection-observer/edge-inclusive-intersection.html", @@ -367194,6 +368185,12 @@ {} ] ], + "largest-contentful-paint/first-paint-equals-lcp-text.html": [ + [ + "largest-contentful-paint/first-paint-equals-lcp-text.html", + {} + ] + ], "largest-contentful-paint/idlharness.html": [ [ "largest-contentful-paint/idlharness.html", @@ -384519,6 +385516,18 @@ {} ] ], + "portals/history/history-manipulation-inside-portal-with-subframes.html": [ + [ + "portals/history/history-manipulation-inside-portal-with-subframes.html", + {} + ] + ], + "portals/history/history-manipulation-inside-portal.html": [ + [ + "portals/history/history-manipulation-inside-portal.html", + {} + ] + ], "portals/htmlportalelement-event-handler-content-attributes.html": [ [ "portals/htmlportalelement-event-handler-content-attributes.html", @@ -402783,6 +403792,38 @@ } ] ], + "shadow-dom/focus/click-focus-delegatesFocus-click-method.html": [ + [ + "shadow-dom/focus/click-focus-delegatesFocus-click-method.html", + { + "testdriver": true + } + ] + ], + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html": [ + [ + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html", + { + "testdriver": true + } + ] + ], + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html": [ + [ + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html", + { + "testdriver": true + } + ] + ], + "shadow-dom/focus/focus-method-delegatesFocus.html": [ + [ + "shadow-dom/focus/focus-method-delegatesFocus.html", + { + "testdriver": true + } + ] + ], "shadow-dom/focus/focus-selector-delegatesFocus.html": [ [ "shadow-dom/focus/focus-selector-delegatesFocus.html", @@ -402791,6 +403832,14 @@ } ] ], + "shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html": [ + [ + "shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html", + { + "testdriver": true + } + ] + ], "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [ [ "shadow-dom/focus/focus-tabindex-order-shadow-negative.html", @@ -402807,6 +403856,14 @@ } ] ], + "shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html": [ + [ + "shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html", + { + "testdriver": true + } + ] + ], "shadow-dom/focus/focus-tabindex-order-shadow-varying-tabindex.html": [ [ "shadow-dom/focus/focus-tabindex-order-shadow-varying-tabindex.html", @@ -402815,6 +403872,14 @@ } ] ], + "shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html": [ + [ + "shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html", + { + "testdriver": true + } + ] + ], "shadow-dom/focus/focus-tabindex-order-shadow-zero-host-negative.html": [ [ "shadow-dom/focus/focus-tabindex-order-shadow-zero-host-negative.html", @@ -404017,9 +405082,9 @@ } ] ], - "storage-access-api/idl.window.js": [ + "storage-access-api/idlharness.window.js": [ [ - "storage-access-api/idl.window.html", + "storage-access-api/idlharness.window.html", { "script_metadata": [ [ @@ -411775,24 +412840,6 @@ {} ] ], - "trusted-types/Location-assign.tentative.html": [ - [ - "trusted-types/Location-assign.tentative.html", - {} - ] - ], - "trusted-types/Location-href.tentative.html": [ - [ - "trusted-types/Location-href.tentative.html", - {} - ] - ], - "trusted-types/Location-replace.tentative.html": [ - [ - "trusted-types/Location-replace.tentative.html", - {} - ] - ], "trusted-types/Node-multiple-arguments.tentative.html": [ [ "trusted-types/Node-multiple-arguments.tentative.html", @@ -411903,12 +412950,6 @@ {} ] ], - "trusted-types/Window-open.tentative.html": [ - [ - "trusted-types/Window-open.tentative.html", - {} - ] - ], "trusted-types/WorkerGlobalScope-importScripts.https.html": [ [ "trusted-types/WorkerGlobalScope-importScripts.https.html", @@ -411975,36 +413016,12 @@ {} ] ], - "trusted-types/block-string-assignment-to-Location-assign.tentative.html": [ - [ - "trusted-types/block-string-assignment-to-Location-assign.tentative.html", - {} - ] - ], - "trusted-types/block-string-assignment-to-Location-href.tentative.html": [ - [ - "trusted-types/block-string-assignment-to-Location-href.tentative.html", - {} - ] - ], - "trusted-types/block-string-assignment-to-Location-replace.tentative.html": [ - [ - "trusted-types/block-string-assignment-to-Location-replace.tentative.html", - {} - ] - ], "trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html": [ [ "trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html", {} ] ], - "trusted-types/block-string-assignment-to-Window-open.tentative.html": [ - [ - "trusted-types/block-string-assignment-to-Window-open.tentative.html", - {} - ] - ], "trusted-types/block-text-node-insertion-into-script-element.tentative.html": [ [ "trusted-types/block-text-node-insertion-into-script-element.tentative.html", @@ -417032,6 +418049,12 @@ } ] ], + "wake-lock/wakelockpermissiondescriptor.https.html": [ + [ + "wake-lock/wakelockpermissiondescriptor.https.html", + {} + ] + ], "wasm/create_multiple_memory.worker.js": [ [ "wasm/create_multiple_memory.worker.html", @@ -420715,6 +421738,12 @@ {} ] ], + "web-nfc/NFCReader_scan_iframe.https.html": [ + [ + "web-nfc/NFCReader_scan_iframe.https.html", + {} + ] + ], "web-nfc/NFCReadingEvent_constructor.https.html": [ [ "web-nfc/NFCReadingEvent_constructor.https.html", @@ -422287,12 +423316,88 @@ {} ], [ + "webgpu/cts.html?q=cts:command_buffer/render/storeop:", + {} + ], + [ "webgpu/cts.html?q=cts:examples:", {} ], [ "webgpu/cts.html?q=cts:fences:", {} + ], + [ + "webgpu/cts.html?q=cts:validation/createBindGroup:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/createBindGroupLayout:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/createPipelineLayout:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/createRenderPipeline:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/createTexture:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/createView:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/error_scope:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/fences:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/queue_submit:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/render_pass:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/render_pass_descriptor:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setBindGroup:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setBlendColor:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setScissorRect:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setStencilReference:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setVertexBuffer:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/setViewport:", + {} + ], + [ + "webgpu/cts.html?q=cts:validation/vertex_input:", + {} ] ], "webmessaging/Channel_postMessage_Blob.htm": [ @@ -428794,9 +429899,15 @@ {} ] ], - "webxr/events_referenceSpace_reset.https.html": [ + "webxr/events_referenceSpace_reset_immersive.https.html": [ [ - "webxr/events_referenceSpace_reset.https.html", + "webxr/events_referenceSpace_reset_immersive.https.html", + {} + ] + ], + "webxr/events_referenceSpace_reset_inline.https.html": [ + [ + "webxr/events_referenceSpace_reset_inline.https.html", {} ] ], @@ -454847,7 +455958,7 @@ }, "paths": { ".azure-pipelines.yml": [ - "78f36842789b02036a0e4d86107c65c29190737e", + "ff466be667702bc2178cb1f7cf48cb2b1cf4230c", "support" ], ".codecov.yml": [ @@ -454883,7 +455994,7 @@ "support" ], ".taskcluster.yml": [ - "a267540cafba797ceb01a562936ed95d668a139f", + "27479fb57e072114e7898494468740b239c7ae92", "support" ], ".well-known/README.md": [ @@ -459682,6 +460793,22 @@ "c16c0a4e010f9805796cd93f9cbd1f141e6c91e5", "testharness" ], + "IndexedDB/blob-contenttype.any.js": [ + "0b2debae7b1a6498523459ee97882257a7ac974c", + "testharness" + ], + "IndexedDB/blob-delete-objectstore-db.any.js": [ + "61d7bad914e96a9063c97e3a14844aa8c30079e4", + "testharness" + ], + "IndexedDB/blob-valid-after-deletion.any.js": [ + "7c7825cb421e2f1e2aacb9838db594ff16e8f30a", + "testharness" + ], + "IndexedDB/blob-valid-before-commit.any.js": [ + "0803c9ea69c1e187bab2e6f0afe76a403973b645", + "testharness" + ], "IndexedDB/clone-before-keypath-eval.html": [ "bf67c5d6d732f6dfcf7687d9b12f3d313eb61707", "testharness" @@ -459743,7 +460870,7 @@ "testharness" ], "IndexedDB/idb-explicit-commit.any.js": [ - "12e56cc267a2a8ecb869b8b121f6e74047d0f73d", + "2acd904ea6ab5f887cfda7e7dece0ed506c27ae4", "testharness" ], "IndexedDB/idb_binary_key_conversion.htm": [ @@ -461059,7 +462186,7 @@ "testharness" ], "IndexedDB/structured-clone.any.js": [ - "8078aaf796b843aaf9f23be5889febbe4c8fb960", + "e03ba7aeee47bcd8ae75e2210fc2165581c0a82f", "testharness" ], "IndexedDB/support-promises.js": [ @@ -466742,10 +467869,6 @@ "269f464a547c7d1d23ba88527a55b9767e814304", "support" ], - "common/sleep.py": [ - "2e803b1b262423e219be592fab548ada982bc439", - "support" - ], "common/slow.py": [ "f3b1c7e2ea61b571bd56cc1c70c5f89bb8e7e4dc", "support" @@ -466918,6 +468041,22 @@ "1d3965fca6769c70bc02308a4c70b4e58c8990e5", "reftest" ], + "compression/compression-bad-chunks.any.js": [ + "06e3be9c0fe6d5663acf07cff12c4b9903c24661", + "testharness" + ], + "compression/compression-including-empty-chunk.any.js": [ + "eff928857903890e967fdbcab042a44a0731e946", + "testharness" + ], + "compression/compression-multiple-chunks.any.js": [ + "ca49b9cf42766a072b57cc8eb3f083127d90f8c4", + "testharness" + ], + "compression/compression-output-length.any.js": [ + "d7dafcd10092d5fd1135cbb4ca2d82d5844f6d08", + "testharness" + ], "compression/compression-stream.any.js": [ "47df70f7cd3979c1a3eab45581376fd38a6b2367", "testharness" @@ -556994,6 +558133,10 @@ "4684440bdbfd9886fd34a6ba1144ae1724b6a157", "reftest" ], + "css/css-contain/contain-size-scrollbars-004.html": [ + "6a45fdd23f4b797565e3cfa1934308f62709a0ca", + "reftest" + ], "css/css-contain/contain-size-select-001.html": [ "071db67831fd7951b8568ca1b7e4dcc5dbc119a1", "reftest" @@ -557298,6 +558441,10 @@ "402ff6c95e14c7c6dbe6e91cd779937bf6c4caa8", "support" ], + "css/css-contain/reference/contain-size-scrollbars-004-ref.html": [ + "91d9e51709465a24fbf418f197d2c01fd4cf2789", + "support" + ], "css/css-contain/reference/contain-size-select-001-ref.html": [ "960abc1e158756fca26ed3e42afcc9d97a0d07b1", "support" @@ -575827,11 +576974,11 @@ "visual" ], "css/css-lists/content-property/marker-text-matches-armenian-ref.html": [ - "f21dfff69608a6a1201bd586c2a6e1e24d5fd915", + "de55b7381ac1e2cf1553adcaee916e24e7348c4c", "support" ], "css/css-lists/content-property/marker-text-matches-armenian.html": [ - "fd0df631149a740a201510f2edff405d28f41929", + "58f570cd1197579aba1b646a1c970ab13c23c3e3", "reftest" ], "css/css-lists/content-property/marker-text-matches-circle-ref.html": [ @@ -577751,7 +578898,7 @@ "reftest" ], "css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html": [ - "6e40afe54c9ce9aa50765f778d74640454dcc1ce", + "1f74697489df2d8ed687b40d3681d9918f2ecb0f", "testharness" ], "css/css-multicol/filter-with-abspos.html": [ @@ -577771,7 +578918,7 @@ "reftest" ], "css/css-multicol/going-out-of-flow-after-spanner.html": [ - "2433864333967f26a2354b791cd7b153d26e44f4", + "2fe0e42a7522647b7eca4db1e6f710a9975faaa4", "testharness" ], "css/css-multicol/inheritance.html": [ @@ -579730,6 +580877,10 @@ "534dff9766ddccf4dd239a307d28d7e8882d6f04", "testharness" ], + "css/css-overflow/outline-with-opacity-crash.html": [ + "556e3cfedcd31d696827211d5626f756fb25dd93", + "testharness" + ], "css/css-overflow/overflow-abpos-transform.html": [ "df1128316f6010f010e6d27c395d7751fa05d7b1", "testharness" @@ -579750,6 +580901,14 @@ "2ed8d2687a33608e0e70884ad2ea59330d2b09e3", "reftest" ], + "css/css-overflow/overflow-body-propagation-005.html": [ + "e4de5769584611f61ec2fecd99c2324916a3d6ec", + "reftest" + ], + "css/css-overflow/overflow-body-propagation-006.html": [ + "475815068357ee24cfe9f22f968b0289ca982383", + "reftest" + ], "css/css-overflow/overflow-codependent-scrollbars.html": [ "eb0e4f5ea2ed9a97c0931c2c53de5e62e72ba1dd", "testharness" @@ -581927,7 +583086,7 @@ "reftest" ], "css/css-pseudo/first-line-first-letter-insert-crash.html": [ - "17f035dedf1ef8df71918a1eacb01e1f0b80d46b", + "bc22aae409b80ee62f3079cb31e89b2130da8270", "testharness" ], "css/css-pseudo/first-line-on-ancestor-block-ref.html": [ @@ -581947,7 +583106,7 @@ "reftest" ], "css/css-pseudo/idlharness.html": [ - "4c113fc9091fb773cabd77f1419fac9a2e99650b", + "eb0652e9eeb374ed1d3bb4bf235b0b3cf13fde06", "testharness" ], "css/css-pseudo/marker-and-other-pseudo-elements-ref.html": [ @@ -585222,6 +586381,10 @@ "2e65c4b1b57bd9959c68e85e11b442c67f2c5a42", "testharness" ], + "css/css-shadow-parts/idlharness.html": [ + "182943ac69de04b409e91b4005fb378cac36f9e2", + "testharness" + ], "css/css-shadow-parts/inner-host.html": [ "2dfd4b0510a758c73bf8ac8291088d39077578d7", "testharness" @@ -585286,6 +586449,22 @@ "a1a19aee4ede175f7e862318105f4625144b6e42", "testharness" ], + "css/css-shadow-parts/simple-important-important.html": [ + "43ec1bbae346e03e2e28209409f24a91273c5bdd", + "testharness" + ], + "css/css-shadow-parts/simple-important-inline.html": [ + "61b83dd4be7f4ff19236e5b6568424191382de80", + "testharness" + ], + "css/css-shadow-parts/simple-important.html": [ + "e3240bd3905f86cfa37dbc72af14dc95eb40d84e", + "testharness" + ], + "css/css-shadow-parts/simple-inline.html": [ + "f2c3638d1e9cc66dcc8051a00f778bc95cb33129", + "testharness" + ], "css/css-shadow-parts/simple.html": [ "a7f17d9670b137995b0dfc6f43221e16b988376d", "testharness" @@ -586175,7 +587354,7 @@ "testharness" ], "css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html": [ - "f79b21a723e6e253df0176e53a4567d8ec9567ab", + "def2d75fd93e472d2a40e4fd3f3418c6b96bafd5", "testharness" ], "css/css-shapes/shape-outside/values/shape-outside-computed-shape-001.html": [ @@ -587566,6 +588745,10 @@ "188257af443a235e8ad5d5804058cbf0bcc07a94", "testharness" ], + "css/css-tables/box-shadow-001.html": [ + "cc699d999eaf9dd7a50c0111ef319816c5c2cb12", + "reftest" + ], "css/css-tables/calc-percent-plus-0px-auto.html": [ "ec6e9ccfdd702963a8c1b35c8c6c64576189de77", "reftest" @@ -594523,11 +595706,11 @@ "reftest" ], "css/css-text/white-space/break-spaces-tab-005.html": [ - "b5cf3f33ec2bb582bb3f322eeed7c45b426f0936", + "81c39aa27fe818a293229a3e819d2394c8824a43", "reftest" ], "css/css-text/white-space/break-spaces-tab-006.html": [ - "85d821a3e4d476e6fdfe74a7a2f9134ffb2629a3", + "34df3bfc1bd2f20abbe29b79124a95ce28a4cfaf", "reftest" ], "css/css-text/white-space/control-chars-000.html": [ @@ -594782,6 +595965,10 @@ "44f6f83f2d110ac24d99de9eccaa6321903d931f", "reftest" ], + "css/css-text/white-space/eol-spaces-bidi-001.html": [ + "976ce7c639f10d2137da1492f50ea74c769c1091", + "reftest" + ], "css/css-text/white-space/line-edge-white-space-collapse-001.html": [ "4e144e6c330191435f183936c2ab2437ec4f7609", "reftest" @@ -594955,11 +596142,11 @@ "reftest" ], "css/css-text/white-space/pre-wrap-tab-005.html": [ - "993aa92e370b708855aa883591e13251f9015364", + "edbc5974c15cd840a278c49f0438d41932a68b8a", "reftest" ], "css/css-text/white-space/pre-wrap-tab-006.html": [ - "a4c7f3d3ebd9ae73a494769b18f046185672030c", + "4bdb7a21c7c59888f7f20eefe704a14d47b8d9e3", "reftest" ], "css/css-text/white-space/reference/break-spaces-tab-003-ref.html": [ @@ -594974,6 +596161,10 @@ "9d5fcb27147a8c53e410d08511cb5035b612f80c", "support" ], + "css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html": [ + "37da6649f9b776cb046a2bacdeb24968d27a2af8", + "support" + ], "css/css-text/white-space/reference/line-edge-white-space-collapse-001-ref.html": [ "02fa594255f00396f66e86837409cd579282f7de", "support" @@ -609779,7 +610970,7 @@ "reftest" ], "css/css-writing-modes/percentage-padding-in-shrink-to-fit.html": [ - "2d4364c886c48c3ef7ebddfb43d2210bdf75e094", + "240a66c9c6b81ba57addbebd456b5c497dcd4d51", "reftest" ], "css/css-writing-modes/reference/available-size-001-ref.html": [ @@ -612931,7 +614122,7 @@ "support" ], "css/css-writing-modes/wm-propagation-001.html": [ - "d313cacf38dac06ec5be6377a7cc9055dc4e2d07", + "f552265d0d0b32593f18df806929d86a368ee81b", "reftest" ], "css/css-writing-modes/wm-propagation-002-ref.html": [ @@ -613003,11 +614194,11 @@ "reftest" ], "css/css-writing-modes/wm-propagation-body-044-ref.html": [ - "31e98673720e06e2ed5519c38bf0ad28ec7b944c", + "9cf46c0b214652ca0bd7f28fe88c7943f6ccef8c", "support" ], "css/css-writing-modes/wm-propagation-body-044.html": [ - "60d444ca8b2f1de90be794a51ef5e3ae77005c7d", + "5993cee35934c63490b4ebbdc833a04f2f13256b", "reftest" ], "css/css-writing-modes/wm-propagation-body-045.html": [ @@ -613383,7 +614574,7 @@ "testharness" ], "css/cssom-view/elementFromPoint-list-001.html": [ - "e3c2c4d18f4c35f31908fd1095b0516fd0161b8a", + "b31453d6c32c2c7ed8192dc1e4b5037476645bcd", "testharness" ], "css/cssom-view/elementFromPoint-mixed-font-sizes.html": [ @@ -616011,7 +617202,7 @@ "reftest" ], "css/mediaqueries/mq-calc-006.html": [ - "989ee424867bb49f484324b7a3e90ed608a1342a", + "8f3ac37b057d0c9e53851e76d7144c602c02bb08", "reftest" ], "css/mediaqueries/mq-case-insensitive-001.html": [ @@ -616079,7 +617270,7 @@ "support" ], "css/mediaqueries/test_media_queries.html": [ - "d368acf8b57da4b98825cb4ddc25ae4c44338745", + "881df835f5a95e45487193881d5da89c81602ba9", "testharness" ], "css/mediaqueries/viewport-script-dynamic-ref.html": [ @@ -618691,7 +619882,7 @@ "support" ], "css/tools/build.py": [ - "d60e00fd330756f4212b9eda89d15a478fb0c861", + "9bbc2a5e7532c08eb2a70afe5569252d61142794", "support" ], "css/tools/w3ctestlib/.hgignore": [ @@ -628515,7 +629706,7 @@ "support" ], "docs/admin/index.md": [ - "8a04e2a0c805e9fc1fd3cf7c2fe4ecd053a45f32", + "7eca6e3a9a92cbbfb8b23d3c1ee88e43d1af69ad", "support" ], "docs/assets/_reftest_graph_example.dot": [ @@ -630847,7 +632038,7 @@ "support" ], "editing/data/inserthtml.js": [ - "0c6cff86c60401b404300ad7e92d697a2e7454c0", + "a3a23cd99e1b7140a9215554d2d17dc6cf34f51c", "support" ], "editing/data/insertimage.js": [ @@ -633507,7 +634698,7 @@ "testharness" ], "event-timing/crossiframe.html": [ - "bb19c82a2a1d64e5edcdc965812488aab1a73652", + "95e16afa0793e33d0839a6bad4a39a57a83ffec1", "testharness" ], "event-timing/idlharness.any.js": [ @@ -635719,7 +636910,7 @@ "support" ], "fetch/corb/resources/html-js-polyglot.js": [ - "5b048d336443c809831bdc08d1d8b0a6e2aecddb", + "db45bb4acc9251959a240da6c5c57603fb8fbce8", "support" ], "fetch/corb/resources/html-js-polyglot.js.headers": [ @@ -635727,7 +636918,7 @@ "support" ], "fetch/corb/resources/html-js-polyglot2.js": [ - "9443f8ed6c35efe7928249735b2faa0ef9bdf0a6", + "faae1b7682b547e93d492ba2c6085a956243f61c", "support" ], "fetch/corb/resources/html-js-polyglot2.js.headers": [ @@ -635787,7 +636978,7 @@ "testharness" ], "fetch/corb/script-html-js-polyglot.sub.html": [ - "ec4103771fb243864bbd8855b5c949922f1f3939", + "9a272d63ffc30e9ac365e6ce5e2179c1c694a955", "testharness" ], "fetch/corb/script-html-via-cross-origin-blob-url.sub.html": [ @@ -635803,11 +636994,11 @@ "testharness" ], "fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html": [ - "cabc7b09c458ca1f3852c633c9cd47680ab6e89d", + "d46944727f8ee9fc144caec437a5505be75e3d4b", "testharness" ], "fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html": [ - "4cbdd7b99e6b4bae045951733d61a794c476571c", + "f83eff82b5e4b21adfaf20915632e3ed6e6b9ba6", "testharness" ], "fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html": [ @@ -635983,107 +637174,107 @@ "support" ], "fetch/metadata/appcache.tentative.https.sub.html": [ - "1b5a5767c2c60e969f9e24204ff17017d599c9dc", + "3aa902cc1462c08cedc4f8efbd0ae2d86c6961bd", "testharness" ], "fetch/metadata/embed.tentative.https.sub.html": [ - "bf895e9d5385e9c6e1411f3360fd8480b2a6aa84", + "77042e85de9f26655fc31085074e2401a8202efc", "testharness" ], "fetch/metadata/fetch-preflight.tentative.https.sub.html": [ - "27dafc25df78b74bb5ae2f86b414b49058c372de", + "1ab3de615c8a620c01378577acd8e032998fb980", "testharness" ], "fetch/metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html": [ - "86edfd06decf56e1ee81030054a582b570bdbecf", + "13016fe35374949ddc27c42b1b57a74190675c7e", "testharness" ], "fetch/metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html": [ - "d59348c257b1c01b3b7c58015da2457294948b29", + "d43715785b4a6c323bae1f96a064b97914c0db3f", "testharness" ], "fetch/metadata/fetch.tentative.https.sub.html": [ - "30042f8aeb86605bbc1d35d623554cec17b32f87", + "72fb52ecd5d8123d5e387fdb20c171a320e38caf", "testharness" ], "fetch/metadata/fetch.tentative.sub.html": [ - "a2d66d6afa932011f8f64b0a85e79fd91486eef9", + "a14c2c5f411c803b28d7a12f314eba466c838437", "testharness" ], "fetch/metadata/font.tentative.https.sub.html": [ - "07152e8f18ca0234710a64e98b6641b32070e36f", + "9064dd6897393b184634a1abcef2f92fed7f9a71", "testharness" ], "fetch/metadata/history.tentative.https.sub.html": [ - "ef8e74bc86daf994ff8249230b6ddaf7162bb749", + "0d78ec06035fa11e6cd9b6f50381079b2001a564", "testharness" ], "fetch/metadata/iframe.tentative.https.sub.html": [ - "7b89d8dc0daa6d50b76eeec7f7a7f7349e23a0cd", + "b8f11c66b7edeedeab85b947e0a0138e5dd0f333", "testharness" ], "fetch/metadata/iframe.tentative.sub.html": [ - "418e2a2d449ee48d2ab8147ed6923706a1eb9cba", + "c5469f458d37bed0ce43ddbf1011085879e9f743", "testharness" ], "fetch/metadata/img.tentative.https.sub.html": [ - "c3248f6096136149e9d496ecd0ffe30106f99326", + "ced6f9845e8af9e6a312d85e9c3f6efa209b8cbb", "testharness" ], "fetch/metadata/navigation.https.sub.html": [ - "50857aeabafc0e544a9895f4b862a38ad50109aa", + "1c2ce9537959c184d864e76010b0d5882932c2a4", "testharness" ], "fetch/metadata/object.tentative.https.sub.html": [ - "40ef308362eea3effd99a11a6b725d182742b8fb", + "cf1c26039995336e413c432c35589322cbcbc43f", "testharness" ], "fetch/metadata/portal.tentative.https.sub.html": [ - "50f0037dfd054dc4a9ea0e70c79b6a42c448d483", + "ee24b5ecbb90c7f0d2892d4f5abeb3c5d1d6acf3", "testharness" ], "fetch/metadata/prefetch.tentative.https.sub.html": [ - "1902b9bca7992a6d29910d60642acd3bdfd08b1c", + "30966f872f85bf0596011b4be2cb192ce7f55d15", "testharness" ], "fetch/metadata/preload.tentative.https.sub.html": [ - "9dbcad322a64bc545f5e00146efcd37f0101235a", + "e8c541ef7f955d72ac95bca171c401c2501f0e5c", "testharness" ], "fetch/metadata/redirect/cross-site-redirect.tentative.https.sub.html": [ - "4747ebf36f87d4b51927f4b87f29c7c180b75170", + "0874273ef94f91eda96b8244ea6c11c9809467eb", "testharness" ], "fetch/metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html": [ - "8120e762517d025d433ab3d28368c56cb0abc43e", + "efff1cdaae8415f54d51b2c54a7cb3f12e6b702e", "testharness" ], "fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html": [ - "a15e681ad84c95c012d0863aa20968e1771a2f1c", + "e7774f6ba10585a1897e11df10ee25fcaae473c6", "testharness" ], "fetch/metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html": [ - "8c65095cc9cd7a3e63c04e990f7c632da0cf0c45", + "b1df738354cc31b9c553b38a0d02f4edaac88462", "testharness" ], "fetch/metadata/redirect/redirect-http-upgrade.tentative.sub.html": [ - "6ba5b948332aa451d10c9c08aa07c80a2f2f8f13", + "c7e1721af78bbf6b3c258df7c7e8f28369c67e27", "testharness" ], "fetch/metadata/redirect/redirect-https-downgrade.tentative.sub.html": [ - "54e48e0c61c258905da416841a6243847ddc65b8", + "eee21dafcac42c5074f786b2b76f12d08735f0ef", "testharness" ], "fetch/metadata/redirect/same-origin-redirect.tentative.https.sub.html": [ - "b88429c540dab3743fb8d674aa0a6927d2ae06d4", + "a31d2d399f2ca7f9c3e167276287baf34e5b9202", "testharness" ], "fetch/metadata/redirect/same-site-redirect.tentative.https.sub.html": [ - "795e418660d8ed6e5b499985415aa6d18970d506", + "f342b1c2669ecc17a68cd2699e786c9ee008af28", "testharness" ], "fetch/metadata/report.tentative.https.sub.html": [ - "8209fd17cd54295faffa9826fa2b7ac371e75eea", + "821c56f5877a7a478047ae8711bb8b4f856d54cd", "testharness" ], "fetch/metadata/report.tentative.https.sub.html.sub.headers": [ @@ -636123,7 +637314,7 @@ "support" ], "fetch/metadata/resources/helper.js": [ - "9425246881b1bdc7f4cace59e4e211d298316197", + "d9b00ed8b94b595a4d4c1a50396355d3518c6496", "support" ], "fetch/metadata/resources/post-to-owner.py": [ @@ -636151,47 +637342,207 @@ "support" ], "fetch/metadata/script.tentative.https.sub.html": [ - "f877b50ec2bd1f04862886853eebf15b0a0dd1c7", + "d5a1096e8198c30e8547e8d6dbcbf71822aad3ed", "testharness" ], "fetch/metadata/script.tentative.sub.html": [ - "66b821265baec27be875bc04dfd8f220facf1e57", + "b1361516cb5371bfe5562a09a32bac680ec2af0d", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html": [ + "469001e2f3380a61f59ffc9cebc123e8912b0f36", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html": [ + "d880deee5dd9560d180357d0631846ae92076447", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html": [ + "63d53e8969dad3d564eedc29675d1fdbd4430eda", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html": [ + "d2341572eb7940fd046e3f895dc251ee27074a5d", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html": [ + "f70ae8b9dd3a55c5dac0d83d01332cd6eba4fea4", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html": [ + "99f8191d7cb928ff5f552e3a4f65e50064bd13b8", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html": [ + "cf6c7977af221f2e5d2abd9f717e55988dc0294a", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html": [ + "bc892db320c29b2979060b4ed29aaf5f507798d8", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html": [ + "d80b727469851c131df6226f20fff03377b4a9c6", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/frame.tentative.sub.html": [ + "61b6d1f446beb918cbaff18d4cbecbab7143aa32", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html": [ + "55e03a23660bc13d98763ffbe0ba8b077914cbcd", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html": [ + "356805d190024230dc691b584c03cb4e6f16951c", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html": [ + "e126e3c0a89147a5d878992f211b19be08e7089c", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html": [ + "f6b84b1795b40b9a9a8e0cab84456ee12d5547ea", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/navigation.https.sub.html": [ + "3ab843d165c0510192bca51a36f701ac583ea1bd", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html": [ + "29db51117858415f4a751892c758c88e9a72bc3e", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html": [ + "ad9e8fd936236ef2d8ba07cb0ad73dadd2e74ce3", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html": [ + "be495ba332ec50e6d2d499b25331154a27dde1a2", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html": [ + "2c82abb366403bd055ad3d95754b3d9df76d06dc", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html": [ + "ea13cc83bdfdb65d2af15f458accc18e20e2b1ec", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html": [ + "e74ce0c06d5b30765a696ea5c57be6f78ff68989", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html": [ + "78ee10dc736cac4ae648254df21afac781ca7526", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html": [ + "90a476684398cad2cf0ce14c29c2dcfcc08ff7c3", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html": [ + "a31efcbf26acd986aab126d990b2eb07f9e0da37", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html": [ + "425753cb5080fab47942a006914d14b9f15cc534", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html": [ + "9b8b44b0ef28882f80a7b6289eb4fe7e6b4b5451", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html": [ + "2f12fe03cab3bee32e9d65be24bbe5784411982b", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html": [ + "d3cb7e101a56c95a2fad3519fc7f6b45789bcd91", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.sub.headers": [ + "1ec5df78f30183b07f2739f180354d87e4572c5b", + "support" + ], + "fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html": [ + "18e8be78848ffc2d821c38545f75d5a5fd23b0e1", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/script.tentative.sub.html": [ + "0512dc676aae721fcbd339540cc9f04f681da2c4", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html": [ + "1faee65bf076d15155e6f678064a851f18b949c9", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html": [ + "882572c86fec7c1b6fcd3b4abbee870fbcb866d7", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html": [ + "ed30c81c7dd23469510ed9a47cd4fef497b976bb", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html": [ + "09e927f1a7c10ab1214c3f4591baeb3944b81e82", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html": [ + "283b928e921917f6d6e54150f992713b29ed4135", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html": [ + "a702fb83d597e7662452d5afc8bcdbf3455502f6", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html": [ + "650ba6afa16c0b4cd230fbc85dfc4adb63001ede", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html": [ + "8e40fb621e24ae1fc60dc512fd8b6455e92bffdb", + "testharness" + ], + "fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html": [ + "df44514fa1f346b5bc46eb73c18495f84c68e8f1", "testharness" ], "fetch/metadata/serviceworker.tentative.https.sub.html": [ - "6fdb37a7f69c2e0bf15bebf5098dcdaac24a9962", + "1fbdee4f091bc46007a627bc80e07c50a1be708f", "testharness" ], "fetch/metadata/sharedworker.tentative.https.sub.html": [ - "90144156ee4b3e36368f685cc4a879f72998ac8e", + "0408c44201fa5125281671e71281d82b0925939f", "testharness" ], "fetch/metadata/style.tentative.https.sub.html": [ - "1f875e8c5104cdf6b950f3c406f8d80206489328", + "08ac184b42109259a5d4977ab1bf0f4865c988b7", "testharness" ], "fetch/metadata/track.tentative.https.sub.html": [ - "63d76372e0329708c6ef5629800c65c8279c358d", + "11e45e23efd00dc5f8c79af8a2f43747628c9050", "testharness" ], "fetch/metadata/trailing-dot.tentative.https.sub.html": [ - "f1a0ad1b485f68a2e097761769b333465b2d614e", + "f7069e7225586ca2de7b3a2c849142e0b4e6a498", "testharness" ], "fetch/metadata/unload.tentative.https.sub.html": [ - "c93ecab3197e32758a173df742a116b90e279f84", + "8917c53a3b3814162366df110fc20aaf38428d3b", "testharness" ], "fetch/metadata/window-open.tentative.https.sub.html": [ - "79f1eec8542a1122e1402dfd734a7051c87bba29", + "29c325f1213e7ca943da8144b0b9badc1e7fb11c", "testharness" ], "fetch/metadata/worker.tentative.https.sub.html": [ - "df1abc4bbca5f69404c9a21dfe9c1b584ddc10a0", + "d2162d5bc7aba1674a75a2f9bc19fccf0aa4eb81", "testharness" ], "fetch/metadata/xslt.tentative.https.sub.html": [ - "6e4f186d55c6c793dc8a6a6006b9217473443236", + "5fc647b3ae7da7a2d0d65a8a6808deb642165084", "testharness" ], "fetch/nosniff/image.html": [ @@ -639815,7 +641166,7 @@ "testharness" ], "html/browsers/origin/cross-origin-objects/cross-origin-objects.html": [ - "72aec0b7542b685945982186f1e2570e80ac6087", + "f16a18d639cc6e528b561d800088fcfebf2c10cf", "testharness" ], "html/browsers/origin/cross-origin-objects/frame-with-then.html": [ @@ -639823,7 +641174,7 @@ "support" ], "html/browsers/origin/cross-origin-objects/frame.html": [ - "3226c8719311f937bcee4ad3b42b840828d0f600", + "ca2dd8ebf829d6f677fdf57b4a6db029a4aa457d", "support" ], "html/browsers/origin/cross-origin-objects/win-documentdomain.sub.html": [ @@ -640202,6 +641553,14 @@ "f266dd7acb96cc473129c066e59f027c2eb067f0", "testharness" ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html": [ + "2acad0734cda6a5076e836240cec107af036a72a", + "testharness" + ], + "html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html": [ + "9d7b9f8a25ecc392abd74949a1362c8b13450a9d", + "support" + ], "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html": [ "d5b1789d59455603d1f5929a7a7f05d8a7218d52", "testharness" @@ -640210,6 +641569,10 @@ "59d94efc994e365301c20dbc5ff1b14409dfcaab", "testharness" ], + "html/browsers/the-window-object/named-access-on-the-window-object/prototype.html": [ + "910374381be85e5b37e1f343b6070ce7a776fe2b", + "testharness" + ], "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [ "c3b3cc185255d159b0f9ff9fd97aae71170d0af6", "support" @@ -650671,7 +652034,7 @@ "testharness" ], "html/semantics/embedded-content/the-iframe-element/iframe-load-event.html": [ - "d245bf0b96451b3419e0e69bda86fe4859c9cbfe", + "5ffe53c308ebed4784543984075deb0e5901be01", "testharness" ], "html/semantics/embedded-content/the-iframe-element/iframe-modify-scrolling-attr-to-yes-ref.html": [ @@ -651734,6 +653097,18 @@ "4ac26092eeea00cc84ccd04154c255280bc76cbb", "testharness" ], + "html/semantics/forms/form-submission-0/form-double-submit-2.html": [ + "f0c9471a704d4c0c0742d7ed8e8f13a789514d69", + "testharness" + ], + "html/semantics/forms/form-submission-0/form-double-submit-3.html": [ + "1bad23260d054b8f60e255de4d1a074803db4b2f", + "testharness" + ], + "html/semantics/forms/form-submission-0/form-double-submit.html": [ + "1102e304174eeec18b65b54deec74a328d998be0", + "testharness" + ], "html/semantics/forms/form-submission-0/form-echo.py": [ "a7f0dc87efd2d3bf8798919649873cb81fc25ade", "support" @@ -656951,7 +658326,7 @@ "testharness" ], "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js": [ - "1d94de8a7c9f28dfab32111deb664d9921437e46", + "ba7278ef18adb42b3f527a9c27ff3a51bdb4dbf7", "testharness" ], "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js": [ @@ -657030,6 +658405,10 @@ "43506a22a46da53885a2b5a0888095bc52b460ca", "testharness" ], + "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html": [ + "a3bdd86ee6ecfda5e09522df5e4c71373a362f5e", + "testharness" + ], "html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js": [ "4efbb863c6372a3ee04d11f38d7ee56a44a2ac7d", "testharness" @@ -657519,7 +658898,7 @@ "testharness" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html": [ - "627a2f3e5a7baca47cf40d8398e77a48d953b626", + "d61618a53ef8afd3cdd2527a0f7f7b094caf570b", "testharness" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-constructor.html": [ @@ -657555,7 +658934,7 @@ "testharness" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py": [ - "3e897bccdce1a3d1c340d03836c23bfabf59e90a", + "be74a36034eda86e1c6d77b84aef3fd631a8a9ef", "support" ], "html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js": [ @@ -658026,18 +659405,6 @@ "2bb82c9834790bfeb1a65cf2ef202dc63d2ebac4", "support" ], - "import-maps/@std/__dir__.headers": [ - "e7ec0d6699d07e5b13d0cb6f24c3639258fccdaa", - "support" - ], - "import-maps/@std/blank": [ - "38e1891bf7d5db9ad7063dc1f22bb17f8b1d4446", - "support" - ], - "import-maps/@std/none": [ - "69e165cce5e223684c9d0f0f7848bc6fc02b14cd", - "support" - ], "import-maps/README.md": [ "3803e350c844b4af77b871831817ac0d90aca97f", "support" @@ -658054,58 +659421,182 @@ "ceef4100aad01f5cd5959086aacf83665f60c805", "testharness" ], - "import-maps/bare.sub.tentative.html": [ - "cf99589f9bd56730423880d6fd4f93df293e6ddf", - "testharness" - ], - "import-maps/bare/__dir__.headers": [ + "import-maps/builtin-support.tentative/@std/__dir__.headers": [ "e7ec0d6699d07e5b13d0cb6f24c3639258fccdaa", "support" ], - "import-maps/bare/bare": [ - "1011e866b81dca7bf423fcb48266463c77591465", + "import-maps/builtin-support.tentative/@std/blank": [ + "38e1891bf7d5db9ad7063dc1f22bb17f8b1d4446", "support" ], - "import-maps/bare/blank": [ - "841d433acf72f828c34faca23f26e9afd10fbab7", + "import-maps/builtin-support.tentative/@std/none": [ + "69e165cce5e223684c9d0f0f7848bc6fc02b14cd", "support" ], - "import-maps/bare/cross-origin-bare": [ - "64851cc8e2455a4cd150b10edf051425bb6dc5bf", + "import-maps/builtin-support.tentative/bare.sub.tentative.html": [ + "e20424aed8a728b31774b71ae98ab7d882df2987", + "testharness" + ], + "import-maps/builtin-support.tentative/bare/__dir__.headers": [ + "e7ec0d6699d07e5b13d0cb6f24c3639258fccdaa", + "support" + ], + "import-maps/builtin-support.tentative/bare/blank": [ + "841d433acf72f828c34faca23f26e9afd10fbab7", "support" ], - "import-maps/bare/none": [ + "import-maps/builtin-support.tentative/bare/none": [ "2aec0d72826f203074dea5a5268b9f937bdb7183", "support" ], - "import-maps/bare/std-blank": [ + "import-maps/builtin-support.tentative/bare/std-blank": [ "5ded98fd382a52a11d52af57cc7e79f56b083843", "support" ], - "import-maps/bare/std-none": [ + "import-maps/builtin-support.tentative/bare/std-none": [ "1437d9ff1e0c0c60672a1f656a2ab91aa01601db", "support" ], - "import-maps/bare/to-bare": [ + "import-maps/builtin-support.tentative/builtin-empty.tentative.html": [ + "9ede75a4c42067a989ee6abaf4728bdaa2d56694", + "testharness" + ], + "import-maps/builtin-support.tentative/builtin-import-scheme.tentative.html": [ + "d9977ae3535c48ebb33e6d3e97bd9d6bab409bc4", + "testharness" + ], + "import-maps/builtin-support.tentative/builtin.tentative.html": [ + "497bb5c606b7648bbdf9a3cd8990b462d9ab7787", + "testharness" + ], + "import-maps/builtin-support.tentative/data.sub.tentative.html": [ + "0377a788491cea37ee42ab4a00fba6a5d0df7d73", + "testharness" + ], + "import-maps/builtin-support.tentative/fallback-disallowed.sub.tentative.html": [ + "7efe90eb751d981012c7d382842001ba176a3b24", + "testharness" + ], + "import-maps/builtin-support.tentative/fallback.sub.tentative.html": [ + "45cf6dc1ced1dc34ef7df4ea477a4a85dbee45ee", + "testharness" + ], + "import-maps/builtin-support.tentative/http.sub.tentative.html": [ + "7689ae13bb5373201890794e7a51e72167e3317d", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html": [ + "0cc92ce3e5e4be7c44abaa41c5d26046feabc049", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html": [ + "9e3bca2935bcf3f52fdfcb76eeb8339674f0db47", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html": [ + "be23c645d0bf071818f96c01b330a5efcab69594", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html": [ + "7bc2d4799f1369750a8675f041c32f36f16c1e8f", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/resolving-builtins.tentative.html": [ + "065cfa30964da0ec2958b4e95634804b8994056b", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html": [ + "3bdd591fd0cba9f83c1bfb6a7e3274532efd2961", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html": [ + "33b49352ccdc3658022559907db7ac5a098ea698", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/resolving.tentative.html": [ + "1d24eb2031e4097551d21df57f0c595957c695ee", + "testharness" + ], + "import-maps/builtin-support.tentative/imported/resources/helpers/parsing.js": [ + "daad6d26d220bb0241f8a413816bd100f3af580d", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/parsing-addresses.js": [ + "0f5fc73506b1222dd7b3ac422d8c6232ac202bd7", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/parsing-schema.js": [ + "695034533c7faa248a29436cfbe805f86506dc48", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/parsing-scope-keys.js": [ + "4993f3a9a8bac441b883be55b58d40423114beab", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/parsing-specifier-keys.js": [ + "9eb423a19eb1fb417526946c1701c7c9dde27c9c", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-builtins.js": [ + "a9383df843d44794351d5c6ffa5580d4d1254b9c", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-not-yet-implemented.js": [ + "93d782fdad83d58160061a4caa40659292a50866", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/resolving-scopes.js": [ + "ca19a66840601efe66fa2db24cffdcc0727681c5", + "support" + ], + "import-maps/builtin-support.tentative/imported/resources/resolving.js": [ + "29ee31ccbc936787894a43de1f6625608d14a192", + "support" + ], + "import-maps/builtin-support.tentative/static-import.js": [ + "1686fc123a798bddbf626f4d112516317739da8f", + "support" + ], + "import-maps/core/bare.sub.tentative.html": [ + "7fb769e09a2af432517522f91a2a101efc484ad8", + "testharness" + ], + "import-maps/core/bare/__dir__.headers": [ + "e7ec0d6699d07e5b13d0cb6f24c3639258fccdaa", + "support" + ], + "import-maps/core/bare/bare": [ + "1011e866b81dca7bf423fcb48266463c77591465", + "support" + ], + "import-maps/core/bare/cross-origin-bare": [ + "64851cc8e2455a4cd150b10edf051425bb6dc5bf", + "support" + ], + "import-maps/core/bare/to-bare": [ "bdb3791bc9471533434067b826dc59fef07e1c0c", "support" ], - "import-maps/bare/to-data": [ + "import-maps/core/bare/to-data": [ "6f25c5af12412dc6dbb374d4bee0fdd1472f475e", "support" ], - "import-maps/builtin-empty.tentative.html": [ - "aba28d18e043d53271888a382a7f7b4ca89a054a", + "import-maps/core/data.sub.tentative.html": [ + "25c18c45b7dc3e7311247fc945eb08a75185085f", "testharness" ], - "import-maps/builtin-import-scheme.tentative.html": [ - "6a27ef5aee2371b2114bc75b2b194c22a5fa85c2", + "import-maps/core/http.sub.tentative.html": [ + "a33a0945e316711a4338045f53ab71d91121c8f6", "testharness" ], - "import-maps/builtin.tentative.html": [ - "e85289e4d884d49bb4520154cecdd2826a07b333", + "import-maps/core/module-map-key.tentative.html": [ + "6f2f18a02e12a92530b7a3ae6bbbd31eecff3816", "testharness" ], + "import-maps/core/static-import.js": [ + "1686fc123a798bddbf626f4d112516317739da8f", + "support" + ], "import-maps/csp/applied-to-target-dynamic.sub.tentative.html": [ "cef80bfcda72956fe7acc59788d984370f25a62f", "testharness" @@ -658134,22 +659625,6 @@ "101c33cf84e9fb5e68cf8d5910f4ffbe7949e9d7", "testharness" ], - "import-maps/data.sub.tentative.html": [ - "634948942eea674ec923a4cb718cb92d5aab9021", - "testharness" - ], - "import-maps/fallback-disallowed.sub.tentative.html": [ - "280d02d847314f97bb88e02618aa46256e055f04", - "testharness" - ], - "import-maps/fallback.sub.tentative.html": [ - "3f4f2887da8208e8f65df41735e5b95e6bf59d4f", - "testharness" - ], - "import-maps/http.sub.tentative.html": [ - "bd24f3535507334a69bb98b711106466c8a340a3", - "testharness" - ], "import-maps/imported/parsing-addresses.tentative.html": [ "ddb3b724bb64e2edd60a620dc6ae1cc98f32a92a", "testharness" @@ -658166,14 +659641,6 @@ "dd547f01d1dfb2379f6afa893385fadc8f1217d1", "testharness" ], - "import-maps/imported/resolving-builtins.tentative.html": [ - "c1395c175c77455361e5ea51819ece56dd24737a", - "testharness" - ], - "import-maps/imported/resolving-not-yet-implemented.tentative.html": [ - "7db5f29f892976720a145499d6e40ccb8959b006", - "testharness" - ], "import-maps/imported/resolving-scopes.tentative.html": [ "4985249f4e2951965ad78321208ee08eca8617fa", "testharness" @@ -658183,51 +659650,39 @@ "testharness" ], "import-maps/imported/resources/helpers/parsing.js": [ - "5c22f6de710ea32753707273be5d63a285633860", + "daad6d26d220bb0241f8a413816bd100f3af580d", "support" ], "import-maps/imported/resources/parsing-addresses.js": [ - "0f5fc73506b1222dd7b3ac422d8c6232ac202bd7", + "92d7714ade9b965325372d58775bd990d3a1ce85", "support" ], "import-maps/imported/resources/parsing-schema.js": [ - "695034533c7faa248a29436cfbe805f86506dc48", + "f60422ae62bce21079cee8d6880cba0dc0dddaa5", "support" ], "import-maps/imported/resources/parsing-scope-keys.js": [ - "cd1d9b34890971dbb21f7bde5d34ed9f2cc91f20", + "4993f3a9a8bac441b883be55b58d40423114beab", "support" ], "import-maps/imported/resources/parsing-specifier-keys.js": [ - "9eb423a19eb1fb417526946c1701c7c9dde27c9c", - "support" - ], - "import-maps/imported/resources/resolving-builtins.js": [ - "a9383df843d44794351d5c6ffa5580d4d1254b9c", - "support" - ], - "import-maps/imported/resources/resolving-not-yet-implemented.js": [ - "93d782fdad83d58160061a4caa40659292a50866", + "7ac24bf867b06a6393fbd1ef8e9478d28b2d714d", "support" ], "import-maps/imported/resources/resolving-scopes.js": [ - "ca19a66840601efe66fa2db24cffdcc0727681c5", + "d133b50bd2b8d80ae6b08531e9ff8607e8ed16f6", "support" ], "import-maps/imported/resources/resolving.js": [ - "29ee31ccbc936787894a43de1f6625608d14a192", + "ef8a4f87d25e7fc6f11c3ee7ed6ef64497058d97", "support" ], - "import-maps/module-map-key.tentative.html": [ - "13bd122c673144f001048eacbaf4fc7bb78c9b58", - "testharness" - ], "import-maps/resources/empty.js": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "support" ], "import-maps/resources/jest-test-helper.js": [ - "8d9236a84d81f838a50acefffca105b44eb5025f", + "8fa7b65adb5f77d0e5a6282305641c8268948cb4", "support" ], "import-maps/resources/log.js": [ @@ -658239,11 +659694,7 @@ "support" ], "import-maps/resources/test-helper.js": [ - "2447bfb94353e1ec193857cbcda79f46556216a1", - "support" - ], - "import-maps/static-import.js": [ - "1686fc123a798bddbf626f4d112516317739da8f", + "f21ad935baa5e1310e15232822902c86481bebc4", "support" ], "inert/frame/button.html": [ @@ -658394,8 +659845,12 @@ "f25f6e088fa06fbcd38b62929309e761b0060988", "testharness" ], + "infrastructure/metadata/infrastructure/assumptions/ahem.html.ini": [ + "8587775d8fc86891605a1509d3062a2c08f56a31", + "support" + ], "infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini": [ - "c9fbabede6d695cd3795e4390b35da0454ffcc34", + "c6f136d9715e86db9952dd6eac80b09b7782eed8", "support" ], "infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini": [ @@ -658502,6 +659957,10 @@ "9ae71a6e73e22a855c69d3269936d71c17d6e9e5", "support" ], + "infrastructure/metadata/infrastructure/testdriver/actions/elementTiming.html.ini": [ + "fb4b51df66dfe434934f0f0110340e7e2d122f10", + "support" + ], "infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini": [ "894f4a11df81be8e164898ab2091e1cc64175290", "support" @@ -658514,6 +659973,10 @@ "657d2a2492605557dcc62f02dca36364cf3007fd", "support" ], + "infrastructure/metadata/infrastructure/testdriver/bless.html.ini": [ + "d652b02787fb13e70fa5008a5b5f656dbacda8a3", + "support" + ], "infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini": [ "e2bfbf8fb8fb71003bd06a8356fec3a074395040", "support" @@ -658831,11 +660294,11 @@ "support" ], "interfaces/META.yml": [ - "6895a5fc5674a099909a481a46726c990804fc61", + "c1dd8dddf9eec3ab3fb58df01c549c251f3a3fdf", "support" ], "interfaces/README.md": [ - "f70ffd2e11e8ead7ccefed830331a1a5017a43e4", + "e0cdf0bc8fb16e32e3ea5465247756957ec1b73e", "support" ], "interfaces/SRI.idl": [ @@ -658966,6 +660429,10 @@ "f7cf3d31a114a653734990ef081ac109478dfcd8", "support" ], + "interfaces/css-shadow-parts.idl": [ + "66aaeba73a7a62280171ea1765915991b9da1ba3", + "support" + ], "interfaces/css-transitions.idl": [ "15ce4b30f211012b5fd9e6a713d92c0ea1045a54", "support" @@ -659215,7 +660682,7 @@ "support" ], "interfaces/reporting.idl": [ - "05d5a42458b5cd38c4a902b5a7066af524a396fc", + "f5370e8f1e656acf7409dbda907ee9672d5e8ed1", "support" ], "interfaces/requestidlecallback.idl": [ @@ -659275,7 +660742,7 @@ "support" ], "interfaces/trusted-types.tentative.idl": [ - "6ff45e7050c90feda36f99a422a243c01ff51156", + "be58b63b2c3d10e8a53ac2af7388e9a44f8fa3e6", "support" ], "interfaces/uievents.idl": [ @@ -659319,7 +660786,7 @@ "support" ], "interfaces/web-nfc.idl": [ - "4e0dc0725163e42455fb3418ed9757ddc1d8f632", + "5f0dd23a1cde61d4489e60ba82c48ccc74be67dd", "support" ], "interfaces/web-share.idl": [ @@ -659426,6 +660893,10 @@ "cae35095e8ec25b4fb6aa2ec4a2b55076fb7f269", "testharness" ], + "intersection-observer/document-scrolling-element-root.html": [ + "9996299312c996f3705af12e35c6eab088905047", + "testharness" + ], "intersection-observer/edge-inclusive-intersection.html": [ "b73c407a274bde4f4361c6b03bb1d214d86095cf", "testharness" @@ -659902,6 +661373,10 @@ "44d2a1a968083e8c91f61b33909ec115ea1b3a63", "testharness" ], + "largest-contentful-paint/first-paint-equals-lcp-text.html": [ + "a49a83f346d59f8c5e1a218891ecddc5a85ac5ea", + "testharness" + ], "largest-contentful-paint/idlharness.html": [ "273fef80ce2d855075781512a9a8ab0a736af420", "testharness" @@ -660067,7 +661542,7 @@ "testharness" ], "lint.whitelist": [ - "d9ea5c17c7cf66a47199faba54d4793e8236f6cb", + "afdc20b67b544ddc7a8ddee518e76f748e147def", "support" ], "loading/lazyload/common.js": [ @@ -673579,7 +675054,7 @@ "testharness" ], "pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html": [ - "fa9a5fb3c5b8ae7df867159aab8fc3ad7a6c77e2", + "b9172dddb4c576eedeeec696af9576cb9a47e6a0", "testharness" ], "pointerevents/pointerevent_setpointercapture_invalid_pointerid.html": [ @@ -673830,6 +675305,34 @@ "d50520cd391a17bf175e9eb7a37ce7adc5be4c91", "support" ], + "portals/history/history-manipulation-inside-portal-with-subframes.html": [ + "8f69182f6467cbf504a5c5cb28bf9cc10ea0b1ba", + "testharness" + ], + "portals/history/history-manipulation-inside-portal.html": [ + "0fe88c4ea113d14f9800f69f49358ca4ff453ee3", + "testharness" + ], + "portals/history/resources/inner-iframe.html": [ + "5c6daa22a55b5c453355eb9fe3abcd549a8f36ac", + "support" + ], + "portals/history/resources/portal-harness.js": [ + "9761ac9268bce245cdf5335a613127874c0fd976", + "support" + ], + "portals/history/resources/portal-manipulate-history-with-subframes.sub.html": [ + "4b3e8cf2d923327f6a39ee46676bf4f2163350a3", + "support" + ], + "portals/history/resources/portal-manipulate-history.html": [ + "591fd2193c1ee7fc9080d0a775afa8870ab8f079", + "support" + ], + "portals/history/resources/run-test-in-portal.js": [ + "c982a1fac8ea4f96b0c7697ec5ec8c45fae44933", + "support" + ], "portals/htmlportalelement-event-handler-content-attributes.html": [ "8fc26386cfc9d30e89062440b9347c62b60aa592", "testharness" @@ -687107,7 +688610,7 @@ "support" ], "resource-timing/SyntheticResponse.py": [ - "26e0a8017d6c2c7b51c94998f34a79fa20eb1e12", + "c5158002f18a2af5c4d65a17c112547f3c3db508", "support" ], "resource-timing/TAO-case-insensitive-null-opaque-origin.sub.html": [ @@ -687622,6 +689125,10 @@ "c7f777a174a6a307c81fba3d6082fb152be99b1f", "testharness" ], + "resource-timing/sleep.py": [ + "2e803b1b262423e219be592fab548ada982bc439", + "support" + ], "resource-timing/status-codes-create-entry.html": [ "22e22c445b0812461ef06eb35ad6b611a3b6faa5", "testharness" @@ -690099,7 +691606,7 @@ "testharness" ], "service-workers/service-worker/fetch-waits-for-activate.https.html": [ - "889c5ec7bbb9367715118f78ae81a994856ad99f", + "7c888450f0d5f5fc72ec38909487877f38a1c024", "testharness" ], "service-workers/service-worker/getregistration.https.html": [ @@ -690995,7 +692502,7 @@ "support" ], "service-workers/service-worker/resources/fetch-waits-for-activate-worker.js": [ - "66f3e5936196d002f9e248677cfce7a211ded8a5", + "92a96ff88fb903748aebf6d6a0efaeb529c7ad39", "support" ], "service-workers/service-worker/resources/frame-for-getregistrations.html": [ @@ -692026,10 +693533,30 @@ "20456b057e1e724cdac9bc656f3b3d6c7ac2f658", "testharness" ], + "shadow-dom/focus/click-focus-delegatesFocus-click-method.html": [ + "92212cd85b86615db21192faa731799218a08d67", + "testharness" + ], + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html": [ + "4051db128a915000bff162fefe4bed55eb338061", + "testharness" + ], + "shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html": [ + "5f7914f2a4e31e107caa817de1b29720c9a21862", + "testharness" + ], + "shadow-dom/focus/focus-method-delegatesFocus.html": [ + "462542e3f7be18bc609b3e6d2c9d9e6ecde30a9f", + "testharness" + ], "shadow-dom/focus/focus-selector-delegatesFocus.html": [ "3702f8e2ba63228cba5c483a76f2b77372e68c4d", "testharness" ], + "shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html": [ + "356b0bb329e27bf2706cbfeda66624adc277d43d", + "testharness" + ], "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [ "ab25ea829bd10952ad6e96898fc95a1a1ae25d8f", "testharness" @@ -692038,10 +693565,18 @@ "3c9e70867c5883e96f6288b85a9bac60b9526f4e", "testharness" ], + "shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html": [ + "67899cff4a9d2e2acac622147c395720fb110f72", + "testharness" + ], "shadow-dom/focus/focus-tabindex-order-shadow-varying-tabindex.html": [ "875e5b6814a95754f5c01d18c125c39c363ad3c6", "testharness" ], + "shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html": [ + "5e6ab3a90f8f12274c58620220e00e6bec09fc44", + "testharness" + ], "shadow-dom/focus/focus-tabindex-order-shadow-zero-host-negative.html": [ "b491c7d237c20604039f2b6482d484635c9f50da", "testharness" @@ -693182,7 +694717,7 @@ "a50c8bf1aeb4535ca18202274403ebe60ade5db7", "support" ], - "storage-access-api/idl.window.js": [ + "storage-access-api/idlharness.window.js": [ "a0b4c37d916a8ef66b2c09ad6afee5ec9f21e12f", "testharness" ], @@ -694355,7 +695890,7 @@ "testharness" ], "svg/animations/syncbase-remove-add-while-running.html": [ - "5b3ae94488f0a83f61cf1b4af4f6c9dc613552dc", + "61b9604a7b6751a156c48431b89fa2f3cd1af551", "testharness" ], "svg/coordinate-systems/abspos.html": [ @@ -698086,6 +699621,10 @@ "df64cc9ec3d387f26238b66b92c9f356f2f23e09", "testharness" ], + "svg/text/reftests/dominant-baseline-hanging-small-font-size.svg": [ + "aa27ec9c09484634330d04b3a1876640856f10f5", + "reftest" + ], "svg/text/reftests/text-clipped-offscreen-move-onscreen-ref.html": [ "b03ac22aaa3155323ea1574e49241368ec1ad66c", "support" @@ -698595,7 +700134,7 @@ "support" ], "tools/ci/azure/install_safari.yml": [ - "bfb6afc332b1b85d7c322e19066708f034e9ac77", + "2c4a25c83a494ad798e80664f417c53c3ec40ab8", "support" ], "tools/ci/azure/pip_install.yml": [ @@ -698655,7 +700194,7 @@ "support" ], "tools/ci/run_tc.py": [ - "956d1c353e54b2179316ad56ff85823bc5009ea6", + "60f175808715e2d8adf173c3145dc06b7bea64c2", "support" ], "tools/ci/taskcluster-run.py": [ @@ -703443,7 +704982,7 @@ "support" ], "tools/wpt/commands.json": [ - "178eda9c2656c393132792c2206489ee95a6a362", + "60fe1621af0decd0faa434f26dcba995154173e7", "support" ], "tools/wpt/create.py": [ @@ -703470,6 +705009,10 @@ "566083cb6be89a03e48cc5c1a0a88fc5ce53a853", "support" ], + "tools/wpt/revlist.py": [ + "f750311914ac13408cc082e58c36c2471e8f48be", + "support" + ], "tools/wpt/run.py": [ "de20e2916ad30244ef3635d1fce562cebbd26052", "support" @@ -703486,6 +705029,10 @@ "25b66e7d922f54edf197baaaf42c26c9fce04621", "support" ], + "tools/wpt/tests/test_revlist.py": [ + "7b13106d0f553727f6bdb32c47a6babf70d8f4a8", + "support" + ], "tools/wpt/tests/test_run.py": [ "ef58ec41b2b4cfc14955b701627d047af78f29bc", "support" @@ -703743,7 +705290,7 @@ "support" ], "tools/wptrunner/wptrunner/browsers/android_webview.py": [ - "dd45c0494b662a2b64709c32f4f45153bf3fc1f7", + "dc687b48ed7a9dde827334ae8b59096cc58d24d7", "support" ], "tools/wptrunner/wptrunner/browsers/base.py": [ @@ -703779,7 +705326,7 @@ "support" ], "tools/wptrunner/wptrunner/browsers/firefox.py": [ - "781d7e31c43c01c0a33328e1dc921f4f536d5296", + "6cf784fd01049a24ad6c8253179ad61d62073774", "support" ], "tools/wptrunner/wptrunner/browsers/firefox_android.py": [ @@ -703955,7 +705502,7 @@ "support" ], "tools/wptrunner/wptrunner/formatters/wptreport.py": [ - "d73911f6a94e922dc8dc6f1d7f746abbf1a04362", + "6d4401ae5aacf9db028f94e88bbfcc2be33726c3", "support" ], "tools/wptrunner/wptrunner/formatters/wptscreenshot.py": [ @@ -703975,7 +705522,7 @@ "support" ], "tools/wptrunner/wptrunner/metadata.py": [ - "15bbf94c33cea80ab4d0fdd958618f264fa57ab1", + "c328dcefa7253ddea952549c702723e98b4cadc4", "support" ], "tools/wptrunner/wptrunner/products.py": [ @@ -704059,7 +705606,7 @@ "support" ], "tools/wptrunner/wptrunner/tests/test_update.py": [ - "d453ae5b464d6a1570f03f99c8e9522a4fcdeeaa", + "5d900a3d6c9cd23696fe0d2b7c20d8ff5142b9e5", "support" ], "tools/wptrunner/wptrunner/tests/test_wpttest.py": [ @@ -704123,7 +705670,7 @@ "support" ], "tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py": [ - "43225a1e72861ee4ee3b8b6e1fb0594a17a0891d", + "aacd7857072f420a209aeeff559ec2ae294170ba", "support" ], "tools/wptrunner/wptrunner/wptmanifest/backends/static.py": [ @@ -704587,11 +706134,11 @@ "testharness" ], "trusted-types/Element-setAttribute.tentative.html": [ - "a284b2f83550b1b0e4cf7c79e7a200791ae8c70a", + "cd6617915bdd16343ff2499e09991fba50b444bc", "testharness" ], "trusted-types/Element-setAttributeNS.tentative.html": [ - "374e6a9cfa3c36a21daf7d8dd6d8111981fe192b", + "67e8236febd77ed3b544126d8c5f9dd37cc513ab", "testharness" ], "trusted-types/GlobalEventHandlers-onclick.tentative.html": [ @@ -704599,19 +706146,7 @@ "testharness" ], "trusted-types/HTMLElement-generic.tentative.html": [ - "d1fafa70cd2768e7b98b5eab6da9f5eb77175fbc", - "testharness" - ], - "trusted-types/Location-assign.tentative.html": [ - "62f98e96d7febe6c744b882f8d196d1686fe9166", - "testharness" - ], - "trusted-types/Location-href.tentative.html": [ - "bacadf6a91b1c0bc5c76293aab38f9d503cfa2b7", - "testharness" - ], - "trusted-types/Location-replace.tentative.html": [ - "4fb53d0260973ed5d714540a448909488b6e2465", + "3ec6cfa60da6d86e6be2e3ce68ae227441e6c5bb", "testharness" ], "trusted-types/META.yml": [ @@ -704639,7 +706174,7 @@ "testharness" ], "trusted-types/TrustedTypePolicy-createXXX.tentative.html": [ - "73ed8c72b23d5101f8e9e0f9867b1330aef0dc87", + "34fbf5587daf725222dd191fc941fffe2630e106", "testharness" ], "trusted-types/TrustedTypePolicy-name.tentative.html": [ @@ -704651,7 +706186,7 @@ "testharness" ], "trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html": [ - "05c7301af7172165a6594e56eadc413cc6900977", + "8608bcc24fed0fb050925bd52830db38082ae3b1", "testharness" ], "trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html": [ @@ -704675,25 +706210,21 @@ "testharness" ], "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html": [ - "f9ba8f2782209df2362c902d5666dbbf4bba34f8", + "0e5a0f51c80bf91c21b37bf02645c70b26ecf374", "testharness" ], "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html": [ - "efaac5d90d8f07f79f89aa72e633294a60487018", + "c620451ba8f797228fd20ea130aeff66d639cd73", "testharness" ], "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html": [ - "70f77b1bb552c3e1f9069b8847a2231aa5b19d48", + "da7d1b4f87700e15420c7c849eaa683cd42c0e5d", "testharness" ], "trusted-types/Window-TrustedTypes.tentative.html": [ "c61d9207b65f430b08c6801a5ffc04d3d0efedd1", "testharness" ], - "trusted-types/Window-open.tentative.html": [ - "172d566e57fc635b551b5d355661db690869b220", - "testharness" - ], "trusted-types/WorkerGlobalScope-importScripts.https.html": [ "9dbfd7b93c97abda7beff52e2e9afebefe518f29", "testharness" @@ -704727,43 +706258,27 @@ "testharness" ], "trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html": [ - "3cae5d29b445ec452d6832c062bf6ce59a54242f", + "1d6f3f6fe62afb4d76ecc4e3ea73c7d1136e9550", "testharness" ], "trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html": [ - "76a639a622799dcb9769ad4781104d17be8439bc", + "5754521b2bd78ebf31c496961108386aff23650f", "testharness" ], "trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html": [ - "89d1216d27e2dcf27ad5faa941e224cc495e9363", - "testharness" - ], - "trusted-types/block-string-assignment-to-Location-assign.tentative.html": [ - "8e89d0d1a6044a354011ed904a621fc519e619ed", - "testharness" - ], - "trusted-types/block-string-assignment-to-Location-href.tentative.html": [ - "998ee21f3456a8a59692774d057bddba349ee15f", - "testharness" - ], - "trusted-types/block-string-assignment-to-Location-replace.tentative.html": [ - "e85bb646fc96f2eafbe2c1953633ebcd59212641", + "84ff83bc083ac473704d791f929df5ae6ba7f1f6", "testharness" ], "trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html": [ "61553eb71dfcf4a49e580450602aabcc3e515282", "testharness" ], - "trusted-types/block-string-assignment-to-Window-open.tentative.html": [ - "e9c1c79050be5c0d28ea6927e9f8285da11b973d", - "testharness" - ], "trusted-types/block-text-node-insertion-into-script-element.tentative.html": [ "a6aa061f7307330e027c3e8b26e6b931cee2bb7c", "testharness" ], "trusted-types/default-policy-report-only.tentative.html": [ - "1a54fd6232917415338e3fac3f622f929a4432f8", + "ba23d7a3678e12419f077cd870e5e56fa701ad63", "testharness" ], "trusted-types/default-policy-report-only.tentative.html.headers": [ @@ -704771,7 +706286,7 @@ "support" ], "trusted-types/default-policy.tentative.html": [ - "672eccfb430b404f8d13e8fb3ec8ea8408d4a70c", + "955cdfaa4042119f04ad21622fdc804872613e0f", "testharness" ], "trusted-types/default-policy.tentative.html.headers": [ @@ -704783,7 +706298,7 @@ "testharness" ], "trusted-types/idlharness.window.js": [ - "4c1ee6e04a36971593eea7e89841d147a4febcd5", + "7be9615ce67ca1582c3b82ed849d7019a61e4cdd", "testharness" ], "trusted-types/support/WorkerGlobalScope-importScripts.https.js": [ @@ -704795,7 +706310,7 @@ "support" ], "trusted-types/support/helper.sub.js": [ - "d63ff54ad60d40045da5bbe864458688c0554dbc", + "d13ad567a726f39299a7e7f58aeffec4ba90a908", "support" ], "trusted-types/support/worker.js": [ @@ -704827,7 +706342,7 @@ "support" ], "trusted-types/trusted-types-report-only.tentative.https.html": [ - "1a17d529fd158db853af547c55de675bf71f194e", + "bf0a1eb9c1911e2fb25ed89dbd14e7dfd86cf358", "testharness" ], "trusted-types/trusted-types-report-only.tentative.https.html.headers": [ @@ -704843,7 +706358,7 @@ "support" ], "trusted-types/trusted-types-reporting.tentative.https.html": [ - "6a79fec07b6626c87a22a3b1c4e778a33c975e67", + "10a951fa12cb8d69249a96cb85ce34f6136e52c5", "testharness" ], "trusted-types/trusted-types-reporting.tentative.https.html.headers": [ @@ -709598,6 +711113,10 @@ "62f59a75db2e65b24807efff74321b9083e1604b", "testharness" ], + "wake-lock/wakelockpermissiondescriptor.https.html": [ + "673990f36f6b3e2bbf4024ef52d2f1cbde600cc9", + "testharness" + ], "wasm/META.yml": [ "3ea02ee7c9e41831aafbd37436f59b51244b142e", "support" @@ -710427,7 +711946,7 @@ "support" ], "web-nfc/NDEFMessage_constructor.https.html": [ - "19122112f59bbbbb15f4988e841ab7b18042c4e6", + "88c9ec4006e60c27a0c33f154a3f7f419f5ee2a3", "testharness" ], "web-nfc/NDEFRecord_constructor.https.html": [ @@ -710450,6 +711969,10 @@ "638d0c5a1d1b8d0e2e8e8422bd4b9e9488512e54", "testharness" ], + "web-nfc/NFCReader_scan_iframe.https.html": [ + "1f29fe4b41d9028a2381210b8b3d9ccba598b9b2", + "testharness" + ], "web-nfc/NFCReadingEvent_constructor.https.html": [ "20585176b7f89a129fad99f17d068b2deb828f68", "testharness" @@ -710459,7 +711982,7 @@ "manual" ], "web-nfc/NFCWriter_push.https.html": [ - "dda160f159a23223c0910d2393ecbc8c8e38aed1", + "6b4034fccc2987c0366ccdfd58dd394a5111709b", "testharness" ], "web-nfc/README.md": [ @@ -710478,6 +712001,10 @@ "ed5cc9c9718d01580460535ea14405c2817c0986", "support" ], + "web-nfc/resources/support-iframe.html": [ + "540eab108b19fe917272ad718445693abb989dbe", + "support" + ], "web-share/META.yml": [ "d2eccca6f424e93cc463fafc5a3b16e5a7ecc565", "support" @@ -711855,7 +713382,7 @@ "support" ], "webdriver/tests/element_click/bubbling.py": [ - "2b08be1f983787f69507176b650e64902577b72d", + "a069a5a5df3d7f2bd2851eb4f1a2f9aecdeed86c", "wdspec" ], "webdriver/tests/element_click/center_point.py": [ @@ -712727,7 +714254,7 @@ "testharness" ], "webgpu/cts.html": [ - "661060fcd7b32f7cecbbbc87499c7b70d1f39694", + "b60faec9623bb0adf7c1b9ad0e5d488ce14b5882", "testharness" ], "webgpu/framework/allowed_characters.js": [ @@ -712739,7 +714266,7 @@ "support" ], "webgpu/framework/fixture.js": [ - "d77ede708f0377feec5101d7272eaf27d07c5598", + "6e13385eef42d8af73b97a44a0945802483538c7", "support" ], "webgpu/framework/gpu/implementation.js": [ @@ -712763,7 +714290,7 @@ "support" ], "webgpu/framework/logger.js": [ - "8aa332c571a19f9db7a5486b9a8d28269101051e", + "d97be59091a1d9b5eadd93a105ba1023e730f8a1", "support" ], "webgpu/framework/params/combine.js": [ @@ -712787,11 +714314,11 @@ "support" ], "webgpu/framework/test_filter/filter_by_group.js": [ - "3036e21bd63c40b7d34f0f46dea432d505b131b1", + "e7cc5f78ba52a49eb021bf7cc9247448f2620f53", "support" ], "webgpu/framework/test_filter/filter_one_file.js": [ - "6a998db0de9c96f796bd05f90e73e60e0d141aee", + "7616bee6afeaec3fb6836f21fd318a4185d78c5a", "support" ], "webgpu/framework/test_filter/index.js": [ @@ -712807,27 +714334,35 @@ "support" ], "webgpu/framework/test_group.js": [ - "c9cafb37b670dd1cf79a46fbcb6acd595b3b53b7", + "09697765b8c7c715bac92536418cceb1ce632ef9", "support" ], "webgpu/framework/url_query.js": [ - "b265139043918b98e9937a6c216e3748a7c5cb87", + "f7c7cbc17fe5a908eb5b496a4a267274ebbc0030", + "support" + ], + "webgpu/framework/util/async_mutex.js": [ + "cb900605bcfe77bae785c207419787e317bf1d73", "support" ], "webgpu/framework/util/index.js": [ - "8d0fe0e5b48c6149bbf5c1f0aa8af2876fad00a3", + "32aea98dea7040379b5f2ccd74fdd57dd264f632", "support" ], "webgpu/framework/util/stack.js": [ "ae99ac904a132d947f304ca0f03f50b25fd197ae", "support" ], + "webgpu/framework/util/timeout.js": [ + "e565a518efc045cfc90e7dd7b23dc65604c6b805", + "support" + ], "webgpu/framework/version.js": [ - "9be025609f36ae16b7395de98c355f6872a9d660", + "0bfbfad4f3995d27200b1601ef8411f5b16c12ae", "support" ], "webgpu/runtime/wpt.js": [ - "d11499f1e8cd45553e2ae6832413e108790fe505", + "ec4ab0123924659e9cb23ba916c51d7ea6aa75cc", "support" ], "webgpu/suites/cts/buffers/create_mapped.spec.js": [ @@ -712855,39 +714390,119 @@ "support" ], "webgpu/suites/cts/command_buffer/basic.spec.js": [ - "137e428bd9db9311987662d6e5024c31f04742ca", + "c4333c794d2d75ca0b09991da9b40cd864b2bb91", "support" ], "webgpu/suites/cts/command_buffer/compute/basic.spec.js": [ - "56754d5f39e21f483f9f21e931e35a7dfa1e1259", + "a001cbc0d82dc1388e875254d1eddd505ffc01f4", "support" ], "webgpu/suites/cts/command_buffer/copies.spec.js": [ - "9bf78db8454bf848a6a1236db6503f893d33a225", + "0055a58d115303f0dfdd79422babfede04efd3c3", "support" ], "webgpu/suites/cts/command_buffer/render/basic.spec.js": [ - "83bb026d963d105e3e73ae118664d9951d246710", + "8f4d8c879da7b16f3fc162c697025c2fab4c6ff7", "support" ], "webgpu/suites/cts/command_buffer/render/rendering.spec.js": [ - "c8a7d7f5738b6efd199e96fadb937a64bd603d99", + "c065ed23be4f21d3368742e0760f07cea2c6f6ff", + "support" + ], + "webgpu/suites/cts/command_buffer/render/storeop.spec.js": [ + "da58ad2d8a571685134180199369244339d4a4a1", "support" ], "webgpu/suites/cts/examples.spec.js": [ - "ad86e73b191e74a8a23a81ccccf54cc2c95f3fa9", + "8a992a6239d78c1f45b2323d77690b8c5b4fab1f", "support" ], "webgpu/suites/cts/fences.spec.js": [ - "d9f8ce57678e9907f20a5819b2a43686e27ba53c", + "ccf513633daf307119ffcfc0eb3e81d27da3f9d3", "support" ], "webgpu/suites/cts/gpu_test.js": [ - "a67ce4ab0ba24f13c8a66dae551390c3d71d06ba", + "e437ee09449bae87f6b410c1643b8c23e628d703", "support" ], "webgpu/suites/cts/index.js": [ - "cb2a592697f9b1041e5a2f71cf59939b5a04ed4a", + "b38ea11df28f63c6374d9b58df5c276d636b7b8d", + "support" + ], + "webgpu/suites/cts/validation/createBindGroup.spec.js": [ + "24d29d0e61e653c34ebde4a35bb01717ee23ab9e", + "support" + ], + "webgpu/suites/cts/validation/createBindGroupLayout.spec.js": [ + "8e3bfc22572c6e8bbeab51c98520f1cfbb3633b2", + "support" + ], + "webgpu/suites/cts/validation/createPipelineLayout.spec.js": [ + "dc759750a986630dc87ea5136afffb4b3b5bd396", + "support" + ], + "webgpu/suites/cts/validation/createRenderPipeline.spec.js": [ + "7cbe93dd9c958cc8331316a522846d126be89556", + "support" + ], + "webgpu/suites/cts/validation/createTexture.spec.js": [ + "c99204b9667fbfa53d743eff285a4090abe70b07", + "support" + ], + "webgpu/suites/cts/validation/createView.spec.js": [ + "2330c6ecdd91abedde02e88391921586cfd40dec", + "support" + ], + "webgpu/suites/cts/validation/error_scope.spec.js": [ + "2232db9b54e48426abf18f0d3c91f3c8901437de", + "support" + ], + "webgpu/suites/cts/validation/fences.spec.js": [ + "4aca3d7773afff6a801a705ca36fe675ee429588", + "support" + ], + "webgpu/suites/cts/validation/queue_submit.spec.js": [ + "50d912f4d6f2a3d53e072fae9b9930616e7ed1a7", + "support" + ], + "webgpu/suites/cts/validation/render_pass.spec.js": [ + "f71a4a2b97420ab76ead6cadf29c31e3d440ce1a", + "support" + ], + "webgpu/suites/cts/validation/render_pass_descriptor.spec.js": [ + "5a171879082762b039c1f21d18f7066b5c193078", + "support" + ], + "webgpu/suites/cts/validation/setBindGroup.spec.js": [ + "c669ea08d586b4911a74336314c72437aa2abec3", + "support" + ], + "webgpu/suites/cts/validation/setBlendColor.spec.js": [ + "a04bcd038ee5f0f957772bb52a63563b400fa502", + "support" + ], + "webgpu/suites/cts/validation/setScissorRect.spec.js": [ + "ee1588d2a885bd2d0fc386737b3e37a5fc91dd7d", + "support" + ], + "webgpu/suites/cts/validation/setStencilReference.spec.js": [ + "3db37a4908e719212043856b9bdf5e3b31a91065", + "support" + ], + "webgpu/suites/cts/validation/setVertexBuffer.spec.js": [ + "949dd91932d8d4e6b498f578e11d5c7c3fb019df", + "support" + ], + "webgpu/suites/cts/validation/setViewport.spec.js": [ + "5610930829e58862955ec7ba26e17d96ca5cb253", + "support" + ], + "webgpu/suites/cts/validation/validation_test.js": [ + "35ad5d895521f1207ab21be1de5af3a0d672cc4f", + "support" + ], + "webgpu/suites/cts/validation/vertex_input.spec.js": [ + "432a04a4ceef0e895e0bc881bf6d4f2ec7f91034", "support" ], "webmessaging/Channel_postMessage_Blob.htm": [ @@ -718518,8 +720133,12 @@ "107cc9b544e3a395c14655d0f4356485f05d7bf5", "testharness" ], - "webxr/events_referenceSpace_reset.https.html": [ - "3a931168fd328b9fb62f5ecd65958f4365b7aa03", + "webxr/events_referenceSpace_reset_immersive.https.html": [ + "2da3788a39a20db3396d542f7fb0dc5d486c2aa3", + "testharness" + ], + "webxr/events_referenceSpace_reset_inline.https.html": [ + "b3abcc817bdf3e53c22284a14d03e31e1184e1a3", "testharness" ], "webxr/events_session_select.https.html": [ diff --git a/tests/wpt/metadata/css/CSS2/linebox/inline-negative-margin-001.html.ini b/tests/wpt/metadata/css/CSS2/linebox/inline-negative-margin-001.html.ini index 35f64aeb424..94a3570d26b 100644 --- a/tests/wpt/metadata/css/CSS2/linebox/inline-negative-margin-001.html.ini +++ b/tests/wpt/metadata/css/CSS2/linebox/inline-negative-margin-001.html.ini @@ -2,12 +2,12 @@ [#container 1] expected: FAIL - [[data-expected-height\] 1] + [[data-expected-height\] 7] expected: FAIL - [[data-expected-height\] 2] + [[data-expected-height\] 3] expected: FAIL - [[data-expected-height\] 7] + [[data-expected-height\] 4] expected: FAIL diff --git a/tests/wpt/metadata/css/css-text/white-space/eol-spaces-bidi-001.html.ini b/tests/wpt/metadata/css/css-text/white-space/eol-spaces-bidi-001.html.ini new file mode 100644 index 00000000000..eafc8f6012c --- /dev/null +++ b/tests/wpt/metadata/css/css-text/white-space/eol-spaces-bidi-001.html.ini @@ -0,0 +1,2 @@ +[eol-spaces-bidi-001.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini b/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini index e953c8679d0..668c3f52a5b 100644 --- a/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini +++ b/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini @@ -2,3 +2,15 @@ [<li>Outside 1</li>] expected: FAIL + [<li>Image Outside 2</li>] + expected: FAIL + + [<li>Outside 2</li>] + expected: FAIL + + [<li>Image Outside 1</li>] + expected: FAIL + + [<li>Outside 3</li>] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom-view/matchMedia-display-none-iframe.html.ini b/tests/wpt/metadata/css/cssom-view/matchMedia-display-none-iframe.html.ini new file mode 100644 index 00000000000..e6e1f29e274 --- /dev/null +++ b/tests/wpt/metadata/css/cssom-view/matchMedia-display-none-iframe.html.ini @@ -0,0 +1,2 @@ +[matchMedia-display-none-iframe.html] + expected: ERROR diff --git a/tests/wpt/metadata/css/cssom-view/matchMediaAddListener-handleEvent.html.ini b/tests/wpt/metadata/css/cssom-view/matchMediaAddListener-handleEvent.html.ini index 176c9ea4568..e797a8fe6de 100644 --- a/tests/wpt/metadata/css/cssom-view/matchMediaAddListener-handleEvent.html.ini +++ b/tests/wpt/metadata/css/cssom-view/matchMediaAddListener-handleEvent.html.ini @@ -8,3 +8,6 @@ [throws if handleEvent is thruthy and not callable] expected: FAIL + [doesn't look up handleEvent method on callable event listeners] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini index fa33468f5ab..fa48a708082 100644 --- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini @@ -324,9 +324,9 @@ [<iframe>: combined response Content-Type: text/html;" text/plain] expected: FAIL - [<iframe>: separate response Content-Type: text/html;x=" text/plain] + [<iframe>: combined response Content-Type: text/html;" \\" text/plain] expected: FAIL - [<iframe>: combined response Content-Type: text/html;" \\" text/plain] + [<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html] expected: FAIL diff --git a/tests/wpt/metadata/fetch/content-type/script.window.js.ini b/tests/wpt/metadata/fetch/content-type/script.window.js.ini index 5c001592859..279734168dc 100644 --- a/tests/wpt/metadata/fetch/content-type/script.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/script.window.js.ini @@ -56,6 +56,6 @@ [separate text/javascript x/x] expected: FAIL - [separate text/javascript;charset=windows-1252 error text/javascript] + [separate text/javascript;charset=windows-1252 text/javascript] expected: FAIL diff --git a/tests/wpt/metadata/fetch/metadata/embed.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/embed.tentative.https.sub.html.ini index 19a76dbb7de..6ee87068bbb 100644 --- a/tests/wpt/metadata/fetch/metadata/embed.tentative.https.sub.html.ini +++ b/tests/wpt/metadata/fetch/metadata/embed.tentative.https.sub.html.ini @@ -9,3 +9,21 @@ [Same-Origin embed] expected: TIMEOUT + [Wrapper: Navigate to cross-site embed] + expected: NOTRUN + + [Wrapper: cross-site embed] + expected: NOTRUN + + [Wrapper: same-site embed] + expected: NOTRUN + + [Wrapper: Navigate to same-origin embed] + expected: NOTRUN + + [Wrapper: Navigate to same-site embed] + expected: NOTRUN + + [Wrapper: same-origin embed] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html.ini new file mode 100644 index 00000000000..6fb669844e1 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[appcache.tentative.https.sub.html] + [Appcache!] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html.ini new file mode 100644 index 00000000000..19a76dbb7de --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html.ini @@ -0,0 +1,11 @@ +[embed.tentative.https.sub.html] + expected: TIMEOUT + [Cross-Site embed] + expected: NOTRUN + + [Same-Site embed] + expected: NOTRUN + + [Same-Origin embed] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html.ini new file mode 100644 index 00000000000..a8276159e46 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html.ini @@ -0,0 +1,7 @@ +[fetch-preflight.tentative.https.sub.html] + [Same-site fetch with preflight] + expected: FAIL + + [Cross-site fetch with preflight] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html.ini new file mode 100644 index 00000000000..0fcd2339104 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[fetch-via-serviceworker--fallback.tentative.https.sub.html] + [Sec-Fetch headers after SW fallback] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html.ini new file mode 100644 index 00000000000..ad0e96bd334 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[fetch-via-serviceworker--respondWith.tentative.https.sub.html] + [Sec-Fetch headers after SW fallback] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html.ini new file mode 100644 index 00000000000..3940ed7f391 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html.ini @@ -0,0 +1,19 @@ +[fetch.tentative.https.sub.html] + [Same-origin fetch] + expected: FAIL + + [Same-origin mode] + expected: FAIL + + [Cross-site fetch] + expected: FAIL + + [Same-site fetch] + expected: FAIL + + [no-CORS mode] + expected: FAIL + + [CORS mode] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html.ini new file mode 100644 index 00000000000..9383237b8b0 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html.ini @@ -0,0 +1,4 @@ +[fetch.tentative.sub.html] + [http->https fetch (cross-scheme => cross-site)] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html.ini new file mode 100644 index 00000000000..39b898e8564 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[font.tentative.https.sub.html] + [font] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html.ini new file mode 100644 index 00000000000..e668969d548 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html.ini @@ -0,0 +1,14 @@ +[frame.tentative.sub.html] + expected: TIMEOUT + [Secure, cross-site (cross-scheme, same-host) frame] + expected: TIMEOUT + + [Non-secure cross-site iframe => No headers.] + expected: TIMEOUT + + [Non-secure same-site iframe => No headers] + expected: TIMEOUT + + [Non-secure same-origin iframe => No headers] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html.ini new file mode 100644 index 00000000000..42c34b2dad5 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[history.tentative.https.sub.html] + [back to same-origin-initiated navigation] + expected: FAIL + + [back to same-site-initiated navigation] + expected: FAIL + + [back to cross-site-initiated navigation] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html.ini new file mode 100644 index 00000000000..fe45c4e6471 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html.ini @@ -0,0 +1,4 @@ +[iframe.tentative.sub.html] + [Secure, cross-site (cross-scheme, same-host) iframe] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html.ini new file mode 100644 index 00000000000..747ee23fa57 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[img.tentative.https.sub.html] + [Cross-site image] + expected: FAIL + + [Same-origin image] + expected: FAIL + + [Same-site image] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/navigation.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/navigation.https.sub.html.ini new file mode 100644 index 00000000000..a53ed577de8 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/navigation.https.sub.html.ini @@ -0,0 +1,2 @@ +[navigation.https.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html.ini new file mode 100644 index 00000000000..8e3bee8e2d6 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html.ini @@ -0,0 +1,11 @@ +[object.tentative.https.sub.html] + expected: TIMEOUT + [Same-Origin object] + expected: TIMEOUT + + [Cross-Site object] + expected: NOTRUN + + [Same-Site object] + expected: NOTRUN + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html.ini new file mode 100644 index 00000000000..ace4812ca1b --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html.ini @@ -0,0 +1,14 @@ +[prefetch.tentative.https.sub.html] + expected: TIMEOUT + [<link rel='prefetch' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='prefetch' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='prefetch' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [Browser supports prefetch.] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html.ini new file mode 100644 index 00000000000..326d86df3ef --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html.ini @@ -0,0 +1,59 @@ +[preload.tentative.https.sub.html] + expected: TIMEOUT + [<link rel='preload' as='fetch' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='script' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='font' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='script' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='track' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='image' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='image' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='track' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [Browser supports preload.] + expected: FAIL + + [<link rel='preload' as='fetch' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='style' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='font' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='fetch' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='image' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='font' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='style' href='https://www.not-web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='script' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='track' href='https://www.web-platform.test:8443/...'>] + expected: TIMEOUT + + [<link rel='preload' as='style' href='https://web-platform.test:8443/...'>] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html.ini new file mode 100644 index 00000000000..ff5d3abc74b --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[cross-site-redirect.tentative.https.sub.html] + [Cross-Site -> Cross-Site redirect] + expected: FAIL + + [Cross-Site -> Same-Site redirect] + expected: FAIL + + [Cross-Site -> Same-Origin redirect] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html.ini new file mode 100644 index 00000000000..ea5a2ec1a12 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[multiple-redirect-cross-site.tentative.https.sub.html] + [Same-Origin -> Cross-Site -> Same-Origin redirect] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html.ini new file mode 100644 index 00000000000..70f7e987b5c --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html.ini @@ -0,0 +1,4 @@ +[multiple-redirect-https-downgrade-upgrade.tentative.sub.html] + [multiple-redirect-https-downgrade-upgrade] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html.ini new file mode 100644 index 00000000000..cb4a0801f78 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[multiple-redirect-same-site.tentative.https.sub.html] + [Same-Origin -> Same-Site -> Same-Origin redirect] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html.ini new file mode 100644 index 00000000000..90c6012f913 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html.ini @@ -0,0 +1,4 @@ +[redirect-http-upgrade.tentative.sub.html] + [redirect-http-upgrade] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html.ini new file mode 100644 index 00000000000..6b117e1204f --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html.ini @@ -0,0 +1,4 @@ +[redirect-https-downgrade.tentative.sub.html] + [redirect-https-downgrade] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html.ini new file mode 100644 index 00000000000..0ec11a20c11 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[same-origin-redirect.tentative.https.sub.html] + [Same-Origin -> Cross-Site redirect] + expected: FAIL + + [Same-Origin -> Same-Site redirect] + expected: FAIL + + [Same-Origin -> Same-Origin redirect] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html.ini new file mode 100644 index 00000000000..72a5cbe072e --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[same-site-redirect.tentative.https.sub.html] + [Same-Site -> Same-Origin redirect] + expected: FAIL + + [Same-Site -> Same-Site redirect] + expected: FAIL + + [Same-Site -> Cross-Site redirect] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.ini new file mode 100644 index 00000000000..6673e91722b --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.ini @@ -0,0 +1,2 @@ +[report.tentative.https.sub.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html.ini new file mode 100644 index 00000000000..08e38d7f7f3 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html.ini @@ -0,0 +1,13 @@ +[script.tentative.https.sub.html] + [Same-origin script] + expected: FAIL + + [Cross-site script] + expected: FAIL + + [Same-origin CORS script] + expected: FAIL + + [Same-site script] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html.ini new file mode 100644 index 00000000000..a1f13c53676 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[serviceworker.tentative.https.sub.html] + [metadata for service worker scripts] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html.ini new file mode 100644 index 00000000000..9aa11216376 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[sharedworker.tentative.https.sub.html] + [sharedworker] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html.ini new file mode 100644 index 00000000000..92fe2faad02 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html.ini @@ -0,0 +1,13 @@ +[style.tentative.https.sub.html] + [Same-Origin, cors style] + expected: FAIL + + [Cross-Site style] + expected: FAIL + + [Same-Site style] + expected: FAIL + + [Same-Origin style] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html.ini new file mode 100644 index 00000000000..7fa0efeb57c --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html.ini @@ -0,0 +1,14 @@ +[track.tentative.https.sub.html] + expected: TIMEOUT + [Same-Site track] + expected: NOTRUN + + [Same-Origin track] + expected: TIMEOUT + + [Same-Origin, CORS track] + expected: NOTRUN + + [Cross-Site track] + expected: NOTRUN + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html.ini new file mode 100644 index 00000000000..21cbeae87cc --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[trailing-dot.tentative.https.sub.html] + [Fetching a resource from a cross-site host, spelled with a trailing dot.] + expected: FAIL + + [Fetching a resource from the same origin, but spelled with a trailing dot.] + expected: FAIL + + [Fetching a resource from the same site, but spelled with a trailing dot.] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html.ini new file mode 100644 index 00000000000..73e93bdf2e1 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html.ini @@ -0,0 +1,4 @@ +[worker.tentative.https.sub.html] + [Same-Origin worker] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html.ini b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html.ini new file mode 100644 index 00000000000..c07bd4dac16 --- /dev/null +++ b/tests/wpt/metadata/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html.ini @@ -0,0 +1,10 @@ +[xslt.tentative.https.sub.html] + [Same-Origin xslt] + expected: FAIL + + [Cross-site xslt] + expected: FAIL + + [Same-site xslt] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini index 87c807a49ff..b7052af5b5c 100644 --- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,3 +11,6 @@ [X-Content-Type-Options%3A%20nosniff%0C] expected: FAIL + [X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini deleted file mode 100644 index 87b07c3e670..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_1.html] - [Multiple history traversals from the same task] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini deleted file mode 100644 index 75d75b4cda2..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_2.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini deleted file mode 100644 index 385376c7321..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_4.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini deleted file mode 100644 index dc2e45516de..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_5.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html.ini new file mode 100644 index 00000000000..986671d6ab3 --- /dev/null +++ b/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html.ini @@ -0,0 +1,4 @@ +[cross-global-npo.html] + [Named access across globals] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html.ini new file mode 100644 index 00000000000..62535b8ec74 --- /dev/null +++ b/tests/wpt/metadata/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html.ini @@ -0,0 +1,10 @@ +[prototype.html] + [Property on EventTarget.prototype.] + expected: FAIL + + [Property on window.] + expected: FAIL + + [Property on Window.prototype.] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini index 2532dceabac..442db3cb549 100644 --- a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini @@ -1,5 +1,4 @@ [embedded-opener-remove-frame.html] - expected: CRASH [opener and "removed" embedded documents] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini new file mode 100644 index 00000000000..8cc42056d34 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini @@ -0,0 +1,10 @@ +[non-active-document.html] + [DOMParser] + expected: FAIL + + [createHTMLDocument] + expected: FAIL + + [<template>] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-2.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-2.html.ini new file mode 100644 index 00000000000..f6eecd82b49 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-2.html.ini @@ -0,0 +1,5 @@ +[form-double-submit-2.html] + expected: ERROR + [preventDefault should allow onclick submit() to succeed] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini new file mode 100644 index 00000000000..941d0dee0c8 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini @@ -0,0 +1,5 @@ +[form-double-submit-3.html] + expected: ERROR + [<button> should have the same double-submit protection as <input type=submit>] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini new file mode 100644 index 00000000000..47a7bbb7975 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini @@ -0,0 +1,5 @@ +[form-double-submit.html] + expected: ERROR + [default submit action should supersede onclick submit()] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js.ini b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js.ini new file mode 100644 index 00000000000..ce482a60da8 --- /dev/null +++ b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js.ini @@ -0,0 +1,7 @@ +[aborted-parser.window.html] + [document.open() after parser is aborted] + expected: FAIL + + [async document.open() after parser is aborted] + expected: FAIL + diff --git a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html.ini b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html.ini new file mode 100644 index 00000000000..7ab69a8c1f1 --- /dev/null +++ b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html.ini @@ -0,0 +1,5 @@ +[location-set-and-document-open.html] + expected: TIMEOUT + [Location sets should cancel current navigation and prevent later document.open() from doing anything] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html.ini b/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html.ini index 4f6125d0275..9ad0a4d4f85 100644 --- a/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html.ini +++ b/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html.ini @@ -1,5 +1,5 @@ [disallow-crossorigin.html] type: testharness - expected: ERROR [Promise rejection event should be muted for cross-origin non-CORS script] expected: FAIL + diff --git a/tests/wpt/metadata/webxr/events_referenceSpace_reset.https.html.ini b/tests/wpt/metadata/webxr/events_referenceSpace_reset.https.html.ini deleted file mode 100644 index 5d6851c9d84..00000000000 --- a/tests/wpt/metadata/webxr/events_referenceSpace_reset.https.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[events_referenceSpace_reset.https.html] - [XRSession resetpose from a device properly fires off the right events for non-immersive sessions] - expected: FAIL - - [XRSession resetpose from a device properly fires off the right events for immersive sessions] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/events_referenceSpace_reset_immersive.https.html.ini b/tests/wpt/metadata/webxr/events_referenceSpace_reset_immersive.https.html.ini new file mode 100644 index 00000000000..1433a6309d5 --- /dev/null +++ b/tests/wpt/metadata/webxr/events_referenceSpace_reset_immersive.https.html.ini @@ -0,0 +1,4 @@ +[events_referenceSpace_reset_immersive.https.html] + [XRSession resetpose from a device properly fires off the right events for immersive sessions] + expected: FAIL + diff --git a/tests/wpt/metadata/webxr/events_referenceSpace_reset_inline.https.html.ini b/tests/wpt/metadata/webxr/events_referenceSpace_reset_inline.https.html.ini new file mode 100644 index 00000000000..94f78bccd2b --- /dev/null +++ b/tests/wpt/metadata/webxr/events_referenceSpace_reset_inline.https.html.ini @@ -0,0 +1,4 @@ +[events_referenceSpace_reset_inline.https.html] + [XRSession resetpose from a device properly fires off the right events for non-immersive sessions] + expected: FAIL + diff --git a/tests/wpt/metadata/workers/constructors/Worker/Worker-constructor.html.ini b/tests/wpt/metadata/workers/constructors/Worker/Worker-constructor.html.ini deleted file mode 100644 index 80f9a4f15b8..00000000000 --- a/tests/wpt/metadata/workers/constructors/Worker/Worker-constructor.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[Worker-constructor.html] - expected: ERROR diff --git a/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini b/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini deleted file mode 100644 index dbea4f293ad..00000000000 --- a/tests/wpt/mozilla/meta/css/transition_calc_implicit.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transition_calc_implicit.html] - expected: TIMEOUT diff --git a/tests/wpt/web-platform-tests/.azure-pipelines.yml b/tests/wpt/web-platform-tests/.azure-pipelines.yml index 78f36842789..ff466be6677 100644 --- a/tests/wpt/web-platform-tests/.azure-pipelines.yml +++ b/tests/wpt/web-platform-tests/.azure-pipelines.yml @@ -28,7 +28,7 @@ jobs: displayName: 'affected tests: Safari Technology Preview' condition: eq(variables['Build.Reason'], 'PullRequest') pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/affected_tests.yml parameters: @@ -42,7 +42,7 @@ jobs: displayName: 'affected tests without changes: Safari Technology Preview' condition: eq(variables['Build.Reason'], 'PullRequest') pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/affected_tests.yml parameters: @@ -76,7 +76,7 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_infrastructure'] pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml @@ -106,7 +106,7 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.tools_unittest'] pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml @@ -119,7 +119,7 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_unittest'] pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml @@ -131,7 +131,7 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wpt_integration'] pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: # full checkout required - template: tools/ci/azure/install_chrome.yml @@ -353,7 +353,7 @@ jobs: parallel: 5 # chosen to make runtime ~2h timeoutInMinutes: 360 pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' steps: - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml diff --git a/tests/wpt/web-platform-tests/.taskcluster.yml b/tests/wpt/web-platform-tests/.taskcluster.yml index a267540cafb..27479fb57e0 100644 --- a/tests/wpt/web-platform-tests/.taskcluster.yml +++ b/tests/wpt/web-platform-tests/.taskcluster.yml @@ -25,31 +25,27 @@ tasks: } each(browser): $map: - - [testharness, 1, 15] - - [testharness, 2, 15] - - [testharness, 3, 15] - - [testharness, 4, 15] - - [testharness, 5, 15] - - [testharness, 6, 15] - - [testharness, 7, 15] - - [testharness, 8, 15] - - [testharness, 9, 15] - - [testharness, 10, 15] - - [testharness, 11, 15] - - [testharness, 12, 15] - - [testharness, 13, 15] - - [testharness, 14, 15] - - [testharness, 15, 15] - - [reftest, 1, 10] - - [reftest, 2, 10] - - [reftest, 3, 10] - - [reftest, 4, 10] - - [reftest, 5, 10] - - [reftest, 6, 10] - - [reftest, 7, 10] - - [reftest, 8, 10] - - [reftest, 9, 10] - - [reftest, 10, 10] + - [testharness, 1, 16] + - [testharness, 2, 16] + - [testharness, 3, 16] + - [testharness, 4, 16] + - [testharness, 5, 16] + - [testharness, 6, 16] + - [testharness, 7, 16] + - [testharness, 8, 16] + - [testharness, 9, 16] + - [testharness, 10, 16] + - [testharness, 11, 16] + - [testharness, 12, 16] + - [testharness, 13, 16] + - [testharness, 14, 16] + - [testharness, 15, 16] + - [testharness, 16, 16] + - [reftest, 1, 5] + - [reftest, 2, 5] + - [reftest, 3, 5] + - [reftest, 4, 5] + - [reftest, 5, 5] - [wdspec, 1, 1] each(chunk): taskId: {$eval: 'as_slugid(browser.name + browser.channel + chunk[0] + str(chunk[1]))'} diff --git a/tests/wpt/web-platform-tests/IndexedDB/blob-contenttype.any.js b/tests/wpt/web-platform-tests/IndexedDB/blob-contenttype.any.js new file mode 100644 index 00000000000..0b2debae7b1 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/blob-contenttype.any.js @@ -0,0 +1,39 @@ +// META: title=Blob Content Type +// META: script=support.js +// META: timeout=long + +indexeddb_test( + function upgrade(t, db) { + db.createObjectStore('store'); + }, + function success(t, db) { + var type = 'x-files/trust-no-one'; + + var blob = new Blob(['mulder', 'scully'], {type: type}); + assert_equals(blob.type, type, 'Blob type should match constructor option'); + + var tx = db.transaction('store', 'readwrite'); + tx.objectStore('store').put(blob, 'key'); + + tx.oncomplete = t.step_func(function() { + var tx = db.transaction('store'); + tx.objectStore('store').get('key').onsuccess = t.step_func(function(e) { + var result = e.target.result; + assert_equals(result.type, type, 'Blob type should survive round-trip'); + + var url = URL.createObjectURL(result); + var xhr = new XMLHttpRequest(), async = true; + xhr.open('GET', url, async); + xhr.send(); + xhr.onreadystatechange = t.step_func(function() { + if (xhr.readyState !== XMLHttpRequest.DONE) + return; + assert_equals(xhr.getResponseHeader('Content-Type'), type, + 'Blob type should be preserved when fetched'); + t.done(); + }); + }); + }); + }, + 'Ensure that content type round trips when reading blob data' +); diff --git a/tests/wpt/web-platform-tests/IndexedDB/blob-delete-objectstore-db.any.js b/tests/wpt/web-platform-tests/IndexedDB/blob-delete-objectstore-db.any.js new file mode 100644 index 00000000000..61d7bad914e --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/blob-delete-objectstore-db.any.js @@ -0,0 +1,47 @@ +// META: title=Blob Delete Object Store +// META: script=support.js + +let key = "blob key"; + +indexeddb_test( + function upgrade(t, db) { + const store0 = db.createObjectStore('store0'); + const store1 = db.createObjectStore('store1'); + + const blobAContent = "First blob content"; + const blobA = new Blob([blobAContent], {"type" : "text/plain"}); + + store0.put(blobA, key); + }, + function success(t, db) { + db.close(); + const request = indexedDB.open(db.name, 2); + + request.onupgradeneeded = t.step_func(function(e) { + const db = e.target.result; + db.deleteObjectStore('store0'); + + request.onsuccess = t.step_func(function() { + const blobBContent = "Second blob content"; + const trans = db.transaction('store1', 'readwrite'); + const store1 = trans.objectStore('store1'); + const blobB = new Blob([blobBContent], {"type" : "text/plain"}); + store1.put(blobB, key); + + trans.oncomplete = t.step_func(function() { + db.close(); + const delete_request = indexedDB.deleteDatabase(db.name); + + // The test passes if it successfully completes. + delete_request.onsuccess = t.step_func_done(); + + delete_request.onerror = t.unreached_func("Request should not fail."); + }); + + trans.onabort = t.unreached_func("Transaction should not be aborted."); + }); + }); + request.onsuccess = t.unreached_func("Request should not succeed without an upgrade."); + request.onerror = t.unreached_func("Request should not fail."); + request.onblocked = t.unreached_func("Request should not be blocked."); + }, "Deleting an object store and a database containing blobs doesn't crash."); diff --git a/tests/wpt/web-platform-tests/IndexedDB/blob-valid-after-deletion.any.js b/tests/wpt/web-platform-tests/IndexedDB/blob-valid-after-deletion.any.js new file mode 100644 index 00000000000..7c7825cb421 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/blob-valid-after-deletion.any.js @@ -0,0 +1,53 @@ +// META: title=Blob Valid After Deletion +// META: script=support.js + +let key = "key"; + +indexeddb_test( + function upgrade(t, db) { + db.createObjectStore('store'); + }, + function success(t, db) { + const blobAContent = "Blob A content"; + const blobBContent = "Blob B content"; + const blobA = new Blob([blobAContent], {"type" : "text/plain"}); + const blobB = new Blob([blobBContent], {"type" : "text/plain"}); + value = { a0: blobA, a1: blobA, b0: blobB }; + + const tx = db.transaction('store', 'readwrite'); + var store = tx.objectStore('store'); + + store.put(value, key); + value = null; + + const trans = db.transaction('store'); + store = trans.objectStore('store'); + const request = store.get(key); + + request.onsuccess = t.step_func(function() { + const record = request.result; + + trans.oncomplete = t.step_func(function() { + const trans = db.transaction('store', 'readwrite'); + store = trans.objectStore('store'); + const request = store.delete(key); + + trans.oncomplete = t.step_func(function() { + const promise1 = record.a0.text().then(t.step_func(text => { assert_equals(text, blobAContent); }, + t.unreached_func())); + + const promise2 = record.a1.text().then(t.step_func(text => { assert_equals(text, blobAContent); }, + t.unreached_func())); + + const promise3 = record.b0.text().then(t.step_func(text => { assert_equals(text, blobBContent); }, + t.unreached_func())); + + Promise.all([promise1, promise2, promise3]).then(function() { + // The test passes if it successfully completes. + t.done(); + }); + }); + }); + }); + }, + "Blobs stay alive after their records are deleted.");
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/IndexedDB/blob-valid-before-commit.any.js b/tests/wpt/web-platform-tests/IndexedDB/blob-valid-before-commit.any.js new file mode 100644 index 00000000000..0803c9ea69c --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/blob-valid-before-commit.any.js @@ -0,0 +1,41 @@ +// META: title=Blob Valid Before Commit +// META: script=support.js + +let key = "key"; + +indexeddb_test( + function upgrade(t, db) { + db.createObjectStore('store'); + }, + function success(t, db) { + const blobAContent = "Blob A content"; + const blobBContent = "Blob B content"; + const blobA = new Blob([blobAContent], {"type" : "text/plain"}); + const blobB = new Blob([blobBContent], {"type" : "text/plain"}); + const value = { a0: blobA, a1: blobA, b0: blobB }; + + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + + store.put(value, key); + const request = store.get(key); + + request.onsuccess = t.step_func(function() { + const record = request.result; + + const promise1 = record.a0.text().then(t.step_func(text => { assert_equals(text, blobAContent); }, + t.unreached_func())); + + const promise2 = record.a1.text().then(t.step_func(text => { assert_equals(text, blobAContent); }, + t.unreached_func())); + + const promise3 = record.b0.text().then(t.step_func(text => { assert_equals(text, blobBContent); }, + t.unreached_func())); + + Promise.all([promise1, promise2, promise3]).then(function() { + // The test passes if it successfully completes. + t.done(); + }); + }); + }, + "Blobs can be read back before their records are committed.");
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/IndexedDB/idb-explicit-commit.any.js b/tests/wpt/web-platform-tests/IndexedDB/idb-explicit-commit.any.js index 12e56cc267a..2acd904ea6a 100644 --- a/tests/wpt/web-platform-tests/IndexedDB/idb-explicit-commit.any.js +++ b/tests/wpt/web-platform-tests/IndexedDB/idb-explicit-commit.any.js @@ -288,5 +288,5 @@ promise_test(async testCase => { assert_equals(getRequest1.result.title, 'title1'); assert_equals(getRequest2.result.title, 'title2'); db.close(); -}, 'Transactions that handle all errors properly should be behave as ' + +}, 'Transactions that handle all errors properly should behave as ' + 'expected when an explicit commit is called in an onerror handler.'); diff --git a/tests/wpt/web-platform-tests/IndexedDB/structured-clone.any.js b/tests/wpt/web-platform-tests/IndexedDB/structured-clone.any.js index 8078aaf796b..e03ba7aeee4 100644 --- a/tests/wpt/web-platform-tests/IndexedDB/structured-clone.any.js +++ b/tests/wpt/web-platform-tests/IndexedDB/structured-clone.any.js @@ -288,8 +288,6 @@ cloneObjectTest( assert_equals(orig.type, clone.type); assert_equals(orig.name, clone.name); assert_equals(orig.lastModified, clone.lastModified); - assert_equals(String(orig.lastModifiedDate), - String(clone.lastModifiedDate)); assert_equals(await orig.text(), await clone.text()); }); diff --git a/tests/wpt/web-platform-tests/compression/compression-bad-chunks.any.js b/tests/wpt/web-platform-tests/compression/compression-bad-chunks.any.js new file mode 100644 index 00000000000..06e3be9c0fe --- /dev/null +++ b/tests/wpt/web-platform-tests/compression/compression-bad-chunks.any.js @@ -0,0 +1,62 @@ +// META: global=worker + +'use strict'; + +const badChunks = [ + { + name: 'undefined', + value: undefined + }, + { + name: 'null', + value: null + }, + { + name: 'numeric', + value: 3.14 + }, + { + name: 'object, not BufferSource', + value: {} + }, + { + name: 'array', + value: [65] + }, + { + name: 'SharedArrayBuffer', + // Use a getter to postpone construction so that all tests don't fail where + // SharedArrayBuffer is not yet implemented. + get value() { + return new SharedArrayBuffer(); + } + }, + { + name: 'shared Uint8Array', + get value() { + return new Uint8Array(new SharedArrayBuffer()) + } + }, +]; + +for (const chunk of badChunks) { + promise_test(async t => { + const cs = new CompressionStream('gzip'); + const reader = cs.readable.getReader(); + const writer = cs.writable.getWriter(); + const writePromise = writer.write(chunk.value); + const readPromise = reader.read(); + await promise_rejects(t, new TypeError(), writePromise, 'write should reject'); + await promise_rejects(t, new TypeError(), readPromise, 'read should reject'); + }, `chunk of type ${chunk.name} should error the stream for gzip`); + + promise_test(async t => { + const cs = new CompressionStream('deflate'); + const reader = cs.readable.getReader(); + const writer = cs.writable.getWriter(); + const writePromise = writer.write(chunk.value); + const readPromise = reader.read(); + await promise_rejects(t, new TypeError(), writePromise, 'write should reject'); + await promise_rejects(t, new TypeError(), readPromise, 'read should reject'); + }, `chunk of type ${chunk.name} should error the stream for deflate`); +} diff --git a/tests/wpt/web-platform-tests/compression/compression-including-empty-chunk.any.js b/tests/wpt/web-platform-tests/compression/compression-including-empty-chunk.any.js new file mode 100644 index 00000000000..eff92885790 --- /dev/null +++ b/tests/wpt/web-platform-tests/compression/compression-including-empty-chunk.any.js @@ -0,0 +1,57 @@ +// META: global=worker +// META: script=pako/pako_inflate.min.js +// META: timeout=long + +'use strict'; + +// This test asserts that compressing '' doesn't affect the compressed data. +// Example: compressing ['Hello', '', 'Hello'] results in 'HelloHello' + +async function compressChunkList(chunkList, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + for (const chunk of chunkList) { + const chunkByte = new TextEncoder().encode(chunk); + writer.write(chunkByte); + } + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +const chunkLists = [ + ['', 'Hello', 'Hello'], + ['Hello', '', 'Hello'], + ['Hello', 'Hello', ''] +]; +const expectedValue = new TextEncoder().encode('HelloHello'); + +for (const chunkList of chunkLists) { + promise_test(async t => { + const compressedData = await compressChunkList(chunkList, 'deflate'); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `the result of compressing [${chunkList}] with deflate should be 'HelloHello'`); + + promise_test(async t => { + const compressedData = await compressChunkList(chunkList, 'gzip'); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `the result of compressing [${chunkList}] with gzip should be 'HelloHello'`); +} diff --git a/tests/wpt/web-platform-tests/compression/compression-multiple-chunks.any.js b/tests/wpt/web-platform-tests/compression/compression-multiple-chunks.any.js new file mode 100644 index 00000000000..ca49b9cf427 --- /dev/null +++ b/tests/wpt/web-platform-tests/compression/compression-multiple-chunks.any.js @@ -0,0 +1,60 @@ +// META: global=worker +// META: script=pako/pako_inflate.min.js +// META: timeout=long + +'use strict'; + +// This test asserts that compressing multiple chunks should work. + +// Example: ('Hello', 3) => TextEncoder().encode('HelloHelloHello') +function makeExpectedChunk(input, numberOfChunks) { + const expectedChunk = input.repeat(numberOfChunks); + return new TextEncoder().encode(expectedChunk); +} + +// Example: ('Hello', 3, 'deflate') => compress ['Hello', 'Hello', Hello'] +async function compressMultipleChunks(input, numberOfChunks, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + const chunk = new TextEncoder().encode(input); + for (let i = 0; i < numberOfChunks; ++i) { + writer.write(chunk); + } + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +const hello = 'Hello'; + +for (let numberOfChunks = 2; numberOfChunks <= 16; ++numberOfChunks) { + promise_test(async t => { + const compressedData = await compressMultipleChunks(hello, numberOfChunks, 'deflate'); + const expectedValue = makeExpectedChunk(hello, numberOfChunks); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `compressing ${numberOfChunks} chunks with deflate should work`); + + promise_test(async t => { + const compressedData = await compressMultipleChunks(hello, numberOfChunks, 'gzip'); + const expectedValue = makeExpectedChunk(hello, numberOfChunks); + // decompress with pako, and check that we got the same result as our original string + assert_array_equals(expectedValue, pako.inflate(compressedData), 'value should match'); + }, `compressing ${numberOfChunks} chunks with gzip should work`); +} diff --git a/tests/wpt/web-platform-tests/compression/compression-output-length.any.js b/tests/wpt/web-platform-tests/compression/compression-output-length.any.js new file mode 100644 index 00000000000..d7dafcd1009 --- /dev/null +++ b/tests/wpt/web-platform-tests/compression/compression-output-length.any.js @@ -0,0 +1,54 @@ +// META: global=worker + +'use strict'; + +// This test asserts that compressed data length is shorter than the original +// data length. If the input is extremely small, the compressed data may be +// larger than the original data. + +const LARGE_FILE = '/media/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm'; + +async function compressArrayBuffer(input, format) { + const cs = new CompressionStream(format); + const writer = cs.writable.getWriter(); + writer.write(input); + const closePromise = writer.close(); + const out = []; + const reader = cs.readable.getReader(); + let totalSize = 0; + while (true) { + const { value, done } = await reader.read(); + if (done) + break; + out.push(value); + totalSize += value.byteLength; + } + await closePromise; + const concatenated = new Uint8Array(totalSize); + let offset = 0; + for (const array of out) { + concatenated.set(array, offset); + offset += array.byteLength; + } + return concatenated; +} + +promise_test(async () => { + const response = await fetch(LARGE_FILE); + const buffer = await response.arrayBuffer(); + const bufferView = new Uint8Array(buffer); + const originalLength = bufferView.length; + const compressedData = await compressArrayBuffer(bufferView, 'deflate'); + const compressedLength = compressedData.length; + assert_less_than(compressedLength, originalLength, 'output should be smaller'); +}, 'the length of deflated data should be shorter than that of the original data'); + +promise_test(async () => { + const response = await fetch(LARGE_FILE); + const buffer = await response.arrayBuffer(); + const bufferView = new Uint8Array(buffer); + const originalLength = bufferView.length; + const compressedData = await compressArrayBuffer(bufferView, 'gzip'); + const compressedLength = compressedData.length; + assert_less_than(compressedLength, originalLength, 'output should be smaller'); +}, 'the length of gzipped data should be shorter than that of the original data'); diff --git a/tests/wpt/web-platform-tests/css/css-contain/contain-size-scrollbars-004.html b/tests/wpt/web-platform-tests/css/css-contain/contain-size-scrollbars-004.html new file mode 100644 index 00000000000..6a45fdd23f4 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-contain/contain-size-scrollbars-004.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Containment Test: Size containment scrollbars</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size"> +<link rel="match" href="reference/contain-size-scrollbars-004-ref.html"> +<meta name=assert content="This test checks that contain:size element's content and padding are considered for scrollbars."> +<style> +#scroller { + contain: size; + background: lightgreen; + overflow: scroll; + padding-bottom: 50px; + width: 100px; + height: 100px; +} +#content { + background: lightblue; + width: 50px; + height: 130px; +} +</style> + +<div id=scroller> + <div id=content> + </div> +</div> + +<p>This test passes if it has the same output as the reference.</p> diff --git a/tests/wpt/web-platform-tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html b/tests/wpt/web-platform-tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html new file mode 100644 index 00000000000..91d9e517094 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-contain/reference/contain-size-scrollbars-004-ref.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Containment Test: Reference file</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<style> +#scroller { + background: lightgreen; + overflow: scroll; + padding-bottom: 50px; + width: 100px; + height: 100px; +} +#content { + background: lightblue; + width: 50px; + height: 130px; +} +</style> + +<div id=scroller> + <div id=content> + </div> +</div> + +<p>This test passes if it has the same output as the reference.</p> diff --git a/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian-ref.html b/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian-ref.html index f21dfff6960..de55b7381ac 100644 --- a/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian-ref.html +++ b/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian-ref.html @@ -7,4 +7,4 @@ padding: 0; } </style> -<p>Ա. Filler Text +<p>Ա. Filler Text<span style="display: inline-block; width: 1px; height: 50px;"></span> diff --git a/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian.html b/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian.html index fd0df631149..58f570cd119 100644 --- a/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian.html +++ b/tests/wpt/web-platform-tests/css/css-lists/content-property/marker-text-matches-armenian.html @@ -14,5 +14,5 @@ ol { </style> <ol> - <li>Filler Text</li> + <li>Filler Text<span style="display: inline-block; width: 1px; height: 50px;"></span></li> </ol> diff --git a/tests/wpt/web-platform-tests/css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html b/tests/wpt/web-platform-tests/css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html index 6e40afe54c9..1f74697489d 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html +++ b/tests/wpt/web-platform-tests/css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <title>CSS Multi-column Layout Test: extremely tall multicolumn container with extremely tall inline-block inside</title> <link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org"> -<link rel="help" href="http://www.w3.org/TR/css3-multicol/" title="CSS Multi-column Layout Module Level 1"> +<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#the-multi-column-model" title="CSS Multi-column Layout Module Level 1"> <meta name="assert" content="This tests that we get no crash if we put an extremely tall inline-block inside an extremely tall multicol container. Engines typically have some maximum limit for how large values they can represent. If the value is large enough to become 'infinity', the engine should still not crash"> <!-- Explanation for the CSS values specified below: This test was written for the Chromium Blink engine, which uses a fixed-point 32 bit integer. In this diff --git a/tests/wpt/web-platform-tests/css/css-multicol/going-out-of-flow-after-spanner.html b/tests/wpt/web-platform-tests/css/css-multicol/going-out-of-flow-after-spanner.html index 24338643339..2fe0e42a752 100644 --- a/tests/wpt/web-platform-tests/css/css-multicol/going-out-of-flow-after-spanner.html +++ b/tests/wpt/web-platform-tests/css/css-multicol/going-out-of-flow-after-spanner.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <title>Taking the sole box after a spanner out of flow, then remove it</title> <link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org"> -<link rel="help" href="http://www.w3.org/TR/css3-multicol/" title="CSS Multi-column Layout Module Level 1"> +<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#the-multi-column-model"> <meta name="assert" content="An absolutely positioned box is still contained by the multicol container if its containing block is inside the multicol container"> <div id="multicol" style="columns:3;"> <div style="position:relative;"> diff --git a/tests/wpt/web-platform-tests/css/css-overflow/outline-with-opacity-crash.html b/tests/wpt/web-platform-tests/css/css-overflow/outline-with-opacity-crash.html new file mode 100644 index 00000000000..556e3cfedcd --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-overflow/outline-with-opacity-crash.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<link rel="author" title="Philip Rogers" href="mailto:pdr@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1011699"> +<span id="target" style="outline: 1px solid black; will-change: opacity; opacity: 0.7;">test</span> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(()=> { + target.style.background = "lightblue"; + }, "no crash"); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-005.html b/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-005.html new file mode 100644 index 00000000000..e4de5769584 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-005.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>CSS Overflow Test: overscroll-behavior doesn't stop overflow from being propagated from the body</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-overflow/#overflow-propagation"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1586600"> +<link rel="match" href="reference/overflow-body-propagation-ref.html"> +<style> + :root { + overscroll-behavior-y: contain; + } + body { + overflow: scroll; + margin-top: 100px; + } +</style> +<body>The viewport should have scrollbars, not the body.</body> diff --git a/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-006.html b/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-006.html new file mode 100644 index 00000000000..47581506835 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-overflow/overflow-body-propagation-006.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>CSS Overflow Test: scroll-snap-type doesn't stop overflow from being propagated from the body</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-overflow/#overflow-propagation"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1586600"> +<link rel="match" href="reference/overflow-body-propagation-ref.html"> +<style> + :root { + scroll-snap-type: both mandatory; + } + body { + overflow: scroll; + margin-top: 100px; + } +</style> +<body>The viewport should have scrollbars, not the body.</body> diff --git a/tests/wpt/web-platform-tests/css/css-pseudo/first-line-first-letter-insert-crash.html b/tests/wpt/web-platform-tests/css/css-pseudo/first-line-first-letter-insert-crash.html index 17f035dedf1..bc22aae409b 100644 --- a/tests/wpt/web-platform-tests/css/css-pseudo/first-line-first-letter-insert-crash.html +++ b/tests/wpt/web-platform-tests/css/css-pseudo/first-line-first-letter-insert-crash.html @@ -1,6 +1,6 @@ <!DOCTYPE html> <title>Should not crash when inserting an element inside a :first-line pseudo.</title> -<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-line-pseudo"> <style> p:first-line, p:first-letter { font-family: serif; diff --git a/tests/wpt/web-platform-tests/css/css-pseudo/idlharness.html b/tests/wpt/web-platform-tests/css/css-pseudo/idlharness.html index 4c113fc9091..eb0652e9eeb 100644 --- a/tests/wpt/web-platform-tests/css/css-pseudo/idlharness.html +++ b/tests/wpt/web-platform-tests/css/css-pseudo/idlharness.html @@ -1,6 +1,6 @@ <!doctype html> <title>CSS Pseudo Element API IDL tests</title> -<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#cssom"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/WebIDLParser.js"></script> diff --git a/tests/wpt/web-platform-tests/css/css-shadow-parts/idlharness.html b/tests/wpt/web-platform-tests/css/css-shadow-parts/idlharness.html new file mode 100644 index 00000000000..182943ac69d --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-shadow-parts/idlharness.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<title>CSS Shadow Parts IDL tests</title> +<link rel="help" href="https://drafts.csswg.org/css-shadow-parts/#idl"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="/resources/idlharness.js"></script> +<script> +idl_test( + ['css-shadow-parts'], + ['dom'], + idl_array => { + self.element = document.createElementNS('ns', 'e'); + self.htmlElement = document.createElement('html'); + self.svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + idl_array.add_objects({ + Element: ['element', 'htmlElement', 'svgElement'], + }); + } +); +</script> diff --git a/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-important.html b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-important.html new file mode 100644 index 00000000000..43ec1bbae34 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-important.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Shadow Parts - Simple Important Important</title> + <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> + <link href="http://www.google.com/" rel="author" title="Google"> + <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/shadow-helper.js"></script> + </head> + <body> + <style>#c-e::part(partp) { color: green !important; }</style> + <script>installCustomElement("custom-element", "custom-element-template");</script> + <template id="custom-element-template"> + <style>span { color: red !important; }</style> + <span id="part" part="partp">This text</span> + </template> + The following text should be green: + <custom-element id="c-e"></custom-element> + <script> + "use strict"; + const colorRed = "rgb(255, 0, 0)"; + test(function() { + const el = getElementByShadowIds(document, ["c-e", "part"]); + assert_equals(window.getComputedStyle(el).color, colorRed); + }, "Part in selected host is styled"); + </script> + </body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-inline.html b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-inline.html new file mode 100644 index 00000000000..61b83dd4be7 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important-inline.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Shadow Parts - Simple Important Inline</title> + <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> + <link href="http://www.google.com/" rel="author" title="Google"> + <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/shadow-helper.js"></script> + </head> + <body> + <style>#c-e::part(partp) { color: red; }</style> + <script>installCustomElement("custom-element", "custom-element-template");</script> + <template id="custom-element-template"> + <span id="part" part="partp" style="color: green !important">This text</span> + </template> + The following text should be red: + <custom-element id="c-e"></custom-element> + <script> + "use strict"; + const colorGreen = "rgb(0, 128, 0)"; + test(function() { + const el = getElementByShadowIds(document, ["c-e", "part"]); + assert_equals(window.getComputedStyle(el).color, colorGreen); + }, "Part in selected host is not styled"); + </script> + </body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important.html b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important.html new file mode 100644 index 00000000000..e3240bd3905 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-important.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Shadow Parts - Simple Important</title> + <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> + <link href="http://www.google.com/" rel="author" title="Google"> + <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/shadow-helper.js"></script> + </head> + <body> + <style>#c-e::part(partp) { color: red; }</style> + <script>installCustomElement("custom-element", "custom-element-template");</script> + <template id="custom-element-template"> + <style>span { color: green !important; }</style> + <span id="part" part="partp">This text</span> + </template> + The following text should be green: + <custom-element id="c-e"></custom-element> + <script> + "use strict"; + const colorGreen = "rgb(0, 128, 0)"; + test(function() { + const el = getElementByShadowIds(document, ["c-e", "part"]); + assert_equals(window.getComputedStyle(el).color, colorGreen); + }, "Part in selected host is styled"); + </script> + </body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-inline.html b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-inline.html new file mode 100644 index 00000000000..f2c3638d1e9 --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-shadow-parts/simple-inline.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Shadow Parts - Simple Inline</title> + <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> + <link href="http://www.google.com/" rel="author" title="Google"> + <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/shadow-helper.js"></script> + </head> + <body> + <style>#c-e::part(partp) { color: green; }</style> + <script>installCustomElement("custom-element", "custom-element-template");</script> + <template id="custom-element-template"> + <span id="part" part="partp" style="color: red">This text</span> + </template> + The following text should be green: + <custom-element id="c-e"></custom-element> + <script> + "use strict"; + const colorGreen = "rgb(0, 128, 0)"; + test(function() { + const el = getElementByShadowIds(document, ["c-e", "part"]); + assert_equals(window.getComputedStyle(el).color, colorGreen); + }, "Part in selected host is styled"); + </script> + </body> +</html> diff --git a/tests/wpt/web-platform-tests/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html b/tests/wpt/web-platform-tests/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html index f79b21a723e..def2d75fd93 100644 --- a/tests/wpt/web-platform-tests/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html +++ b/tests/wpt/web-platform-tests/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html @@ -19,16 +19,16 @@ // font relative units: em, ex, ch, rem var units = ['em', 'ex', 'ch', 'rem']; var resolveds = {}; - ParsingUtils.setupFonts(function () { - var div = document.createElement('div'); - document.body.appendChild(div); - units.forEach(function(unit) { - div.style.width = '10' + unit; - var s = getComputedStyle(div); - resolveds[unit] = parseFloat(s.width); - }); - document.body.removeChild(div); - })(); + ParsingUtils.setupFonts(); + + var div = document.createElement('div'); + document.body.appendChild(div); + units.forEach(function(unit) { + div.style.width = '10' + unit; + var s = getComputedStyle(div); + resolveds[unit] = parseFloat(s.width); + }); + document.body.removeChild(div); function fillArray(string, length) { return Array.apply(null, new Array(length)).map(String.prototype.valueOf, string); @@ -49,6 +49,8 @@ }); generate_tests(testUnit, tests); + + ParsingUtils.restoreFonts(); </script> </body> </html> diff --git a/tests/wpt/web-platform-tests/css/css-tables/box-shadow-001.html b/tests/wpt/web-platform-tests/css/css-tables/box-shadow-001.html new file mode 100644 index 00000000000..cc699d999ea --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-tables/box-shadow-001.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<title>Collapsed borders and box-shadow</title> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-tables-3/#in-collapsed-borders-mode"> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#box-shadow"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<link rel="bookmark" href="https://crbug.com/1006241" /> +<meta name="flags" content="" /> +<meta name="assert" content="box-shadow size and location on a cell with collapsed borders are calculated correctly" /> + +<style> +table { + border-collapse: collapse; +} + +/* Make the green box-shadow start at the inner edge of the border to cover up all the red. + Chrome's bug made the box-shadow start further toward the center. */ +td { + border: 20px solid green; + box-shadow: inset 60px 0px green; + /* The properties after the blank line aren't the focus of the test. */ + + background: red; + line-height: 0px; + padding: 0px; +} + +td > span { + display: inline-block; /* chrome only hits this bug when the td children are inline */ + + height: 60px; + width: 60px; +} +</style> + +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<table> + <tr> + <td><span></span></td> + </tr> +</table> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-005.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-005.html index b5cf3f33ec2..81c39aa27fe 100644 --- a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-005.html +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-005.html @@ -2,7 +2,7 @@ <meta charset="utf-8"> <title>CSS Text level 3 Test: break-space tabs don't hang</title> <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> -<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> <link rel="match" href="reference/break-spaces-tab-005-ref.html"> <meta name="assert" content="a sequence of break-spaces tabs at the end of a line does not hang."> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-006.html b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-006.html index 85d821a3e4d..34df3bfc1bd 100644 --- a/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-006.html +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/break-spaces-tab-006.html @@ -2,7 +2,7 @@ <meta charset="utf-8"> <title>CSS Text level 3 Test: break-spaces tabs and spaces don't hang</title> <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> -<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> <link rel="match" href="reference/break-spaces-tab-005-ref.html"> <meta name="assert" content="a sequence of break-spaces tabs and spaces at the end of a line does not hang, and can wrap after each tab or space."> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/eol-spaces-bidi-001.html b/tests/wpt/web-platform-tests/css/css-text/white-space/eol-spaces-bidi-001.html new file mode 100644 index 00000000000..976ce7c639f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/eol-spaces-bidi-001.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text level 3 Test: collapsible white space at end-of-line and bidi</title> +<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="match" href="reference/eol-spaces-bidi-001-ref.html"> +<meta name="assert" content="Collapsible space at the end of the line prior to bidi reordering are removed."> +<style> +div { + font-family: monospace; + border: solid blue; + font-size: 1.5em; + margin-bottom:1em; + display: inline-block; +} +.ref { + white-space: pre; + border-color: orange; +} +.w5 { width: 5ch; } +.w6 { width: 6ch; } +.w7 { width: 7ch; } +.w8 { width: 8ch; } + +.blue { background: #aaaaff; } +.red { background: #ffaaaa; } +.green { background: #aaffaa; } +.pink { background: #ffaaff; } +.yellow { background: #ffffaa; } + +</style> +<p>Test passes if the content of each blue box (on the left) is laid out identically to the content of the orange box to its right. + +<div class=w5><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div> +<div class="ref w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<br> +<div class=w6><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div> +<div class="ref w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<br> +<div class=w7><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div> +<div class="ref w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> +<br> +<div class=w8><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div> +<div class="ref w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-005.html b/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-005.html index 993aa92e370..edbc5974c15 100644 --- a/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-005.html +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-005.html @@ -2,7 +2,7 @@ <meta charset="utf-8"> <title>CSS Text level 3 Test: pre-wrap tabs hang</title> <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> -<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> <link rel="match" href="reference/pre-wrap-001-ref.html"> <meta name="assert" content="a sequence of pre-wrap tabs at the end of a line hangs."> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-006.html b/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-006.html index a4c7f3d3ebd..4bdb7a21c7c 100644 --- a/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-006.html +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/pre-wrap-tab-006.html @@ -2,7 +2,7 @@ <meta charset="utf-8"> <title>CSS Text level 3 Test: pre-wrap tabs and spaces hang</title> <link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> -<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-3"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> <link rel="match" href="reference/pre-wrap-001-ref.html"> <meta name="assert" content="a sequence of pre-wrap tabs and spaces at the end of a line hangs."> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> diff --git a/tests/wpt/web-platform-tests/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html b/tests/wpt/web-platform-tests/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html new file mode 100644 index 00000000000..37da6649f9b --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS test reference</title> +<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/"> +<style> +div { + font-family: monospace; + border: solid blue; + font-size: 1.5em; + margin-bottom:1em; + display: inline-block; + white-space: pre; +} +.ref { + border-color: orange; +} +.w5 { width: 5ch; } +.w6 { width: 6ch; } +.w7 { width: 7ch; } +.w8 { width: 8ch; } + +.blue { background: #aaaaff; } +.red { background: #ffaaaa; } +.green { background: #aaffaa; } + +</style> +<p>Test passes if the content of each blue box (on the left) is laid out identically to the content of the orange box to its right. + +<div class="w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<div class="ref w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<br> +<div class="w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<div class="ref w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div> +<br> +<div class="w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> +<div class="ref w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> +<br> +<div class="w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> +<div class="ref w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div> diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/percentage-padding-in-shrink-to-fit.html b/tests/wpt/web-platform-tests/css/css-writing-modes/percentage-padding-in-shrink-to-fit.html index 2d4364c886c..240a66c9c6b 100644 --- a/tests/wpt/web-platform-tests/css/css-writing-modes/percentage-padding-in-shrink-to-fit.html +++ b/tests/wpt/web-platform-tests/css/css-writing-modes/percentage-padding-in-shrink-to-fit.html @@ -1,6 +1,6 @@ <!DOCTYPE html> <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> -<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/"> +<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#dimension-mapping"> <link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-top"> <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=966795"> <link rel="match" href="../reference/nothing.html"> diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-001.html b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-001.html index d313cacf38d..f552265d0d0 100644 --- a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-001.html +++ b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-001.html @@ -13,18 +13,17 @@ body { writing-mode: vertical-rl; width: 0; height: 0; } -html::before { - content: "This text must be vertical."; - /* This is inline content of the root, - and should therefore be vertical, - as the root's used value is vertical */ -} html::after { content: "This text must be horizontal."; display: block; - /* This is a block level element, - with it's own writing mode inherited from the root, - horizontal since the root's computed value should be horizontal*/ + /* The writing mode inherited from the root must be horizontal + since the root's computed value should be horizontal */ + } </style> -<body></body> +<script> + document.documentElement.append("This text must be vertical"); + /* This is direct content of the root, + and should therefore be vertical, + as the root's used value is vertical */ +</script> diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044-ref.html b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044-ref.html index 31e98673720..9cf46c0b214 100644 --- a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044-ref.html +++ b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044-ref.html @@ -13,6 +13,11 @@ padding-right: 16px; vertical-align: top; } + div + { + margin-left: -8px; + writing-mode: vertical-rl; + } </style> @@ -24,4 +29,4 @@ in the <strong>upper-left corner</strong> of the page. --> - <div style=margin-left:-8px>This text must be written horizontally.</div> + <div>This text must be written vertically, below the orange square.</div> diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044.html b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044.html index 60d444ca8b2..5993cee3593 100644 --- a/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044.html +++ b/tests/wpt/web-platform-tests/css/css-writing-modes/wm-propagation-body-044.html @@ -14,7 +14,7 @@ <link rel="match" href="wm-propagation-body-044-ref.html"> <meta name="flags" content=""> - <meta name="assert" content="This test checks that when the root element has a <body> child element, then the principal writing mode is instead taken from the values of writing-mode and direction on the first such child element instead of taken from the root element. Also, a small script in this test verifies that the computed value of 'writing-mode' of the root element itself is not affected by such propagation. Finally, in order to make sure that the principal writing mode is indeed 'horizontal-tb', the test checks that a generated text's inline axis is indeed horizontal and not vertical."> + <meta name="assert" content="This test checks that when the root element has a <body> child element, then the principal writing mode is instead taken from the values of writing-mode and direction on the first such child element instead of taken from the root element. Also, a small script in this test verifies that the computed value of 'writing-mode' of the root element itself is not affected by such propagation. We also check that the computed value is unaffected by inheriting it into a pseudo element."> <!-- Tests 032 to 035: html's writing-mode is not specified @@ -38,7 +38,7 @@ html::after { - content: "This text must be written horizontally."; + content: "This text must be written vertically, below the orange square."; display: block; } diff --git a/tests/wpt/web-platform-tests/css/cssom-view/elementFromPoint-list-001.html b/tests/wpt/web-platform-tests/css/cssom-view/elementFromPoint-list-001.html index e3c2c4d18f4..b31453d6c32 100644 --- a/tests/wpt/web-platform-tests/css/cssom-view/elementFromPoint-list-001.html +++ b/tests/wpt/web-platform-tests/css/cssom-view/elementFromPoint-list-001.html @@ -5,28 +5,79 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <style> +ul { + font-size: 10px; +} ul.inside { list-style-position: inside; } +.image { + list-style-image: url(../../images/green-16x16.png); +} +.debug-marker { + position: absolute; + width: 0; + height: 0; + outline: 2px solid red; +} </style> <body> <ul> <li>Outside 1</li> <li>Outside 2</li> <li>Outside 3</li> + <li class="image">Image Outside 1</li> + <li class="image">Image Outside 2</li> </ul> <ul class="inside"> <li>Inside 1</li> <li>Inside 2</li> <li>Inside 3</li> + <li class="image">Image Inside 1</li> + <li class="image">Image Inside 2</li> </ul> <script> -for (let li of document.getElementsByTagName('li')) { - test(() => { - let bounds = li.getBoundingClientRect(); - let target = document.elementFromPoint(bounds.x + 1, bounds.y + 1); - assert_equals(target, li); - }, `<li>${li.textContent}</li>`); +setup({explicit_done:true}); +window.onload = function() { + for (let li of document.getElementsByTagName('li')) { + test(() => { + let bounds = li.getBoundingClientRect(); + let style = window.getComputedStyle(li); + let y = (bounds.top + bounds.bottom) / 2; + if (style.listStylePosition === 'inside') { + // Inside markers are normal inline boxes. + // It is safe to assume "left + 1" is in the box. + let x = bounds.left + 1; + addDebugMarker(x, y); + let result = document.elementFromPoint(x, y); + assert_equals(result, li); + } else { + // The spec does not define outside marker position. + // This code assumes that the marker is within "left - 40" to "left - 1". + // This is heuristic, but all browsers seem to pass with this method. + let result = null; + for (let x = bounds.left - 40; x < bounds.left; x++) { + result = document.elementFromPoint(x, y); + if (result === li) { + addDebugMarker(x, y); + break; + } + } + assert_equals(result, li); + } + }, `<li>${li.textContent}</li>`); + } + done(); +}; + +// Show a marker for the debugging purposes, in case the heuristic doesn't apply. +function addDebugMarker(x, y) { + let div = document.createElement('div'); + div.className = 'debug-marker'; + let style = div.style; + style.left = x + 'px'; + style.top = y + 'px'; + document.body.appendChild(div); } </script> </body> diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-006.html b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-006.html index 989ee424867..8f3ac37b057 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-006.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/mq-calc-006.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <link rel="author" title="Xiaocheng Hu" href="xiaochengh@chromium.org"> <link rel="help" href="http://www.w3.org/TR/css3-values/#calc-notation"> -<link rel="help" href="http://www.w3.org/TR/css3-mediaqueries/"> +<link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#units"> <link rel="match" href="../reference/ref-filled-green-100px-square.xht"> <meta name="assert" content="The 'in' unit used in calc is not mistaken as 'px'."> <style> diff --git a/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html b/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html index d368acf8b57..881df835f5a 100644 --- a/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html +++ b/tests/wpt/web-platform-tests/css/mediaqueries/test_media_queries.html @@ -5,7 +5,7 @@ <link rel="author" title="L. David Baron" href="https://dbaron.org/"> <link rel="author" title="Anne van Kesteren" href="http://annevankesteren.nl/"> <link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"> - <link rel="help" href="http://www.w3.org/TR/css3-mediaqueries/"> + <link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#media0"> <script type="text/javascript" src="/resources/testharness.js"></script> <script type="text/javascript" src="/resources/testharnessreport.js"></script> </head> diff --git a/tests/wpt/web-platform-tests/css/tools/build.py b/tests/wpt/web-platform-tests/css/tools/build.py index d60e00fd330..9bbc2a5e753 100755 --- a/tests/wpt/web-platform-tests/css/tools/build.py +++ b/tests/wpt/web-platform-tests/css/tools/build.py @@ -130,7 +130,12 @@ class Builder(object): if not source.isTest(): continue - metaData = source.getMetadata(True) + try: + metaData = source.getMetadata(True) + except Exception as error: + self.ui.warn("Exception parsing '", filePath, "': ", error, "\n") + continue + if not metaData: if (source.errors): self.ui.warn("Error parsing '", filePath, "': ", ' '.join(source.errors), "\n") diff --git a/tests/wpt/web-platform-tests/docs/admin/index.md b/tests/wpt/web-platform-tests/docs/admin/index.md index 8a04e2a0c80..7eca6e3a9a9 100644 --- a/tests/wpt/web-platform-tests/docs/admin/index.md +++ b/tests/wpt/web-platform-tests/docs/admin/index.md @@ -48,7 +48,6 @@ explicitly-managed secret. - [Google Domains](https://domains.google/): https://wpt.fyi - foolip@google.com - jeffcarp@google.com - - lukebjerring@google.com - mike@bocoup.com - [GitHub](https://github.com/): web-platform-tests - [@foolip](https://github.com/foolip) @@ -66,8 +65,6 @@ explicitly-managed secret. - foolip@google.com - geoffers@gmail.com - jeffcarp@google.com - - kereliuk@google.com - - lukebjerring@google.com - markdittmer@google.com - mike@bocoup.com - rick@bocoup.com diff --git a/tests/wpt/web-platform-tests/editing/data/inserthtml.js b/tests/wpt/web-platform-tests/editing/data/inserthtml.js index 0c6cff86c60..a3a23cd99e1 100644 --- a/tests/wpt/web-platform-tests/editing/data/inserthtml.js +++ b/tests/wpt/web-platform-tests/editing/data/inserthtml.js @@ -360,6 +360,26 @@ var browserTests = [ "<ul><li>f<ul><li>abc</li></ul>{}o</li></ul>", [true], {"inserthtml":[false,false,"",false,false,""]}], +["<ul id=\"old\"><li id=\"li0\">{}<br></ul>", + [["inserthtml","<ul id=\"new\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ul>"]], + "<ul id=\"old\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ul>", + [true], + {"inserthtml":[false,false,"",false,false,""]}], +["<ol id=\"old\"><li id=\"li0\">{}<br></ol>", + [["inserthtml","<ol id=\"new\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ol>"]], + "<ol id=\"old\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ol>", + [true], + {"inserthtml":[false,false,"",false,false,""]}], +["<ul id=\"old\"><li id=\"li0\">{}<br></ul>", + [["inserthtml","<ol id=\"new\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ol>"]], + "<ul id=\"old\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ul>", + [true], + {"inserthtml":[false,false,"",false,false,""]}], +["<ol id=\"old\"><li id=\"li0\">{}<br></ol>", + [["inserthtml","<ul id=\"new\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ul>"]], + "<ol id=\"old\"><li id=\"li1\">abc</li><li id=\"li2\">def</li></ol>", + [true], + {"inserthtml":[false,false,"",false,false,""]}], ["f[o]o", [["defaultparagraphseparator","div"],["inserthtml","<li>abc</li>"]], "f<div>abc</div>{}o", diff --git a/tests/wpt/web-platform-tests/event-timing/crossiframe.html b/tests/wpt/web-platform-tests/event-timing/crossiframe.html index bb19c82a2a1..95e16afa079 100644 --- a/tests/wpt/web-platform-tests/event-timing/crossiframe.html +++ b/tests/wpt/web-platform-tests/event-timing/crossiframe.html @@ -34,7 +34,7 @@ assert_greater_than(entry.processingStart, processingStartMin, "The entry's processing start should be later than processingStartMin."); assert_greater_than(onloadStart, entry.processingStart, - "onload should occur later than the entry's procesisng start."); + "onload should occur later than the entry's processing start."); assert_greater_than(entry.startTime, clickTimeMin, "The entry's start time should be later than clickTimeMin."); assert_greater_than(onloadStart, entry.startTime, diff --git a/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot.js b/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot.js index 5b048d33644..db45bb4acc9 100644 --- a/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot.js +++ b/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot.js @@ -4,6 +4,6 @@ // which found out that some script resources are served // with text/html content-type and with a body that is // both a valid html and a valid javascript. -window.polyglot = "html-js-polyglot.js"; +window['html-js-polyglot.js'] = true; //--></script></body></html> diff --git a/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot2.js b/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot2.js index 9443f8ed6c3..faae1b7682b 100644 --- a/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot2.js +++ b/tests/wpt/web-platform-tests/fetch/corb/resources/html-js-polyglot2.js @@ -5,6 +5,6 @@ // which found out that some script resources are served // with text/html content-type and with a body that is // both a valid html and a valid javascript. -window.polyglot = "html-js-polyglot2.js"; +window['html-js-polyglot2.js'] = true; //]]>--></script> diff --git a/tests/wpt/web-platform-tests/fetch/corb/script-html-js-polyglot.sub.html b/tests/wpt/web-platform-tests/fetch/corb/script-html-js-polyglot.sub.html index ec4103771fb..9a272d63ffc 100644 --- a/tests/wpt/web-platform-tests/fetch/corb/script-html-js-polyglot.sub.html +++ b/tests/wpt/web-platform-tests/fetch/corb/script-html-js-polyglot.sub.html @@ -9,13 +9,13 @@ <script> ["html-js-polyglot.js", "html-js-polyglot2.js"].forEach(polyglot_name => { async_test(function(t) { - window.polyglot = "not yet set by the script"; + window[polyglot_name] = false; var script = document.createElement("script"); script.onload = t.step_func_done(function(){ // Verify that the script response wasn't blocked - that script - // should have set window.polyglot to |polyglot_name|. - assert_equals(window.polyglot, polyglot_name); + // should have set window[polyglot_name] to true. + assert_true(window[polyglot_name]); }) addEventListener("error",function(e) { t.step(function() { diff --git a/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html index cabc7b09c45..d46944727f8 100644 --- a/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html @@ -53,25 +53,25 @@ mime_types = [ ] function test(mime_type, body) { - async_test(function(t) { + // The test below depends on a global/shared event handler - we need to ensure + // that no tests run in parallel - this is achieved by using `promise_test` + // instead of `async_test`. See also + // https://web-platform-tests.org/writing-tests/testharness-api.html#promise-tests + promise_test(t => new Promise(function(resolve, reject) { var script = document.createElement("script") // Without CORB, the JSON parser breaker would cause a syntax error when // parsed as JavaScript, but with CORB there should be no errors (because // CORB will replace the response body with an empty body). - script.onload = t.step_func_done(function(){}) - addEventListener("error",function(e) { - t.step(function() { - assert_unreached("Empty body of a CORS-blocked response shouldn't trigger syntax errors."); - t.done(); - }) - }); + script.onload = resolve; + addEventListener("error", t.unreached_func( + "Empty body of a CORS-blocked response shouldn't trigger syntax errors.")) // www1 is cross-origin, so the HTTP response is CORB-eligible. var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body); document.body.appendChild(script) - }, "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body); + }), "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body); } mime_types.forEach(function(type) { diff --git a/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html index 4cbdd7b99e6..f83eff82b5e 100644 --- a/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html @@ -11,6 +11,7 @@ <meta charset="utf-8"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> <div id=log></div> <script> setup({allow_uncaught_exception : true}); @@ -18,16 +19,17 @@ setup({allow_uncaught_exception : true}); function test(mime_type, is_blocking_expected) { async_test(function(t) { var script = document.createElement("script") + var script_has_run_token = "script_has_run" + token(); // With and without CORB there should be no error, but without CORB the // original script body will be preserved and |window.script_has_run| will // be set. - window.script_has_run = false; + window[script_has_run_token] = false; script.onload = t.step_func_done(function(){ if (is_blocking_expected) { - assert_false(window.script_has_run); + assert_false(window[script_has_run_token]); } else { - assert_true(window.script_has_run); + assert_true(window[script_has_run_token]); } }); addEventListener("error",function(e) { @@ -44,7 +46,7 @@ function test(mime_type, is_blocking_expected) { // rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). // See also https://crbug.com/918660 for more context. var src_prefix = "http://{{hosts[alt][www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; - body = "window.script_has_run = true;" + body = `window['${script_has_run_token}'] = true;` script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body); document.body.appendChild(script) }, "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body); diff --git a/tests/wpt/web-platform-tests/fetch/metadata/appcache.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/appcache.tentative.https.sub.html index 1b5a5767c2c..3aa902cc146 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/appcache.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/appcache.tentative.https.sub.html @@ -12,7 +12,6 @@ fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=appcache-manifest{{$id}}") .then(t.step_func(response => response.text())) .then(t.step_func_done(text => assert_header_equals(text, { - "dest": "", "site": "same-origin", "user": "", "mode": "no-cors" diff --git a/tests/wpt/web-platform-tests/fetch/metadata/embed.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/embed.tentative.https.sub.html index bf895e9d538..77042e85de9 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/embed.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/embed.tentative.https.sub.html @@ -7,62 +7,52 @@ <script src=/common/utils.js></script> <body> <script> - let nonce = token(); - - promise_test(t => { - return new Promise((resolve, reject) => { - let key = "embed-same-origin" + nonce; - - let e = document.createElement('embed'); - e.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - e.onload = e => { - let expected = {"dest":"embed", "site":"same-origin", "user":"", "mode":"no-cors"}; - fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) - .then(response => response.text()) - .then(text => assert_header_equals(text, expected)) - .then(_ => resolve()) - .catch(e => reject(e)); - }; - - document.body.appendChild(e); - }) - }, "Same-Origin embed"); - - promise_test(t => { - return new Promise((resolve, reject) => { - let key = "embed-same-site" + nonce; - - let e = document.createElement('embed'); - e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - e.onload = e => { - let expected = {"dest":"embed", "site":"same-site", "user":"", "mode":"no-cors"}; - fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) - .then(response => response.text()) - .then(text => assert_header_equals(text, expected)) - .then(_ => resolve()) - .catch(e => reject(e)); - }; - - document.body.appendChild(e); - }) - }, "Same-Site embed"); - - promise_test(t => { - return new Promise((resolve, reject) => { - let key = "embed-cross-site" + nonce; - - let e = document.createElement('embed'); - e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - e.onload = e => { - let expected = {"dest":"embed", "site":"cross-site", "user":"", "mode":"no-cors"}; - fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) - .then(response => response.text()) - .then(text => assert_header_equals(text, expected)) - .then(_ => resolve()) - .catch(e => reject(e)); - }; - - document.body.appendChild(e); - }) - }, "Cross-Site embed"); + const nonce = token(); + + const origins = { + "same-origin": "https://{{host}}:{{ports[https][0]}}", + "same-site": "https://{{hosts[][www]}}:{{ports[https][0]}}", + "cross-site": "https://{{hosts[alt][www]}}:{{ports[https][0]}}", + }; + + for (let site in origins) { + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "embed-" + site + "-" + nonce; + + let el = document.createElement('embed'); + el.src = origins[site] + "/fetch/metadata/resources/record-header.py?file=" + key; + el.onload = _ => { + let expected = {"dest": "embed", "site": site, "user": "", "mode":"no-cors"}; + validate_expectations(key, expected, site + " embed") + .then(resolve) + .catch(reject); + }; + + document.body.appendChild(el); + }) + }, "Wrapper: " + site + " embed"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "post-embed-" + site + "-" + nonce; + + let el = document.createElement('embed'); + el.src = "/common/blank.html"; + el.addEventListener("load", _ => { + el.addEventListener("load", _ => { + let expected = {"dest": "embed", "site": site, "user":"", "mode":"no-cors"}; + validate_expectations(key, expected, "Navigate to " + site + " embed") + .then(resolve) + .catch(reject); + }, { once: true }); + + // Navigate the existing `<embed>` + window.frames[window.length - 1].location = origins[site] + "/fetch/metadata/resources/record-header.py?file=" + key; + }, { once: true }); + + document.body.appendChild(el); + }) + }, "Wrapper: Navigate to " + site + " embed"); + } </script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/fetch-preflight.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/fetch-preflight.tentative.https.sub.html index 27dafc25df7..1ab3de615c8 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/fetch-preflight.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/fetch-preflight.tentative.https.sub.html @@ -13,7 +13,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-site", "user": "", "mode": "cors", @@ -30,7 +29,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html index 86edfd06dec..13016fe3537 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html @@ -44,7 +44,7 @@ const text = await response.text(); // Verify presence of the expected Sec-Fetch-... request headers. - let expected = {"dest":"empty", "site":"same-origin", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "no-cors"}; assert_header_equals(text, expected); }, 'Sec-Fetch headers after SW fallback'); </script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html index d59348c257b..d43715785b4 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html @@ -45,7 +45,7 @@ const text = await response.text(); // Verify presence of the expected Sec-Fetch-... request headers. - let expected = {"dest":"empty", "site":"same-origin", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "no-cors"}; assert_header_equals(text, expected); }, 'Sec-Fetch headers after SW fallback'); </script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.https.sub.html index 30042f8aeb8..72fb52ecd5d 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.https.sub.html @@ -9,7 +9,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-origin", "user": "", "mode": "cors", @@ -22,7 +21,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-site", "user": "", "mode": "cors", @@ -35,7 +33,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", @@ -49,7 +46,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-origin", "user": "", "mode": "same-origin", @@ -62,7 +58,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-origin", "user": "", "mode": "cors", @@ -75,7 +70,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "same-origin", "user": "", "mode": "no-cors", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.sub.html index a2d66d6afa9..a14c2c5f411 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/fetch.tentative.sub.html @@ -12,7 +12,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", @@ -27,7 +26,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "", "site": "", "user": "", "mode": "", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/font.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/font.tentative.https.sub.html index 07152e8f18c..9064dd68973 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/font.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/font.tentative.https.sub.html @@ -46,7 +46,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-same-origin"; - let expected = {"dest":"font", "site":"same-origin", "user":"", "mode": "cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -58,7 +58,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-same-site"; - let expected = {"dest":"font", "site":"same-site", "user":"", "mode": "cors"}; + let expected = {"site":"same-site", "user":"", "mode": "cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -70,7 +70,7 @@ promise_test(t => { return new Promise((resolve, reject) => { let key = "font-cross-site"; - let expected = {"dest":"font", "site":"cross-site", "user":"", "mode": "cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/history.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/history.tentative.https.sub.html index ef8e74bc86d..0d78ec06035 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/history.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/history.tentative.https.sub.html @@ -55,8 +55,7 @@ add_test( "back to same-origin-initiated navigation", same_origin_host, // report_host cross_site_host, // go_back_host - { "dest": "document", - "site": "same-origin", + { "site": "same-origin", "user": "", "mode": "navigate" }); @@ -64,8 +63,7 @@ add_test( "back to same-site-initiated navigation", same_site_host, // report_host cross_site_host, // go_back_host - { "dest": "document", - "site": "same-site", + { "site": "same-site", "user": "", "mode": "navigate" }); @@ -73,8 +71,7 @@ add_test( "back to cross-site-initiated navigation", cross_site_host, // report_host cross_site_host, // go_back_host - { "dest": "document", - "site": "cross-site", + { "site": "cross-site", "user": "", "mode": "navigate" }); diff --git a/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.https.sub.html index 7b89d8dc0da..b8f11c66b7e 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.https.sub.html @@ -42,42 +42,36 @@ } create_test("{{host}}:{{ports[https][0]}}", FORCED, { - "dest": "nested-document", "site": "same-origin", "user": "", "mode": "nested-navigate" }); create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, { - "dest": "nested-document", "site": "same-site", "user": "", "mode": "nested-navigate" }); create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, { - "dest": "nested-document", "site": "cross-site", "user": "", "mode": "nested-navigate" }); create_test("{{host}}:{{ports[https][0]}}", USER, { - "dest": "nested-document", "site": "same-origin", "user": "?1", "mode": "nested-navigate" }); create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, { - "dest": "nested-document", "site": "same-site", "user": "?1", "mode": "nested-navigate" }); create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, { - "dest": "nested-document", "site": "cross-site", "user": "?1", "mode": "nested-navigate" diff --git a/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.sub.html index 418e2a2d449..c5469f458d3 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/iframe.tentative.sub.html @@ -12,7 +12,6 @@ return; assert_header_equals(e.data, { - "dest": "", "site": "", "user": "", "mode": "", @@ -31,7 +30,6 @@ return; assert_header_equals(e.data, { - "dest": "", "site": "", "user": "", "mode": "", @@ -50,7 +48,6 @@ return; assert_header_equals(e.data, { - "dest": "", "site": "", "user": "", "mode": "", @@ -69,7 +66,6 @@ return; assert_header_equals(e.data, { - "dest": "nested-document", "site": "cross-site", "user": "", "mode": "nested-navigate", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/img.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/img.tentative.https.sub.html index c3248f60961..ced6f9845e8 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/img.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/img.tentative.https.sub.html @@ -13,13 +13,11 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] }; assert_header_equals(got, { - "dest": "image", "site": "same-origin", // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. @@ -35,13 +33,11 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] }; assert_header_equals(got, { - "dest": "image", "site": "same-site", // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. @@ -57,13 +53,11 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] }; assert_header_equals(got, { - "dest": "image", "site": "cross-site", // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. diff --git a/tests/wpt/web-platform-tests/fetch/metadata/navigation.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/navigation.https.sub.html index 50857aeabaf..1c2ce953795 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/navigation.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/navigation.https.sub.html @@ -6,13 +6,11 @@ <script> test(t => { let expected = { - "dest": "document", "mode": "navigate", "site": "none", }; let actual = { - "dest": "{{headers[sec-fetch-dest]}}", "mode": "{{headers[sec-fetch-mode]}}", "site": "{{headers[sec-fetch-site]}}", // Skipping `Sec-Fetch-User`, as the test harness isn't consistent here. diff --git a/tests/wpt/web-platform-tests/fetch/metadata/object.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/object.tentative.https.sub.html index 40ef308362e..cf1c2603999 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/object.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/object.tentative.https.sub.html @@ -16,7 +16,7 @@ let e = document.createElement('object'); e.data = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"same-origin", "user":"", "mode":"no-cors"}; + let expected = {"site":"same-origin", "user":"", "mode":"no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -35,7 +35,7 @@ let e = document.createElement('object'); e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"same-site", "user":"", "mode":"no-cors"}; + let expected = {"site":"same-site", "user":"", "mode":"no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -54,7 +54,7 @@ let e = document.createElement('object'); e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"object", "site":"cross-site", "user":"", "mode":"no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode":"no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/portal.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/portal.tentative.https.sub.html index 50f0037dfd0..ee24b5ecbb9 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/portal.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/portal.tentative.https.sub.html @@ -25,22 +25,18 @@ } create_test("{{host}}:{{ports[https][0]}}", { - // TODO(mkwst): 'document' seems right, I guess? Perhaps a portal-specific destination would be better? - "dest": "document", "site": "same-origin", "user": "", "mode": "nested-navigate" }); create_test("{{hosts[][www]}}:{{ports[https][0]}}", { - "dest": "document", "site": "same-site", "user": "", "mode": "nested-navigate" }); create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", { - "dest": "document", "site": "cross-site", "user": "", "mode": "nested-navigate" diff --git a/tests/wpt/web-platform-tests/fetch/metadata/prefetch.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/prefetch.tentative.https.sub.html index 1902b9bca79..30966f872f8 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/prefetch.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/prefetch.tentative.https.sub.html @@ -30,7 +30,7 @@ }, `<link rel='prefetch' href='https://${host}/...'>`); } - create_test("{{host}}:{{ports[https][0]}}", {"dest":"empty", "site":"same-origin", "user":"", "mode": "cors"}); - create_test("{{hosts[][www]}}:{{ports[https][0]}}", {"dest":"empty", "site":"same-site", "user":"", "mode": "cors"}); - create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", {"dest":"empty", "site":"cross-site", "user":"", "mode": "cors"}); + create_test("{{host}}:{{ports[https][0]}}", {"site":"same-origin", "user":"", "mode": "cors"}); + create_test("{{hosts[][www]}}:{{ports[https][0]}}", {"site":"same-site", "user":"", "mode": "cors"}); + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", {"site":"cross-site", "user":"", "mode": "cors"}); </script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/preload.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/preload.tentative.https.sub.html index 9dbcad322a6..e8c541ef7f9 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/preload.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/preload.tentative.https.sub.html @@ -44,8 +44,8 @@ ]; as_tests.forEach(item => { - create_test("{{host}}:{{ports[https][0]}}", item[0], {"dest":item[1], "site":"same-origin", "user":"", "mode": "cors"}); - create_test("{{hosts[][www]}}:{{ports[https][0]}}", item[0], {"dest":item[1], "site":"same-site", "user":"", "mode": "cors"}); - create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", item[0], {"dest":item[1], "site":"cross-site", "user":"", "mode": "cors"}); + create_test("{{host}}:{{ports[https][0]}}", item[0], {"site":"same-origin", "user":"", "mode": "cors"}); + create_test("{{hosts[][www]}}:{{ports[https][0]}}", item[0], {"site":"same-site", "user":"", "mode": "cors"}); + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", item[0], {"site":"cross-site", "user":"", "mode": "cors"}); }); </script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/cross-site-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/cross-site-redirect.tentative.https.sub.html index 4747ebf36f8..0874273ef94 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/cross-site-redirect.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/cross-site-redirect.tentative.https.sub.html @@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) @@ -41,7 +41,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) @@ -67,7 +67,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html index 8120e762517..efff1cdaae8 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html @@ -17,7 +17,7 @@ e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// cross-site "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key;// same-origin - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html index a15e681ad84..e7774f6ba10 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html @@ -19,7 +19,7 @@ <div id="fontTest">Downgraded then upgraded font</div> <script> let nonce = "{{$id}}"; - let expected = { "dest": "", "site": "cross-site", "user": "", "mode": "cors" }; + let expected = { "site": "cross-site", "user": "", "mode": "cors" }; // Validate various scenarios handle a request that redirects from https => http // correctly and avoids disclosure of any Sec- headers. @@ -43,7 +43,6 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] @@ -51,7 +50,6 @@ assert_header_equals(got, { // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. - "dest": undefined, "site": "cross-site", "user": undefined, "mode": "cors", @@ -63,7 +61,7 @@ <script> test(t => { t.add_cleanup(_ => { header = null; }); - assert_header_equals(header, { "dest": "", "site": "cross-site", "user": "", "mode": "no-cors" }); + assert_header_equals(header, { "site": "cross-site", "user": "", "mode": "no-cors" }); }, "Https downgrade-upgrade script => No headers"); </script> </body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html index 8c65095cc9c..b1df738354c 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html @@ -17,7 +17,7 @@ e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-site "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key;// same-origin - let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-http-upgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-http-upgrade.tentative.sub.html index 6ba5b948332..c7e1721af78 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-http-upgrade.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-http-upgrade.tentative.sub.html @@ -19,7 +19,7 @@ <div id="fontTest">Upgraded font</div> <script> let nonce = "{{$id}}"; - let expected = { "dest": "", "site": "cross-site", "user": "", "mode": "cors" }; + let expected = { "site": "cross-site", "user": "", "mode": "cors" }; // Validate various scenarios handle a request that redirects from http => https correctly and add the proper Sec- headers. RunCommonRedirectTests("Http upgrade", upgradeRedirectTo, expected); @@ -42,7 +42,6 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] @@ -50,7 +49,6 @@ assert_header_equals(got, { // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. - "dest": undefined, "site": "cross-site", "user": undefined, "mode": "cors", @@ -63,7 +61,7 @@ <script> test(t => { t.add_cleanup(_ => { header = null; }); - assert_header_equals(header, { "dest": "", "site": "cross-site", "user": "", "mode": "no-cors" }); + assert_header_equals(header, { "site": "cross-site", "user": "", "mode": "no-cors" }); }, "Http upgrade script => No headers"); </script> </body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-https-downgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-https-downgrade.tentative.sub.html index 54e48e0c61c..eee21dafcac 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-https-downgrade.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/redirect-https-downgrade.tentative.sub.html @@ -19,7 +19,7 @@ <div id="fontTest">Downgraded font</div> <script> let nonce = token(); - let expected = { "dest": "", "site": "", "user": "", "mode": "" }; + let expected = { "site": "", "user": "", "mode": "" }; // Validate various scenarios handle a request that redirects from https => http correctly and avoids disclosure of any Sec- headers. RunCommonRedirectTests("Https downgrade", downgradeRedirectTo, expected); @@ -42,7 +42,6 @@ .then(result => { headers = result.headers; got = { - "dest": headers["sec-fetch-dest"], "mode": headers["sec-fetch-mode"], "site": headers["sec-fetch-site"], "user": headers["sec-fetch-user"] @@ -50,7 +49,6 @@ assert_header_equals(got, { // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. - "dest": undefined, "site": undefined, "user": undefined, "mode": undefined, @@ -62,7 +60,7 @@ <script> test(t => { t.add_cleanup(_ => { header = null; }); - assert_header_equals(header, { "dest": "", "site": "cross-site", "user": "", "mode": "no-cors" }); + assert_header_equals(header, { "site": "cross-site", "user": "", "mode": "no-cors" }); }, "Https downgrade script => No headers"); </script> </body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-origin-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-origin-redirect.tentative.https.sub.html index b88429c540d..a31d2d399f2 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-origin-redirect.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-origin-redirect.tentative.https.sub.html @@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-origin", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -42,7 +42,7 @@ promise_test(t => { let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -69,7 +69,7 @@ promise_test(t => { let e = document.createElement('img'); e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-site-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-site-redirect.tentative.https.sub.html index 795e418660d..f342b1c2669 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-site-redirect.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/redirect/same-site-redirect.tentative.https.sub.html @@ -15,7 +15,7 @@ let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -42,7 +42,7 @@ promise_test(t => { let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) @@ -69,7 +69,7 @@ promise_test(t => { let e = document.createElement('img'); e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; - let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; e.onload = e => { fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/report.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/report.tentative.https.sub.html index 8209fd17cd5..821c56f5877 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/report.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/report.tentative.https.sub.html @@ -22,9 +22,9 @@ document.addEventListener("securitypolicyviolation", (e) => { counter++; if (counter == 3) { - generate_test({"dest":"report", "site":"same-origin", "user":"", "mode": "no-cors"}, "same-origin"); - generate_test({"dest":"report", "site":"same-site", "user":"", "mode": "no-cors"}, "same-site"); - generate_test({"dest":"report", "site":"cross-site", "user":"", "mode": "no-cors"}, "cross-site"); + generate_test({"site":"same-origin", "user":"", "mode": "no-cors"}, "same-origin"); + generate_test({"site":"same-site", "user":"", "mode": "no-cors"}, "same-site"); + generate_test({"site":"cross-site", "user":"", "mode": "no-cors"}, "cross-site"); done(); } diff --git a/tests/wpt/web-platform-tests/fetch/metadata/resources/helper.js b/tests/wpt/web-platform-tests/fetch/metadata/resources/helper.js index 9425246881b..d9b00ed8b94 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/resources/helper.js +++ b/tests/wpt/web-platform-tests/fetch/metadata/resources/helper.js @@ -2,15 +2,85 @@ function wrap_by_tag(tag, text) { return tag ? `${tag}: ${text}`: text; } +function validate_expectations(key, expected, tag) { + return fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + .then(response => response.text()) + .then(text => { + assert_not_equals(text, "No header has been recorded"); + let value = JSON.parse(text); + test(t => assert_equals(value.dest, expected.dest), `${tag}: sec-fetch-dest`); + test(t => assert_equals(value.mode, expected.mode), `${tag}: sec-fetch-mode`); + test(t => assert_equals(value.site, expected.site), `${tag}: sec-fetch-site`); + test(t => assert_equals(value.user, expected.user), `${tag}: sec-fetch-user`); + }); +}; + +/** + * @param {object} value + * @param {object} expected + * @param {string} tag + **/ function assert_header_equals(value, expected, tag) { if (typeof(value) === "string"){ assert_not_equals(value, "No header has been recorded"); value = JSON.parse(value); } - assert_equals(value.dest, expected.dest, wrap_by_tag(tag, "dest")); assert_equals(value.mode, expected.mode, wrap_by_tag(tag, "mode")); assert_equals(value.site, expected.site, wrap_by_tag(tag, "site")); if (expected.hasOwnProperty("user")) assert_equals(value.user, expected.user, wrap_by_tag(tag, "user")); } + +/** + * @param {string} header + * @param {object} value + * @param {string} expected + * @param {string} tag + **/ +function assert_header(header, value, expected, tag) { + if (typeof(value) === "string"){ + assert_not_equals(value, "No header has been recorded"); + value = JSON.parse(value); + } + + assert_equals(value[header], expected, wrap_by_tag(tag, header)); +} + +/** + * + * @param {object} value + * @param {string} expected + * @param {string} tag + **/ +function assert_header_dest_equals(value, expected, tag) { + assert_header("dest", value, expected, tag); +} + +/** + * Test fetch record-header.py + * @param {string} key + * @param {string} expected + * @param {function} assert + * @return {Promise<string | never>} + */ +function fetch_record_header(key, expected, assert) { + return fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + .then(response => response.text()) + .then(text => assert(text, expected)) +} + +/** + * + * @param {string} key + * @param {string} expected + * @param {function} assert + * @param {function} resolve + * @param {function} reject + * @return {Promise<any>} + */ +function fetch_record_header_with_catch(key, expected, assert, resolve, reject) { + return fetch_record_header(key, expected, assert, resolve) + .then(_ => resolve()) + .catch(e => reject(e)); +} diff --git a/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.https.sub.html index f877b50ec2b..d5a1096e819 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.https.sub.html @@ -10,7 +10,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "script", "site": "same-origin", "user": "", "mode": "no-cors", @@ -25,7 +24,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "script", "site": "same-site", "user": "", "mode": "no-cors", @@ -40,7 +38,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "script", "site": "cross-site", "user": "", "mode": "no-cors", @@ -55,7 +52,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "script", "site": "same-origin", "user": "", "mode": "cors", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.sub.html index 66b821265ba..b1361516cb5 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/script.tentative.sub.html @@ -10,7 +10,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "", "site": "", "user": "", "mode": "", @@ -25,7 +24,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "", "site": "", "user": "", "mode": "", @@ -40,7 +38,6 @@ t.add_cleanup(_ => { header = null; }); assert_header_equals(header, { - "dest": "", "site": "", "user": "", "mode": "", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html new file mode 100644 index 00000000000..469001e2f33 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/appcache.tentative.https.sub.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html manifest="/fetch/metadata/resources/record-header.py?file=appcache-manifest{{$id:uuid()}}"> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + async_test(t => { + window.applicationCache.oncached = window.applicationCache.onnoupdate = window.applicationCache.onerror = t.step_func(e => { + fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=appcache-manifest{{$id}}") + .then(t.step_func(response => response.text())) + .then(t.step_func_done(text => assert_header_dest_equals(text, ""))) + .catch(t.unreached_func("Fetching and verifying the results should succeed.")); +}); +}, "Appcache!"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html new file mode 100644 index 00000000000..d880deee5dd --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/embed.tentative.https.sub.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<meta charset="utf-8"/> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "embed-same-origin" + nonce; + + let e = document.createElement('embed'); + e.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "embed", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin embed"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "embed-same-site" + nonce; + + let e = document.createElement('embed'); + e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "embed", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site embed"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "embed-cross-site" + nonce; + + let e = document.createElement('embed'); + e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "embed", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site embed"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html new file mode 100644 index 00000000000..63d53e8969d --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-preflight.tentative.https.sub.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + // Site + promise_test(t => { + return fetch("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", + { + mode: "cors", + headers: { 'x-test': 'testing' } + }) + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Same-site fetch with preflight"); + + promise_test(t => { + return fetch("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", + { + mode: "cors", + headers: { 'x-test': 'testing' } + }) + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Cross-site fetch with preflight"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html new file mode 100644 index 00000000000..d2341572eb7 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--fallback.tentative.https.sub.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<!-- + This test verifies presence of Sec-Fetch-... request headers on a request + handled by a service worker - this test covers the scenario when the service + worker doesn't do anything and the request falls back to the network. +--> +<meta charset="utf-8"/> +<link rel="author" href="lukasza@chromium.org" title="Lukasz Anforowicz"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script> +<script src=/common/utils.js></script> +<script> + const nonce = token(); + const key = "fetch-via-serviceworker--fallback--" + nonce; + + promise_test(async function(t) { + const SCOPE = '/fetch/metadata/resources/fetch-via-serviceworker--fallback--frame.html'; + const SCRIPT = '/fetch/metadata/resources/fetch-via-serviceworker--fallback--sw.js'; + const URL = '/fetch/metadata/resources/record-header.py?file=' + key; + const RETRIEVAL_URL = "/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key; + + const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE); + t.add_cleanup(async () => { + if (reg) + await reg.unregister(); + }); + + await wait_for_state(t, reg.installing, 'activated'); + + const frame = await with_iframe(SCOPE); + t.add_cleanup(async () => { + if (frame) + frame.remove(); + }); + + // Trigger a fetch that 1) will go through the service worker and 2) will + // fetch a special URL that records request headers. + await frame.contentWindow.fetch(URL, {mode:'no-cors'}); + + // Retrieve the request headers that have been recorded in the previous step. + const response = await fetch(RETRIEVAL_URL); + const text = await response.text(); + + // Verify presence of the expected Sec-Fetch-... request headers. + assert_header_dest_equals(text, "empty"); + }, 'Sec-Fetch headers after SW fallback'); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html new file mode 100644 index 00000000000..f70ae8b9dd3 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch-via-serviceworker--respondWith.tentative.https.sub.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<!-- + This test verifies presence of Sec-Fetch-... request headers on a request + handled by a service worker - this test covers the scenario when the service + worker responds to the `fetch` event with: + event.respondWith(fetch(event.request)); +--> +<meta charset="utf-8"/> +<link rel="author" href="lukasza@chromium.org" title="Lukasz Anforowicz"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script> +<script src=/common/utils.js></script> +<script> + const nonce = token(); + const key = "fetch-via-serviceworker--respondWith--" + nonce; + + promise_test(async function(t) { + const SCOPE = '/fetch/metadata/resources/fetch-via-serviceworker--respondWith--frame.html'; + const SCRIPT = '/fetch/metadata/resources/fetch-via-serviceworker--respondWith--sw.js'; + const URL = '/fetch/metadata/resources/record-header.py?file=' + key; + const RETRIEVAL_URL = "/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key; + + const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE); + t.add_cleanup(async () => { + if (reg) + await reg.unregister(); + }); + + await wait_for_state(t, reg.installing, 'activated'); + + const frame = await with_iframe(SCOPE); + t.add_cleanup(async () => { + if (frame) + frame.remove(); + }); + + // Trigger a fetch that 1) will go through the service worker and 2) will + // fetch a special URL that records request headers. + await frame.contentWindow.fetch(URL, {mode:'no-cors'}); + + // Retrieve the request headers that have been recorder in the previous step. + const response = await fetch(RETRIEVAL_URL); + const text = await response.text(); + + // Verify presence of the expected Sec-Fetch-... request headers. + assert_header_dest_equals(text, "empty"); + }, 'Sec-Fetch headers after SW fallback'); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html new file mode 100644 index 00000000000..99f8191d7cb --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.https.sub.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + // Site + promise_test(t => { + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Same-origin fetch"); + + promise_test(t => { + return fetch("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Same-site fetch"); + + promise_test(t => { + return fetch("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Cross-site fetch"); + + // Mode + promise_test(t => { + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "same-origin"}) + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "Same-origin mode"); + + promise_test(t => { + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "cors"}) + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "CORS mode"); + + promise_test(t => { + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py", {mode: "no-cors"}) + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "no-CORS mode"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html new file mode 100644 index 00000000000..cf6c7977af2 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/fetch.tentative.sub.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + // http -> https should see `Sec-Fetch-Site: cross-site`. + // This is a regression test for + // https://github.com/w3c/webappsec-fetch-metadata/issues/34 + promise_test(t => { + assert_equals(location.protocol, "http:"); + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "empty")); + }, "http->https fetch (cross-scheme => cross-site)"); + + // http -> http should see no `Sec-Fetch-Site`. + promise_test(t => { + assert_equals(location.protocol, "http:"); + return fetch("/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => assert_header_dest_equals(j, "")); + }, "http->http fetch (non-trustworthy destination => no metadata)"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html new file mode 100644 index 00000000000..bc892db320c --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/font.tentative.https.sub.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<html> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<body> + <div id="test1">1</div> + <div id="test2">2</div> + <div id="test3">3</div> + <!-- Same-Origin request --> + <style> + @font-face { + font-family: myFirstFont; + src: url(https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=font-same-origin); + } + #test1 { + font-family: myFirstFont; + } + </style> + + <!-- Same-Site request --> + <style> + @font-face { + font-family: mySecondFont; + src: url(https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=font-same-site); + } + #test2 { + font-family: mySecondFont; + } + </style> + + <!-- Cross-Site request --> + <style> + @font-face { + font-family: myThirdFont; + src: url(https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=font-cross-site); + } + #test3 { + font-family: myThirdFont; + } + </style> +</body> +<script> + document.fonts.ready.then(function () { + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-same-origin"; + fetch_record_header_with_catch(key, "font", assert_header_dest_equals, resolve, reject); + }); + }, "Same-Origin font"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-same-site"; + fetch_record_header_with_catch(key, "font", assert_header_dest_equals, resolve, reject); + }); + }, "Same-Site font"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-cross-site"; + fetch_record_header_with_catch(key, "font", assert_header_dest_equals, resolve, reject); + }); + }, "Cross-Site font"); + + }); +</script> +</html> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html new file mode 100644 index 00000000000..d80b7274698 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.https.sub.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + const USER = true; + const FORCED = false; + + function create_test(host, user_activated, expectations) { + async_test(t => { + let i = document.createElement('frame'); + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, expectations); + t.done(); + })); + + let url = `https://${host}/fetch/metadata/resources/post-to-owner.py`; + if (user_activated == FORCED) { + i.src = url; + document.body.appendChild(i); + } else if (user_activated == USER) { + let uuid = token(); + i.name = uuid; + let a = document.createElement('a'); + a.href = url; + a.target = uuid; + a.text = "This is a link!"; + + document.body.appendChild(i); + document.body.appendChild(a); + + test_driver.click(a); + } + }, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`); + } + + create_test("{{host}}:{{ports[https][0]}}", FORCED, "frame"); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, "frame"); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, "frame"); + + create_test("{{host}}:{{ports[https][0]}}", USER, "frame"); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, "frame"); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, "frame"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html new file mode 100644 index 00000000000..61b6d1f446b --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/frame.tentative.sub.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<body> +<script> + async_test(t => { + let i = document.createElement('frame'); + i.src = "http://{{host}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure same-origin iframe => No headers"); + + async_test(t => { + let i = document.createElement('frame'); + i.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure same-site iframe => No headers"); + + async_test(t => { + let i = document.createElement('frame'); + i.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure cross-site iframe => No headers."); + + async_test(t => { + let i = document.createElement('frame'); + i.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, "frame"); + t.done(); + })); + + document.body.appendChild(i); + }, "Secure, cross-site (cross-scheme, same-host) frame"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html new file mode 100644 index 00000000000..55e03a23660 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/history.tentative.https.sub.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + +// Test that correct `Sec-Fetch-Site` (and other `Sec-Fetch-...` request +/// headers) are used in navigations triggered by |history.back()|. +function add_test(description, report_host, go_back_host, expectation) { + async_test(t => { + // STEP1: Navigate a new window to report_host/post-to-owner.py + const url_suffix = '/fetch/metadata/resources/post-to-owner.py' + const url = `https://${report_host}${url_suffix}`; + const w = window.open(url, '_blank'); + + var msg_counter = 0; + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + msg_counter = msg_counter + 1; + if (msg_counter == 1) { + // STEP2: Verify the headers (this is a sanity check that the same + // headers are used here and in STEP5). + assert_header_dest_equals(e.data, expectation); + + // STEP3: Go to go_back_host/go-back.html (postponing this via + // step_timeout ensures that go-back.html will get a separate + // history entry - otherwise it might be treated as a client-side + // redirect and we might end up with nowhere to go back to). + t.step_timeout(() => { + const url_suffix = '/fetch/metadata/resources/go-back.html' + const url = `https://${go_back_host}${url_suffix}`; + w.location = url; + }); + + // STEP4 (elsewhere - inside go-back.html): Call history.back(). + } else if (msg_counter == 2) { + // STEP5: Verify the headers (this is the main verification and focus + // of the test). + assert_header_dest_equals(e.data, expectation); + + // STEP6: Finish the test. + t.done(); + } + })); + }, description); +} + +const same_origin_host = "{{host}}:{{ports[https][0]}}"; +const same_site_host = "{{hosts[][www]}}:{{ports[https][0]}}"; +const cross_site_host = "{{hosts[alt][www]}}:{{ports[https][0]}}"; + +add_test( + "back to same-origin-initiated navigation", + same_origin_host, // report_host + cross_site_host, // go_back_host + "document"); + +add_test( + "back to same-site-initiated navigation", + same_site_host, // report_host + cross_site_host, // go_back_host + "document"); + +add_test( + "back to cross-site-initiated navigation", + cross_site_host, // report_host + cross_site_host, // go_back_host + "document"); + +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html new file mode 100644 index 00000000000..356805d1900 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.https.sub.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + const USER = true; + const FORCED = false; + + function create_test(host, user_activated, expectations) { + async_test(t => { + let i = document.createElement('iframe'); + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, expectations); + t.done(); + })); + + let url = `https://${host}/fetch/metadata/resources/post-to-owner.py`; + if (user_activated == FORCED) { + i.src = url; + document.body.appendChild(i); + } else if (user_activated == USER) { + let uuid = token(); + i.name = uuid; + let a = document.createElement('a'); + a.href = url; + a.target = uuid; + a.text = "This is a link!"; + + document.body.appendChild(i); + document.body.appendChild(a); + + test_driver.click(a); + } + }, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`); + } + + create_test("{{host}}:{{ports[https][0]}}", FORCED, "iframe"); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, "iframe"); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, "iframe"); + + create_test("{{host}}:{{ports[https][0]}}", USER, "iframe"); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, "iframe"); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, "iframe"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html new file mode 100644 index 00000000000..e126e3c0a89 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/iframe.tentative.sub.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<body> +<script> + async_test(t => { + let i = document.createElement('iframe'); + i.src = "http://{{host}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure same-origin iframe => No headers"); + + async_test(t => { + let i = document.createElement('iframe'); + i.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure same-site iframe => No headers"); + + async_test(t => { + let i = document.createElement('iframe'); + i.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, ""); + t.done(); + })); + + document.body.appendChild(i); + }, "Non-secure cross-site iframe => No headers."); + + async_test(t => { + let i = document.createElement('iframe'); + i.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_dest_equals(e.data, "iframe"); + t.done(); + })); + + document.body.appendChild(i); + }, "Secure, cross-site (cross-scheme, same-host) iframe"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html new file mode 100644 index 00000000000..f6b84b1795b --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/img.tentative.https.sub.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/security-features/resources/common.sub.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<body> +<script> + // These tests reuse the `referrer-policy` infrastructure to load images that + // encode their request headers in their pixels. Fun stuff! + promise_test(() => + requestViaImage( + "https://{{host}}:{{ports[https][0]}}/common/security-features/subresource/image.py") + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + assert_header_dest_equals(got, "image"); + }), + "Same-origin image"); + + promise_test(() => + requestViaImage( + "https://{{hosts[][www]}}:{{ports[https][0]}}/common/security-features/subresource/image.py") + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + assert_header_dest_equals(got, "image"); + }), + "Same-site image"); + + promise_test(() => + requestViaImage( + "https://{{hosts[alt][www]}}:{{ports[https][0]}}/common/security-features/subresource/image.py") + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + assert_header_dest_equals(got, "image"); + }), + "Cross-site image"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/navigation.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/navigation.https.sub.html new file mode 100644 index 00000000000..3ab843d165c --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/navigation.https.sub.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + test(t => { + let actual = { + "dest": "{{headers[sec-fetch-dest]}}" + }; + + assert_header_dest_equals(actual, "document"); + }, "This page's top-level navigation."); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html new file mode 100644 index 00000000000..29db5111785 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/object.tentative.https.sub.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<meta charset="utf-8"/> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "object-same-origin" + nonce; + + let e = document.createElement('object'); + e.data = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "object", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin object"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "object-same-site" + nonce; + + let e = document.createElement('object'); + e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "object", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site object"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "object-cross-site" + nonce; + + let e = document.createElement('object'); + e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "object", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site object"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html new file mode 100644 index 00000000000..ad9e8fd9362 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/portal.tentative.https.sub.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + const USER = true; + const FORCED = false; + + function create_test(host, expectation) { + async_test(t => { + let p = document.createElement('portal'); + p.addEventListener('message', t.step_func(e => { + assert_header_dest_equals(e.data, expectation); + t.done(); + })); + + let url = `https://${host}/fetch/metadata/resources/post-to-owner.py`; + p.src = url; + document.body.appendChild(p); + }, `{{host}} -> ${host} portal`); + } + + // TODO(mkwst): 'document' seems right, I guess? Perhaps a portal-specific destination would be better? + create_test("{{host}}:{{ports[https][0]}}", "document"); + + create_test("{{hosts[][www]}}:{{ports[https][0]}}", "document"); + + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", "document"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html new file mode 100644 index 00000000000..be495ba332e --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/prefetch.tentative.https.sub.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + test(t => { + assert_true(document.createElement('link').relList.supports('prefetch')); + }, "Browser supports prefetch."); + + function create_test(host, expected) { + async_test(t => { + let nonce = token(); + let key = "prefetch" + nonce; + + let e = document.createElement('link'); + e.rel = "prefetch"; + e.href = `https://${host}/fetch/metadata/resources/record-header.py?file=${key}`; + e.setAttribute("crossorigin", "crossorigin"); + e.onload = t.step_func(e => { + fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + .then(t.step_func(response => response.text())) + .then(t.step_func_done(text => assert_header_dest_equals(text, expected))) + .catch(t.unreached_func("Fetching and verifying the results should succeed.")); + }); + e.onerror = t.unreached_func(); + + document.head.appendChild(e); + }, `<link rel='prefetch' href='https://${host}/...'>`); + } + + create_test("{{host}}:{{ports[https][0]}}", "empty"); + create_test("{{hosts[][www]}}:{{ports[https][0]}}", "empty"); + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", "empty"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html new file mode 100644 index 00000000000..2c82abb3664 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/preload.tentative.https.sub.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + test(t => { + assert_true(document.createElement('link').relList.supports('preload')); + }, "Browser supports preload."); + + function create_test(host, as, expected) { + async_test(t => { + let nonce = "{{uuid()}}"; + let key = as + nonce; + + let e = document.createElement('link'); + e.rel = "preload"; + e.href = `https://${host}/fetch/metadata/resources/record-header.py?file=${key}`; + e.setAttribute("crossorigin", "crossorigin"); + if (as !== undefined) { + e.setAttribute("as", as); + } + e.onload = e.onerror = t.step_func_done(e => { + fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + .then(t.step_func(response => response.text())) + .then(t.step_func(text => assert_header_dest_equals(text, expected))) + .then(t.step_func_done(_ => resolve())) + .catch(t.unreached_func()); + }); + + document.head.appendChild(e); + }, `<link rel='preload' as='${as}' href='https://${host}/...'>`); + } + + let as_tests = [ + [ "fetch", "empty" ], + [ "font", "font" ], + [ "image", "image" ], + [ "script", "script" ], + [ "style", "style" ], + [ "track", "track" ], + ]; + + as_tests.forEach(item => { + create_test("{{host}}:{{ports[https][0]}}", item[0], item[1]); + create_test("{{hosts[][www]}}:{{ports[https][0]}}", item[0], item[1]); + create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", item[0], item[1]); + }); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html new file mode 100644 index 00000000000..ea13cc83bdf --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/cross-site-redirect.tentative.https.sub.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-cross-site-same-origin" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site -> Same-Origin redirect"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-cross-site-same-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site -> Same-Site redirect"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-cross-site-cross-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site -> Cross-Site redirect"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html new file mode 100644 index 00000000000..e74ce0c06d5 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-cross-site.tentative.https.sub.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-multiple-cross-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin + "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// cross-site + "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key;// same-origin + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin -> Cross-Site -> Same-Origin redirect"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html new file mode 100644 index 00000000000..78ee10dc736 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/fetch/metadata/resources/redirectTestHelper.sub.js></script> +<script src=/common/security-features/resources/common.sub.js></script> +<script src=/common/utils.js></script> +<style> + @font-face { + font-family: myDowngradeUpgradeFont; + src: url(https://{{host}}:{{ports[https][0]}}/fetch/api/resources/redirect.py?location=http%3A%2F%2F{{host}}%3A{{ports[http][0]}}%2Ffetch%2Fapi%2Fresources%2Fredirect.py%3Flocation%3Dhttps%253A%252F%252F{{host}}%253A{{ports[https][0]}}%252Ffetch%252Fmetadata%252Fresources%252Frecord-header.py%253Ffile%253Dfont-https-downgrade-upgrade{{$id:uuid()}}); + } + #fontTest { + font-family: myDowngradeUpgradeFont; + } +</style> +<body> + <div id="fontTest">Downgraded then upgraded font</div> + <script> + let nonce = "{{$id}}"; + + // Validate various scenarios handle a request that redirects from https => http + // correctly and avoids disclosure of any Sec- headers. + RunCommonRedirectTests("Https downgrade-upgrade", MultipleRedirectTo, expected); + + document.fonts.ready.then(function () { + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-https-downgrade-upgrade{{$id}}"; + return fetch_record_header_with_catch(key, "", assert_header_dest_equals, resolve, reject); + }); + }, "Https downgrade-upgrade font => No headers"); + }); + + promise_test(() => { + return requestViaImage(secureRedirectURL + encodeURIComponent(insecureRedirectURL + encodeURIComponent("https://{{host}}:{{ports[https][0]}}/common/security-features/subresource/image.py"))) + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + assert_header_dest_equals(got, undefined); + }); + }, "Https downgrade-upgrade image => No headers"); +</script> +<script src="https://{{host}}:{{ports[https][0]}}/fetch/api/resources/redirect.py?location=http%3A%2F%2F{{host}}%3A{{ports[http][0]}}%2Ffetch%2Fapi%2Fresources%2Fredirect.py%3Flocation%3Dhttps%253A%252F%252F{{host}}%253A{{ports[https][0]}}%252Ffetch%252Fmetadata%252Fresources%252Fecho-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + assert_header_dest_equals(header, ""); + }, "Https downgrade-upgrade script => No headers"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html new file mode 100644 index 00000000000..90a47668439 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/multiple-redirect-same-site.tentative.https.sub.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-multiple-same-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin + "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-site + "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key;// same-origin + + e.onload = e => { + return fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + return fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin -> Same-Site -> Same-Origin redirect"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html new file mode 100644 index 00000000000..a31efcbf26a --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-http-upgrade.tentative.sub.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/fetch/metadata/resources/redirectTestHelper.sub.js></script> +<script src=/common/security-features/resources/common.sub.js></script> +<script src=/common/utils.js></script> +<style> + @font-face { + font-family: myUpgradedFont; + src: url(http://{{host}}:{{ports[http][0]}}/fetch/api/resources/redirect.py?location=https%3A%2F%2F{{host}}%3A{{ports[https][0]}}%2Ffetch%2Fmetadata%2Fresources%2Frecord-header.py%3Ffile%3Dfont-https-upgrade{{$id:uuid()}}); + } + #fontTest { + font-family: myUpgradedFont; + } +</style> +<body> + <div id="fontTest">Upgraded font</div> + <script> + let nonce = "{{$id}}"; + + // Validate various scenarios handle a request that redirects from http => https correctly and add the proper Sec- headers. + RunCommonRedirectTests("Http upgrade", upgradeRedirectTo, expected); + + document.fonts.ready.then(function () { + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-https-upgrade{{$id}}"; + fetch_record_header_with_catch(key, "", assert_header_dest_equals, resolve, reject); + }); + }, "Http upgrade font => No headers"); + }); + + promise_test(() => { + return requestViaImage(insecureRedirectURL + encodeURIComponent("https://{{host}}:{{ports[https][0]}}/common/security-features/subresource/image.py")) + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + assert_header_dest_equals(got, undefined); + }); + }, "Http upgrade image => No headers"); +</script> + +<script src="http://{{host}}:{{ports[http][0]}}/fetch/api/resources/redirect.py?location=https%3A%2F%2F{{host}}%3A{{ports[https][0]}}%2Ffetch%2Fmetadata%2Fresources%2Fecho-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + assert_header_dest_equals(header, ""); + }, "Http upgrade script => No headers"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html new file mode 100644 index 00000000000..425753cb508 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/redirect-https-downgrade.tentative.sub.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/fetch/metadata/resources/redirectTestHelper.sub.js></script> +<script src=/common/security-features/resources/common.sub.js></script> +<script src=/common/utils.js></script> +<style> + @font-face { + font-family: myDowngradedFont; + src: url(https://{{host}}:{{ports[https][0]}}/fetch/api/resources/redirect.py?location=http%3A%2F%2F{{host}}%3A{{ports[http][0]}}%2Ffetch%2Fmetadata%2Fresources%2Frecord-header.py%3Ffile%3Dfont-https-downgrade); + } + #fontTest { + font-family: myDowngradedFont; + } +</style> +<body> + <div id="fontTest">Downgraded font</div> + <script> + let nonce = token(); + + // Validate various scenarios handle a request that redirects from https => http correctly and avoids disclosure of any Sec- headers. + RunCommonRedirectTests("Https downgrade", downgradeRedirectTo, expected); + + document.fonts.ready.then(function () { + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "font-https-downgrade"; + fetch_record_header_with_catch(key, "", assert_header_dest_equals, resolve, reject); + }); + }, "Https downgrade font => No headers"); + }); + + promise_test(() => + return requestViaImage(secureRedirectURL + encodeURIComponent("http://{{host}}:{{ports[http][0]}}/common/security-features/subresource/image.py")) + .then(result => { + headers = result.headers; + got = { + "dest": headers["sec-fetch-dest"] + }; + // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way + // that `image.py` encodes data. + assert_header_dest_equals(got, undefined); + }), "Https downgrade image => No headers"); +</script> + +<script src="https://{{host}}:{{ports[https][0]}}/fetch/api/resources/redirect.py?location=http%3A%2F%2F{{host}}%3A{{ports[http][0]}}%2Ffetch%2Fmetadata%2Fresources%2Fecho-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + assert_header_dest_equals(header, ""); + }, "Https downgrade script => No headers"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html new file mode 100644 index 00000000000..9b8b44b0ef2 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-origin-redirect.tentative.https.sub.html @@ -0,0 +1,65 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-origin-same-origin" + nonce; + + let e = document.createElement('img'); + e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin -> Same-Origin redirect"); + +promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-origin-same-site" + nonce; + + let e = document.createElement('img'); + e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin -> Same-Site redirect"); + +promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-origin-cross-site" + nonce; + + let e = document.createElement('img'); + e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin -> Cross-Site redirect"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html new file mode 100644 index 00000000000..2f12fe03cab --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/redirect/same-site-redirect.tentative.https.sub.html @@ -0,0 +1,65 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-site-same-origin" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site -> Same-Origin redirect"); + +promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-site-same-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site -> Same-Site redirect"); + +promise_test(t => { + return new Promise((resolve, reject) => { + let key = "redirect-same-site-cross-site" + nonce; + + let e = document.createElement('img'); + e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + + e.onload = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + e.onerror = e => { + fetch_record_header_with_catch(key, "image", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site -> Cross-Site redirect"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html new file mode 100644 index 00000000000..d3cb7e101a5 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<link id="style" href="https://foo.bar" rel="stylesheet"> +<body></body> +<script> + setup({ explicit_done: true }); + function generate_test(expected, name) { + async_test(t => { + t.step_timeout(_ => { + return fetch_record_header("report-" + name, expected, assert_header_dest_equals) + .then(_ => t.done()); + }, 1000); + }, name + " report"); + } + + let counter = 0; + document.addEventListener("securitypolicyviolation", (e) => { + counter++; + if (counter == 3) { + generate_test("report", "same-origin"); + generate_test("report", "same-site"); + generate_test("report", "cross-site"); + + done(); + } + }); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.sub.headers b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.sub.headers new file mode 100644 index 00000000000..1ec5df78f30 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/report.tentative.https.sub.html.sub.headers @@ -0,0 +1,3 @@ +Content-Security-Policy: style-src 'self' 'unsafe-inline'; report-uri /fetch/metadata/resources/record-header.py?file=report-same-origin +Content-Security-Policy: style-src 'self' 'unsafe-inline'; report-uri https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=report-same-site +Content-Security-Policy: style-src 'self' 'unsafe-inline'; report-uri https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=report-cross-site diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html new file mode 100644 index 00000000000..18e8be78848 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.https.sub.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> + +<!-- Same-origin script --> +<script src="https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, "script"); + }, "Same-origin script"); +</script> + +<!-- Same-site script --> +<script src="https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, "script"); + }, "Same-site script"); +</script> + +<!-- Cross-site script --> +<script src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, "script"); + }, "Cross-site script"); +</script> + +<!-- Same-origin script, CORS mode --> +<script src="https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/echo-as-script.py" crossorigin="anonymous"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, "script"); + }, "Same-origin CORS script"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.sub.html new file mode 100644 index 00000000000..0512dc676aa --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/script.tentative.sub.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> + +<!-- Same-origin script --> +<script src="http://{{host}}:{{ports[http][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, ""); + }, "Non-secure same-origin script => No headers"); +</script> + +<!-- Same-site script --> +<script src="http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, ""); + }, "Non-secure same-site script => No headers"); +</script> + +<!-- Cross-site script --> +<script src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/metadata/resources/echo-as-script.py"></script> +<script> + test(t => { + t.add_cleanup(_ => { header = null; }); + + assert_header_dest_equals(header, ""); + }, "Non-secure cross-site script => No headers"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html new file mode 100644 index 00000000000..1faee65bf07 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/serviceworker.tentative.https.sub.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<!-- + This test verifies presence of Sec-Fetch-... request headers on a request + that fetches the service worker script itself (i.e. the script at the URL + passed as an argument to navigator.serviceWorker.register). +--> +<meta charset="utf-8"/> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> + <script> + promise_test(async t => { + const nonce = token(); + const key = "serviceworker-same-origin" + nonce; + + // Register a service worker and check the request header. + const registration = await navigator.serviceWorker.register('https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=' + key); + t.add_cleanup(() => registration.unregister()); + await retrieve_and_assert_headers(key, 'Register service worker'); + + // Trigger an update check and check the request header again. + await registration.update(); + await retrieve_and_assert_headers(key, 'Update service worker'); + }, 'metadata for service worker scripts'); + + async function retrieve_and_assert_headers(key, tag) { + const response = await fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + const text = await response.text(); + assert_header_dest_equals(text, "serviceworker", tag); + } + </script> +</body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html new file mode 100644 index 00000000000..882572c86fe --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/sharedworker.tentative.https.sub.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<script> + let nonce = token(); + let key = "sharedworker-same-origin" + nonce; + + // TESTS // + if (window.Worker) { + + // Same-Origin test + var sharedWorker = new SharedWorker('/fetch/metadata/resources/record-header.py?file=' + key); + sharedWorker.port.start(); + + sharedWorker.onerror = function(){ + test_same_origin(); + } + sharedWorker.port.onmessage = function(e) { + test_same_origin(); + } + sharedWorker.port.postMessage("Ready"); + } + + function test_same_origin(){ + promise_test(t => { + return new Promise((resolve, reject) => { + fetch_record_header_with_catch(key, "sharedworker", assert_header_dest_equals, resolve, reject); + }) + }, "Same-Origin sharedworker") + } +</script> +<body></body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html new file mode 100644 index 00000000000..ed30c81c7dd --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/style.tentative.https.sub.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body></body> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "style-same-origin" + nonce; + + let e = document.createElement('link'); + e.rel = "stylesheet"; + e.href = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "style", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin style"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "style-same-site" + nonce; + + let e = document.createElement('link'); + e.rel = "stylesheet"; + e.href = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "style", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Site style"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "style-cross-site" + nonce; + + let e = document.createElement('link'); + e.rel = "stylesheet"; + e.href = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.onload = e => { + fetch_record_header_with_catch(key, "style", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Cross-Site style"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "style-same-origin-cors" + nonce; + + let e = document.createElement('link'); + e.rel = "stylesheet"; + e.href = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + e.crossOrigin = "anonymous"; + e.onload = e => { + fetch_record_header_with_catch(key, "style", assert_header_dest_equals, resolve, reject); + }; + + document.body.appendChild(e); + }) + }, "Same-Origin, cors style"); +</script> +</html> + diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html new file mode 100644 index 00000000000..09e927f1a7c --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/track.tentative.https.sub.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +</body> +<script> + let nonce = token(); + + function createVideoElement() { + let el = document.createElement('video'); + el.src = "/media/movie_5.mp4"; + el.setAttribute("controls", ""); + el.setAttribute("crossorigin", ""); + return el; + } + + function createTrack() { + let el = document.createElement("track"); + el.setAttribute("default", ""); + el.setAttribute("kind", "captions"); + el.setAttribute("srclang", "en"); + return el; + } + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "track-same-origin" + nonce; + let video = createVideoElement(); + let el = createTrack(); + el.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + el.onload = t.step_func(_ => { + fetch_record_header_with_catch(key, "track", assert_header_dest_equals, resolve, reject); + }); + video.appendChild(el); + document.body.appendChild(video); + }); + }, "Same-Origin track"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "track-same-site" + nonce; + let video = createVideoElement(); + let el = createTrack(); + el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + el.onload = t.step_func(_ => { + fetch_record_header_with_catch(key, "track", assert_header_dest_equals, resolve, reject); + }); + video.appendChild(el); + document.body.appendChild(video); + }); + }, "Same-Site track"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "track-cross-site" + nonce; + let video = createVideoElement(); + let el = createTrack(); + el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + el.onload = t.step_func(_ => { + fetch_record_header_with_catch(key, "track", assert_header_dest_equals, resolve, reject); + }); + video.appendChild(el); + document.body.appendChild(video); + }); + }, "Cross-Site track"); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "track-same-origin-cors" + nonce; + let video = createVideoElement(); + + // Unset `crossorigin` to change the CORS mode: + video.crossOrigin = undefined; + + let el = createTrack(); + el.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; + el.onload = t.step_func(_ => { + fetch_record_header_with_catch(key, "track", assert_header_dest_equals, resolve, reject); + }); + video.appendChild(el); + document.body.appendChild(video); + }); + }, "Same-Origin, CORS track"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html new file mode 100644 index 00000000000..283b928e921 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/trailing-dot.tentative.https.sub.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script> + // Site + promise_test(t => { + return fetch("https://{{host}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => { + assert_header_dest_equals(j, "empty"); + }); + }, "Fetching a resource from the same origin, but spelled with a trailing dot."); + + promise_test(t => { + return fetch("https://{{hosts[][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => { + assert_header_dest_equals(j, "empty"); + }); + }, "Fetching a resource from the same site, but spelled with a trailing dot."); + + promise_test(t => { + return fetch("https://{{hosts[alt][www]}}.:{{ports[https][0]}}/fetch/metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => { + assert_header_dest_equals(j, "empty"); + }); + }, "Fetching a resource from a cross-site host, spelled with a trailing dot."); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html new file mode 100644 index 00000000000..a702fb83d59 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/unload.tentative.https.sub.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<body> +<script> + // The test + // 1. Creates a same-origin iframe + // 2. Adds to the iframe an unload handler that will + // trigger a request to <unload_request_url>/.../record-header.py... + // 3. Navigate the iframe to a cross-origin url (to data: url) + // 4. Waits until the request goes through + // 5. Verifies Sec-Fetch-Site request header of the request. + // + // This is a regression test for https://crbug.com/986577. + function create_test(unload_request_origin, expectation) { + async_test(t => { + // STEP 1: Create an iframe. + let nonce = token(); + let key = "unload-test-" + nonce; + let url = unload_request_origin + + "/fetch/metadata/resources/record-header.py?file=" + key; + let i = document.createElement('iframe'); + i.src = '/fetch/metadata/resources/unload-with-beacon.html'; + i.onload = () => { + // STEP 2: Ask the iframe to add an unload handler. + i.contentWindow.postMessage(url, '*'); + }; + window.addEventListener('message', e => { + // STEP 3: Navigate the iframe away + i.contentWindow.location = 'data:text/html,DONE'; + }); + document.body.appendChild(i); + + // STEPS 4 and 5: Wait for the beacon to go through and verify + // the request headers. + function wait_and_verify() { + t.step_timeout(() => { + let callback_method = text => t.step(() => { + if (text == "No header has been recorded") { + wait_and_verify(); + return; + } + assert_header_dest_equals(text, expectation); + t.done(); + }); + fetch_record_header(key, expectation, callback_method); + }, 200); + } + wait_and_verify(); + }, "Fetch from an unload handler"); + } + + create_test("https://{{host}}:{{ports[https][0]}}", "empty"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html new file mode 100644 index 00000000000..650ba6afa16 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/window-open.tentative.https.sub.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<body> +<script> + // Forced navigations: + async_test(t => { + let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }, "Same-origin window, forced"); + + async_test(t => { + let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }, "Same-site window, forced"); + + async_test(t => { + let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }, "Cross-site window, forced"); + + async_test(t => { + let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + let messages = 0; + window.addEventListener('message', t.step_func(e => { + messages++; + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + + if (messages == 1) { + w.location.reload(); + } else { + t.done(); + } + })); + }, "Same-origin window, forced, reloaded"); + + async_test(t => { + let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + let messages = 0; + window.addEventListener('message', t.step_func(e => { + messages++; + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + + if (messages == 1) { + w.location.reload(); + } else { + t.done(); + } + })); + }, "Same-site window, forced, reloaded"); + + async_test(t => { + let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + let messages = 0; + window.addEventListener('message', t.step_func(e => { + messages++; + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + + if (messages == 1) { + w.location.reload(); + } else { + t.done(); + } + })); + }, "Cross-site window, forced, reloaded"); + + // User-activated navigations: + async_test(t => { + let b = document.createElement('button'); + b.onclick = t.step_func(_ => { + let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }); + document.body.appendChild(b); + test_driver.click(b); + }, "Same-origin window, user-activated"); + + async_test(t => { + let b = document.createElement('button'); + b.onclick = t.step_func(_ => { + let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }); + document.body.appendChild(b); + test_driver.click(b); + }, "Same-site window, user-activated"); + + async_test(t => { + let b = document.createElement('button'); + b.onclick = t.step_func(_ => { + let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py"); + t.add_cleanup(_ => w.close()); + window.addEventListener('message', t.step_func(e => { + if (e.source != w) + return; + + assert_header_dest_equals(e.data, "document"); + t.done(); + })); + }); + document.body.appendChild(b); + test_driver.click(b); + }, "Cross-site window, user-activated"); +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html new file mode 100644 index 00000000000..8e40fb621e2 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/worker.tentative.https.sub.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<script> + let nonce = token(); + + promise_test(t => { + return new Promise((resolve, reject) => { + let key = "worker-same-origin" + nonce; + let w = new Worker("/fetch/metadata/resources/record-header.py?file=" + key); + w.onmessage = e => { + fetch_record_header_with_catch(key, "worker", assert_header_dest_equals, resolve, reject); + }; + }); + }, "Same-Origin worker"); +</script> +<body></body> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html new file mode 100644 index 00000000000..df44514fa1f --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/metadata/sec-fetch-dest/xslt.tentative.https.sub.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> + +<link rel="author" href="mtrzos@google.com" title="Maciek Trzos"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/metadata/resources/helper.js></script> +<script src=/common/utils.js></script> +<script> + // Open a window with XML document which loads resources via <?xml-stylesheet/> tag + let nonce = token(); + let w = window.open("/fetch/metadata/resources/xslt-test.sub.xml?token=" + nonce); + window.addEventListener('message', function(e) { + if (e.source != w) + return; + + promise_test(t => { + return fetch_record_header("xslt-same-origin" + nonce, "xslt", assert_header_dest_equals); + }, "Same-Origin xslt"); + + promise_test(t => { + return fetch_record_header("xslt-same-site" + nonce, "xslt", assert_header_dest_equals); + }, "Same-site xslt"); + + promise_test(t => { + return fetch_record_header("xslt-cross-site" + nonce, "xslt", assert_header_dest_equals); + }, "Cross-site xslt"); + + w.close(); + }); + +</script> diff --git a/tests/wpt/web-platform-tests/fetch/metadata/serviceworker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/serviceworker.tentative.https.sub.html index 6fdb37a7f69..1fbdee4f091 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/serviceworker.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/serviceworker.tentative.https.sub.html @@ -27,8 +27,8 @@ }, 'metadata for service worker scripts'); async function retrieve_and_assert_headers(key, tag) { - let expected = { "dest": "serviceworker", "site": "same-origin", "user": "", "mode": "same-origin" }; - const response = await fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) + let expected = { "site": "same-origin", "user": "", "mode": "same-origin" }; + const response = await fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key); const text = await response.text(); assert_header_equals(text, expected, tag); } diff --git a/tests/wpt/web-platform-tests/fetch/metadata/sharedworker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/sharedworker.tentative.https.sub.html index 90144156ee4..0408c44201f 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/sharedworker.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/sharedworker.tentative.https.sub.html @@ -28,7 +28,7 @@ function test_same_origin(){ promise_test(t => { return new Promise((resolve, reject) => { - let expected = {"dest":"sharedworker", "site":"same-origin", "user":"", "mode": "same-origin"}; + let expected = {"site":"same-origin", "user":"", "mode": "same-origin"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/style.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/style.tentative.https.sub.html index 1f875e8c510..08ac184b421 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/style.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/style.tentative.https.sub.html @@ -17,7 +17,7 @@ e.rel = "stylesheet"; e.href = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -37,7 +37,7 @@ e.rel = "stylesheet"; e.href = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -57,7 +57,7 @@ e.rel = "stylesheet"; e.href = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.onload = e => { - let expected = {"dest":"style", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) @@ -78,7 +78,7 @@ e.href = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; e.crossOrigin = "anonymous"; e.onload = e => { - let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "cors"}; + let expected = {"site":"same-origin", "user":"", "mode": "cors"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/track.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/track.tentative.https.sub.html index 63d76372e03..11e45e23efd 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/track.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/track.tentative.https.sub.html @@ -34,7 +34,6 @@ el.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; el.onload = t.step_func(_ => { expected = { - "dest": "track", "site": "same-origin", "user": "", "mode": "cors" // Because the `video` element has `crossorigin` @@ -57,7 +56,6 @@ el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; el.onload = t.step_func(_ => { expected = { - "dest": "track", "site": "same-site", "user": "", "mode": "cors" // Because the `video` element has `crossorigin` @@ -82,7 +80,6 @@ el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; el.onload = t.step_func(_ => { expected = { - "dest": "track", "site": "cross-site", "user": "", "mode": "cors" // Because the `video` element has `crossorigin` @@ -110,7 +107,6 @@ el.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/record-header.py?file=" + key; el.onload = t.step_func(_ => { expected = { - "dest":"track", "site":"same-origin", "user":"", "mode": "same-origin" diff --git a/tests/wpt/web-platform-tests/fetch/metadata/trailing-dot.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/trailing-dot.tentative.https.sub.html index f1a0ad1b485..f7069e72255 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/trailing-dot.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/trailing-dot.tentative.https.sub.html @@ -9,7 +9,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", @@ -22,7 +21,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", @@ -35,7 +33,6 @@ .then(r => r.json()) .then(j => { assert_header_equals(j, { - "dest": "empty", "site": "cross-site", "user": "", "mode": "cors", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/unload.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/unload.tentative.https.sub.html index c93ecab3197..8917c53a3b3 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/unload.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/unload.tentative.https.sub.html @@ -56,7 +56,6 @@ } create_test("https://{{host}}:{{ports[https][0]}}", { - "dest": "empty", "site": "same-origin", "user": "", "mode": "no-cors" diff --git a/tests/wpt/web-platform-tests/fetch/metadata/window-open.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/window-open.tentative.https.sub.html index 79f1eec8542..29c325f1213 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/window-open.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/window-open.tentative.https.sub.html @@ -15,7 +15,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-origin", "user": "", "mode": "navigate", @@ -32,7 +31,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-site", "user": "", "mode": "navigate", @@ -49,7 +47,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "cross-site", "user": "", "mode": "navigate", @@ -68,7 +65,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-origin", "user": "", "mode": "navigate", @@ -92,7 +88,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-site", "user": "", "mode": "navigate", @@ -116,7 +111,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "cross-site", "user": "", "mode": "navigate", @@ -141,7 +135,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-origin", "user": "?1", "mode": "navigate", @@ -163,7 +156,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "same-site", "user": "?1", "mode": "navigate", @@ -185,7 +177,6 @@ return; assert_header_equals(e.data, { - "dest": "document", "site": "cross-site", "user": "?1", "mode": "navigate", diff --git a/tests/wpt/web-platform-tests/fetch/metadata/worker.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/worker.tentative.https.sub.html index df1abc4bbca..d2162d5bc7a 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/worker.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/worker.tentative.https.sub.html @@ -13,7 +13,7 @@ let key = "worker-same-origin" + nonce; let w = new Worker("/fetch/metadata/resources/record-header.py?file=" + key); w.onmessage = e => { - let expected = {"dest":"worker", "site":"same-origin", "user":"", "mode": "same-origin"}; + let expected = {"site":"same-origin", "user":"", "mode": "same-origin"}; fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=" + key) .then(response => response.text()) .then(text => assert_header_equals(text, expected)) diff --git a/tests/wpt/web-platform-tests/fetch/metadata/xslt.tentative.https.sub.html b/tests/wpt/web-platform-tests/fetch/metadata/xslt.tentative.https.sub.html index 6e4f186d55c..5fc647b3ae7 100644 --- a/tests/wpt/web-platform-tests/fetch/metadata/xslt.tentative.https.sub.html +++ b/tests/wpt/web-platform-tests/fetch/metadata/xslt.tentative.https.sub.html @@ -14,21 +14,21 @@ return; promise_test(t => { - let expected = {"dest":"xslt", "site":"same-origin", "user":"", "mode": "same-origin"}; + let expected = {"site":"same-origin", "user":"", "mode": "same-origin"}; return fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin" + nonce) .then(response => response.text()) .then(text => assert_header_equals(text, expected)); }, "Same-Origin xslt"); promise_test(t => { - let expected = {"dest":"xslt", "site":"same-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"same-site", "user":"", "mode": "no-cors"}; return fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=xslt-same-site" + nonce) .then(response => response.text()) .then(text => assert_header_equals(text, expected)); }, "Same-site xslt"); promise_test(t => { - let expected = {"dest":"xslt", "site":"cross-site", "user":"", "mode": "no-cors"}; + let expected = {"site":"cross-site", "user":"", "mode": "no-cors"}; return fetch("/fetch/metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site" + nonce) .then(response => response.text()) .then(text => assert_header_equals(text, expected)); diff --git a/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html b/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html index 72aec0b7542..f16a18d639c 100644 --- a/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html +++ b/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects.html @@ -148,6 +148,9 @@ addTest(function(win) { assert_throws("SecurityError", function() { win.location.pathname; }, "location.pathname throws cross-origin"); assert_equals(B.frames, 'override', "Overrides visible in the same-origin case"); assert_equals(win.frames, win, "Overrides invisible in the cross-origin case"); + assert_equals(B.focus, 'override', "Overrides visible in the same-origin case"); + checkFunction(win.focus, Function.prototype); + assert_not_equals(win.focus, focus, "Overrides invisible in the cross-origin case"); }, "Basic sanity-checking"); /* diff --git a/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/frame.html b/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/frame.html index 3226c871931..ca2dd8ebf82 100644 --- a/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/frame.html +++ b/tests/wpt/web-platform-tests/html/browsers/origin/cross-origin-objects/frame.html @@ -6,9 +6,10 @@ document.domain = document.domain; } - // Override the |frames| property to test that such overrides are + // Override the |frames| and |focus| property to test that such overrides are // properly ignored cross-origin. window.frames = "override"; + window.focus = "override"; // Also add a |then| property to test that it doesn't get exposed. window.then = "something"; diff --git a/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html new file mode 100644 index 00000000000..2acad0734cd --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-npo.html @@ -0,0 +1,38 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access across globals</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.src = "cross-global-support.html"; + document.body.appendChild(iframe); + iframe.onload = this.step_func_done(function() { + var name = "named"; + var win = iframe.contentWindow; + var element = win.document.getElementById(name); + + var expectedValues = [ + // [value, is own property] + [element, false, "window"], + [element, false, "Window.prototype"], + [element, true, "named prototype object"], + [undefined, false, "EventTarget.prototype"], + [undefined, false, "Object.prototype"], + ]; + for (var object = win; object; object = Object.getPrototypeOf(object)) { + var expected = expectedValues.shift(); + assert_equals(object[name], expected[0], "[[Get]] on " + expected[2]); + var desc = Object.getOwnPropertyDescriptor(object, name); + if (expected[1]) { + assert_not_equals(desc, undefined, "[[GetOwnProperty]] on " + expected[2] + " should return something"); + assert_equals(desc.value, element, "[[GetOwnProperty]] on " + expected[2]); + } else { + assert_equals(desc, undefined, "[[GetOwnProperty]] on " + expected[2]); + } + } + }); +}); +</script> diff --git a/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html new file mode 100644 index 00000000000..9d7b9f8a25e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/cross-global-support.html @@ -0,0 +1,4 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access across globals: support file</title> +<span id="named"></span> diff --git a/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html new file mode 100644 index 00000000000..910374381be --- /dev/null +++ b/tests/wpt/web-platform-tests/html/browsers/the-window-object/named-access-on-the-window-object/prototype.html @@ -0,0 +1,94 @@ +<!doctype html> +<meta charset=utf-8> +<title>Named access with shadowing properties</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var name = "named1"; + window[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name).value, "shadowing"); + + assert_equals(Window.prototype[name], element); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], element); + assert_equals(Object.getOwnPropertyDescriptor(npo, name).value, element); + + assert_equals(EventTarget.prototype[name], undefined); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); +}, "Property on window."); + +test(function() { + var name = "named2"; + Window.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name).value, "shadowing"); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], element); + assert_equals(Object.getOwnPropertyDescriptor(npo, name).value, element); + + assert_equals(EventTarget.prototype[name], undefined); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); +}, "Property on Window.prototype."); + +test(function() { + var name = "named3"; + EventTarget.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(npo, name), undefined); + + assert_equals(EventTarget.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name).value, "shadowing"); +}, "Property on EventTarget.prototype."); + +test(function() { + var name = "named4"; + Object.prototype[name] = "shadowing"; + var element = document.createElement("span"); + element.id = name; + document.body.appendChild(element); + + assert_equals(window[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(window, name), undefined); + + assert_equals(Window.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Window.prototype, name), undefined); + + var npo = Object.getPrototypeOf(Window.prototype); + assert_equals(npo[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(npo, name), undefined); + + assert_equals(EventTarget.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(EventTarget.prototype, name), undefined); + + assert_equals(Object.prototype[name], "shadowing"); + assert_equals(Object.getOwnPropertyDescriptor(Object.prototype, name).value, "shadowing"); +}, "Property on Object.prototype."); +</script> diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html index d245bf0b964..5ffe53c308e 100644 --- a/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html @@ -8,7 +8,7 @@ async_test(function(t) { var obj = document.createElement("iframe"); obj.onload = t.step_func_done(function(e){ - assert_true(obj.contentWindow instanceof Window, "The iframe element should represent a nested browsing context.") + assert_not_equals(obj.contentWindow, null, "The iframe element should represent a nested browsing context.") assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface."); assert_true(e.isTrusted, "The load event should be a trusted event."); assert_false(e.cancelable, "The load event should not be a cancelable event."); @@ -16,9 +16,7 @@ async_test(function(t) { assert_equals(e.target, obj, "The load event target should be the corresponding object element."); }); - obj.onerror = t.step_func_done(function(e){ - assert_unreached("The error event should not be fired."); - }); + obj.onerror = t.unreached_func("The error event should not be fired."); var url = URL.createObjectURL(new Blob([""], { type: "text/html" })); @@ -29,7 +27,7 @@ async_test(function(t) { async_test(function(t) { var obj = document.createElement("iframe"); obj.onload = t.step_func_done(function(e){ - assert_true(obj.contentWindow instanceof Window, "The object element should represent a nested browsing context.") + assert_not_equals(obj.contentWindow, null, "The object element should represent a nested browsing context.") assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface."); assert_true(e.isTrusted, "The load event should be a trusted event."); assert_false(e.cancelable, "The load event should not be a cancelable event."); @@ -37,12 +35,9 @@ async_test(function(t) { assert_equals(e.target, obj, "The load event target should be the corresponding object element."); }); - obj.onerror = t.step_func_done(function(e){ - assert_unreached("The error event should not be fired."); - }); + obj.onerror = t.unreached_func("The error event should not be fired."); document.body.appendChild(obj); }, "load event of initial about:blank"); - </script> </body> diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-2.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-2.html new file mode 100644 index 00000000000..f0c9471a704 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-2.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- The onclick submit() should *not* get superseded in this case by the + default action submit(), because onclick here calls preventDefault(). + --> + + + + +<label for=frame1 style="display:block">This frame should stay blank</label> +<iframe name=frame1 id=frame1></iframe> +<label for=frame2 style="display:block">This frame should navigate (to 404)</label> +<iframe name=frame2 id=frame2></iframe> +<form id="form1" target="frame2" action="nonexistent.html"> + <input type=hidden name=navigated value=1> + <input id=submitbutton type=submit> +</form> + +<script> +let frame1 = document.getElementById('frame1'); +let frame2 = document.getElementById('frame2'); + +async_test(t => { + window.addEventListener('load', () => { + frame1.addEventListener('load', t.step_func_done(() => { + assert_unreached("Frame1 should not get navigated by this test."); + })); + frame2.addEventListener('load', t.step_func_done(() => { + let params = (new URL(frame2.contentWindow.location)).searchParams; + let wasNavigated = !!params.get("navigated"); + assert_true(wasNavigated); + })); + form1.addEventListener('click', t.step_func(() => { + form1.submit(); + form1.target='frame1'; + event.preventDefault(); // Prevent default here + })); + submitbutton.click(); + }); +}, 'preventDefault should allow onclick submit() to succeed'); +</script> diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-3.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-3.html new file mode 100644 index 00000000000..1bad23260d0 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-3.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- <button> should have the same double-submit protection that + <input type=submit> has. + --> + + + + +<label for=frame1 style="display:block">This frame should stay blank</label> +<iframe name=frame1 id=frame1></iframe> +<label for=frame2 style="display:block">This frame should navigate (to 404)</label> +<iframe name=frame2 id=frame2></iframe> +<form id="form1" target="frame1" action="nonexistent.html"> + <input type=hidden name=navigated value=1> + <button id=submitbutton>submit</button> +</form> + +<script> +let frame1 = document.getElementById('frame1'); +let frame2 = document.getElementById('frame2'); + +async_test(t => { + window.addEventListener('load', () => { + frame1.addEventListener('load', t.step_func_done(() => { + assert_unreached("Frame1 should not get navigated by this test."); + })); + frame2.addEventListener('load', t.step_func_done(() => { + let params = (new URL(frame2.contentWindow.location)).searchParams; + let wasNavigated = !!params.get("navigated"); + assert_true(wasNavigated) + })); + form1.addEventListener('click', t.step_func(() => { + form1.submit(); + form1.target='frame2'; + + })); + submitbutton.click(); + }); +}, '<button> should have the same double-submit protection as <input type=submit>'); + +</script> diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit.html new file mode 100644 index 00000000000..1102e304174 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- The onclick submit() should get superseded by the default + action submit(), which isn't preventDefaulted by onclick here. + This is per the Form Submission Algorithm [1], step 22.3, which + says that new planned navigations replace old planned navigations. + [1] https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm + --> + +<label for=frame1 style="display:block">This frame should stay blank</label> +<iframe name=frame1 id=frame1></iframe> +<label for=frame2 style="display:block">This frame should navigate (to 404)</label> +<iframe name=frame2 id=frame2></iframe> +<form id="form1" target="frame1" action="nonexistent.html"> + <input type=hidden name=navigated value=1> + <input id=submitbutton type=submit> +</form> + +<script> +let frame1 = document.getElementById('frame1'); +let frame2 = document.getElementById('frame2'); + +async_test(t => { + window.addEventListener('load', () => { + frame1.addEventListener('load', t.step_func_done(() => { + assert_unreached("Frame1 should not get navigated by this test."); + })); + frame2.addEventListener('load', t.step_func_done(() => { + let params = (new URL(frame2.contentWindow.location)).searchParams; + let wasNavigated = !!params.get("navigated"); + assert_true(wasNavigated) + })); + form1.addEventListener('click', t.step_func(() => { + form1.submit(); + form1.target='frame2'; + + })); + submitbutton.click(); + }); +}, 'default submit action should supersede onclick submit()'); + +</script> diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js index 1d94de8a7c9..ba7278ef18a 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js +++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js @@ -1,28 +1,31 @@ -// document.open() bails out early if there is an **active parser** with -// non-zero script nesting level. window.stop() aborts the current parser and -// makes it no longer active, and should allow document.open() to work. -// For more details, see https://bugzilla.mozilla.org/show_bug.cgi?id=1475000. +// document.open() bails out early if there is an active parser with non-zero +// script nesting level or if a load was aborted while there was an active +// parser. window.stop() aborts the current parser, so once it has been called +// while a parser is active, document.open() will no longer do anything to that +// document, window.handlers = {}; async_test(t => { const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); frame.src = "resources/aborted-parser-frame.html"; window.handlers.afterOpen = t.step_func_done(() => { const openCalled = frame.contentDocument.childNodes.length === 0; - frame.remove(); - assert_true(openCalled, "child document should be empty"); + assert_false(openCalled, "child document should not be empty"); + assert_equals(frame.contentDocument.querySelector("p").textContent, + "Text", "Should still have our paragraph"); }); }, "document.open() after parser is aborted"); -// Note: This test should pass even if window.close() is not there, as -// document.open() is not executed synchronously in an inline script. async_test(t => { const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); frame.src = "resources/aborted-parser-async-frame.html"; window.handlers.afterOpenAsync = t.step_func_done(() => { const openCalled = frame.contentDocument.childNodes.length === 0; - frame.remove(); - assert_true(openCalled, "child document should be empty"); + assert_false(openCalled, "child document should not be empty"); + assert_equals(frame.contentDocument.querySelector("p").textContent, + "Text", "Should still have our paragraph"); }); }, "async document.open() after parser is aborted"); diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html new file mode 100644 index 00000000000..a3bdd86ee6e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html @@ -0,0 +1,31 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<body> + <script> + var t = async_test("Location sets should cancel current navigation and prevent later document.open() from doing anything"); + + var finishTest = t.step_func_done(function() { + assert_equals(frames[0].document.body.textContent, "PASS", + "Should not have FAIL in our textContent"); + }); + + t.step(function() { + var i = document.createElement("iframe"); + i.srcdoc = ` + <script> + var blob = new Blob(["PASS"], { type: "text/html" }); + var url = URL.createObjectURL(blob); + location.href = url; + frameElement.onload = parent.finishTest; + document.open(); + document.write("FAIL"); + document.close(); + <\/script>`; + document.body.appendChild(i); + }); + + </script> +</body> diff --git a/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html b/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html index 627a2f3e5a7..d61618a53ef 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html +++ b/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html @@ -10,20 +10,82 @@ <script> 'use strict'; +setup({ + allow_uncaught_exception: true +}); + (function() { var resolveLoaded; var loadedPromise = new Promise(function(resolve) { resolveLoaded = resolve; }); - async_test(function(t) { - addEventListener('unhandledrejection', t.unreached_func('unhandledrejection event should never be triggered')); - addEventListener('rejectionhandled', t.unreached_func('rejectionhandled event should never be triggered')); + promise_test(function(t) { + var unreachedUnhandled = t.unreached_func('unhandledrejection event should never be triggered'); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); + + addEventListener('unhandledrejection', unreachedUnhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unreachedUnhandled, unreachedHandled); + + return loadedPromise.then(t.step_func(function() { + return new Promise(function(resolve) { + t.step_timeout(function() { + resolve(); + }, 1000); + }); + })); + }, 'Promise rejection event should be muted for cross-origin non-CORS script'); + + promise_test(function(t) { + var unreachedUnhandled = t.unreached_func('unhandledrejection event should never be triggered'); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); - loadedPromise.then(t.step_func(function() { + addEventListener('unhandledrejection', unreachedUnhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unreachedUnhandled, unreachedHandled); + + return new Promise(function(resolve) { + handleRejectedPromise(new Promise(function(resolve, reject) { reject(42); })); t.step_timeout(function() { - t.done(); + resolve(); }, 1000); + }); + }, 'Promise rejection should be muted if the rejected promise is handled in cross-origin non-CORS script'); + + promise_test(function(t) { + var promise = new Promise(function(resolve, reject) { reject(42); }); + var resolveReceived; + var eventPromise = new Promise(function(resolve) { resolveReceived = resolve; }); + var unhandled = t.step_func(function(e) { + if (e.promise === promise) { + handleRejectedPromise(promise); + resolveReceived(); + } + }); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); + + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unhandled, unreachedHandled); + + return eventPromise.then(t.step_func(function() { + return new Promise(function(resolve) { + t.step_timeout(function() { + resolve(); + }, 1000); + }); })); - }, 'Promise rejection event should be muted for cross-origin non-CORS script'); + }, 'Promise rejection should be muted if the rejected promise is handled in unhandledrejection event handler in cross-origin non-CORS script'); + + function ensureCleanup(t, unhandled, handled) { + t.add_cleanup(function() { + if (unhandled) { + removeEventListener('unhandledrejection', unhandled); + } + if (handled) { + removeEventListener('rejectionhandled', handled); + } + }); + } var scriptEl = document.createElement('script'); scriptEl.src = CROSSDOMAIN + 'support/promise-access-control.py?allow=false'; diff --git a/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py b/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py index 3e897bccdce..be74a36034e 100644 --- a/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py +++ b/tests/wpt/web-platform-tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py @@ -5,6 +5,14 @@ def main(request, response): if allow != "false": headers.append(("Access-Control-Allow-Origin", "*")) - body = "new Promise(function(resolve, reject) { reject(42); })" + body = """ + function handleRejectedPromise(promise) { + promise.catch(() => {}); + } + + (function() { + new Promise(function(resolve, reject) { reject(42); }); + })(); + """ return headers, body diff --git a/tests/wpt/web-platform-tests/import-maps/@std/__dir__.headers b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/__dir__.headers index e7ec0d6699d..e7ec0d6699d 100644 --- a/tests/wpt/web-platform-tests/import-maps/@std/__dir__.headers +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/__dir__.headers diff --git a/tests/wpt/web-platform-tests/import-maps/@std/blank b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/blank index 38e1891bf7d..38e1891bf7d 100644 --- a/tests/wpt/web-platform-tests/import-maps/@std/blank +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/blank diff --git a/tests/wpt/web-platform-tests/import-maps/@std/none b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/none index 69e165cce5e..69e165cce5e 100644 --- a/tests/wpt/web-platform-tests/import-maps/@std/none +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/@std/none diff --git a/tests/wpt/web-platform-tests/import-maps/bare.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare.sub.tentative.html index cf99589f9bd..e20424aed8a 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare.sub.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare.sub.tentative.html @@ -2,7 +2,7 @@ <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> // "bare/..." (i.e. without leading "./") are bare specifiers @@ -15,16 +15,10 @@ const importMap = ` { "imports": { - "bare/bare": "./resources/log.js?pipe=sub&name=bare", - "bare/cross-origin-bare": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bare", - "bare/to-data": "data:text/javascript,log.push('dataURL')", - "bare/std-blank": "std:blank", "bare/blank": "@std/blank", "bare/std-none": "std:none", - "bare/none": "@std/none", - - "bare/to-bare": "bare/bare" + "bare/none": "@std/none" } } `; @@ -41,16 +35,6 @@ const tests = { // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR // below. https://crbug.com/928435 - // Bare to HTTP(S). - "bare/bare": - [Result.URL, Result.URL, "log:bare", "log:bare"], - "bare/cross-origin-bare": - [Result.URL, Result.URL, "log:cross-origin-bare", "log:cross-origin-bare"], - - // Bare to data: - "bare/to-data": - [Result.URL, Result.URL, "dataURL", "dataURL"], - // Bare to built-in. "bare/std-blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], @@ -60,10 +44,6 @@ const tests = { [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], "bare/none": [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], - - // Bare to bare mapping is disabled. - "bare/to-bare": - [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], }; doTests(importMap, null, tests); diff --git a/tests/wpt/web-platform-tests/import-maps/bare/__dir__.headers b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/__dir__.headers index e7ec0d6699d..e7ec0d6699d 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/__dir__.headers +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/__dir__.headers diff --git a/tests/wpt/web-platform-tests/import-maps/bare/blank b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/blank index 841d433acf7..841d433acf7 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/blank +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/blank diff --git a/tests/wpt/web-platform-tests/import-maps/bare/none b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/none index 2aec0d72826..2aec0d72826 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/none +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/none diff --git a/tests/wpt/web-platform-tests/import-maps/bare/std-blank b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/std-blank index 5ded98fd382..5ded98fd382 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/std-blank +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/std-blank diff --git a/tests/wpt/web-platform-tests/import-maps/bare/std-none b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/std-none index 1437d9ff1e0..1437d9ff1e0 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/std-none +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/bare/std-none diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-empty.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin-empty.tentative.html index aba28d18e04..9ede75a4c42 100644 --- a/tests/wpt/web-platform-tests/import-maps/builtin-empty.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin-empty.tentative.html @@ -1,16 +1,16 @@ <!DOCTYPE html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> const importMap = ` { "imports": { - "./resources/log.js?pipe=sub&name=empty": [ "@std/" ], - "./resources/log.js?pipe=sub&name=empty-fallback": [ + "../resources/log.js?pipe=sub&name=empty": [ "@std/" ], + "../resources/log.js?pipe=sub&name=empty-fallback": [ "@std/", - "./resources/log.js?pipe=sub&name=empty-fallback" + "../resources/log.js?pipe=sub&name=empty-fallback" ] } } @@ -32,9 +32,9 @@ const tests = { "@std/": [Result.FETCH_ERROR, Result.PARSE_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR], - "./resources/log.js?pipe=sub&name=empty": + "../resources/log.js?pipe=sub&name=empty": [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], - "./resources/log.js?pipe=sub&name=empty-fallback": + "../resources/log.js?pipe=sub&name=empty-fallback": [Result.URL, Result.URL, Result.URL, Result.URL], }; diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-import-scheme.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin-import-scheme.tentative.html index 6a27ef5aee2..d9977ae3535 100644 --- a/tests/wpt/web-platform-tests/import-maps/builtin-import-scheme.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin-import-scheme.tentative.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> const tests = { diff --git a/tests/wpt/web-platform-tests/import-maps/builtin.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin.tentative.html index e85289e4d88..497bb5c606b 100644 --- a/tests/wpt/web-platform-tests/import-maps/builtin.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/builtin.tentative.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> const tests = { diff --git a/tests/wpt/web-platform-tests/import-maps/data.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/data.sub.tentative.html index 634948942ee..0377a788491 100644 --- a/tests/wpt/web-platform-tests/import-maps/data.sub.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/data.sub.tentative.html @@ -2,7 +2,7 @@ <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> // "bare/..." (i.e. without leading "./") are bare specifiers @@ -15,18 +15,10 @@ const importMap = ` { "imports": { - "bare": "./resources/log.js?pipe=sub&name=bare", - - "data:text/javascript,log.push('data:foo')": "./resources/log.js?pipe=sub&name=foo", - "data:text/javascript,log.push('data:cross-origin-foo')": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo", - "data:text/javascript,log.push('data:to-data')": "data:text/javascript,log.push('dataURL')", - "data:text/javascript,log.push('data:std-blank')": "std:blank", "data:text/javascript,log.push('data:blank')": "@std/blank", "data:text/javascript,log.push('data:std-none')": "std:none", - "data:text/javascript,log.push('data:none')": "@std/none", - - "data:text/javascript,log.push('data:to-bare')": "bare" + "data:text/javascript,log.push('data:none')": "@std/none" } } `; @@ -43,16 +35,6 @@ const tests = { // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR // below. https://crbug.com/928435 - // data: to HTTP(S). - "data:text/javascript,log.push('data:foo')": - [Result.URL, Result.URL, "log:foo", "log:foo"], - "data:text/javascript,log.push('data:cross-origin-foo')": - [Result.URL, Result.URL, "log:cross-origin-foo", "log:cross-origin-foo"], - - // data: to data: - "data:text/javascript,log.push('data:to-data')": - [Result.URL, Result.URL, "dataURL", "dataURL"], - // data: to built-in. "data:text/javascript,log.push('data:std-blank')": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], @@ -62,10 +44,6 @@ const tests = { [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], "data:text/javascript,log.push('data:none')": [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], - - // data: to bare mapping is disabled. - "data:text/javascript,log.push('data:to-bare')": - [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], }; doTests(importMap, null, tests); diff --git a/tests/wpt/web-platform-tests/import-maps/fallback-disallowed.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/fallback-disallowed.sub.tentative.html index 280d02d8473..7efe90eb751 100644 --- a/tests/wpt/web-platform-tests/import-maps/fallback-disallowed.sub.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/fallback-disallowed.sub.tentative.html @@ -2,7 +2,7 @@ <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> // Fallbacks from external URLs (such as HTTPS URLs) are @@ -18,51 +18,51 @@ const importMap = ` { "imports": { - "bare": "./resources/log.js?pipe=sub&name=bare", + "bare": "../resources/log.js?pipe=sub&name=bare", - "./resources/log.js?pipe=sub&name=http-to-builtin": [ - "./resources/log.js?pipe=sub&name=http-to-builtin", + "../resources/log.js?pipe=sub&name=http-to-builtin": [ + "../resources/log.js?pipe=sub&name=http-to-builtin", "@std/blank" ], - "./resources/log.js?pipe=sub&name=fallback-to-different-url-1": [ + "../resources/log.js?pipe=sub&name=fallback-to-different-url-1": [ "@std/blank", - "./resources/log.js?pipe=sub&name=something-different" + "../resources/log.js?pipe=sub&name=something-different" ], - "./resources/log.js?pipe=sub&name=fallback-to-different-url-2": [ + "../resources/log.js?pipe=sub&name=fallback-to-different-url-2": [ "@std/none", - "./resources/log.js?pipe=sub&name=something-different2" + "../resources/log.js?pipe=sub&name=something-different2" ], - "./resources/log.js?pipe=sub&name=fallback-to-different-origin-1": [ + "../resources/log.js?pipe=sub&name=fallback-to-different-origin-1": [ "@std/blank", "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-1" ], - "./resources/log.js?pipe=sub&name=fallback-to-different-origin-2": [ + "../resources/log.js?pipe=sub&name=fallback-to-different-origin-2": [ "@std/none", "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-2" ], - "./resources/log.js?pipe=sub&name=more-than-two-values-1": [ + "../resources/log.js?pipe=sub&name=more-than-two-values-1": [ "@std/none", "@std/blank", - "./resources/log.js?pipe=sub&name=more-than-two-values-1" + "../resources/log.js?pipe=sub&name=more-than-two-values-1" ], - "./resources/log.js?pipe=sub&name=more-than-two-values-2": [ + "../resources/log.js?pipe=sub&name=more-than-two-values-2": [ "@std/none", - "./resources/log.js?pipe=sub&name=more-than-two-values-2", + "../resources/log.js?pipe=sub&name=more-than-two-values-2", "@std/blank" ], - "./resources/log.js?pipe=sub&name=fallback-from-http": [ - "./resources/log.js?pipe=sub&name=non-built-in", - "./resources/log.js?pipe=sub&name=fallback-from-http" + "../resources/log.js?pipe=sub&name=fallback-from-http": [ + "../resources/log.js?pipe=sub&name=non-built-in", + "../resources/log.js?pipe=sub&name=fallback-from-http" ], - "./resources/log.js?pipe=sub&name=fallback-from-data-1": [ + "../resources/log.js?pipe=sub&name=fallback-from-data-1": [ "data:text/plain,", - "./resources/log.js?pipe=sub&name=fallback-from-http" + "../resources/log.js?pipe=sub&name=fallback-from-http" ], - "./resources/log.js?pipe=sub&name=fallback-from-data-2": [ + "../resources/log.js?pipe=sub&name=fallback-from-data-2": [ "data:text/javascript,log.push('dataURL')", - "./resources/log.js?pipe=sub&name=fallback-from-http" + "../resources/log.js?pipe=sub&name=fallback-from-http" ] } } diff --git a/tests/wpt/web-platform-tests/import-maps/fallback.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/fallback.sub.tentative.html index 3f4f2887da8..45cf6dc1ced 100644 --- a/tests/wpt/web-platform-tests/import-maps/fallback.sub.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/fallback.sub.tentative.html @@ -2,7 +2,7 @@ <meta name="timeout" content="long"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> // This tests is for fallbacks with the pattern of @@ -16,13 +16,13 @@ const importMap = ` { "imports": { - "./resources/log.js?pipe=sub&name=blank": [ + "../resources/log.js?pipe=sub&name=blank": [ "@std/blank", - "./resources/log.js?pipe=sub&name=blank" + "../resources/log.js?pipe=sub&name=blank" ], - "./resources/log.js?pipe=sub&name=none": [ + "../resources/log.js?pipe=sub&name=none": [ "@std/none", - "./resources/log.js?pipe=sub&name=none" + "../resources/log.js?pipe=sub&name=none" ], "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank": [ "@std/blank", @@ -33,13 +33,13 @@ const importMap = ` "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none" ], - "./resources/log.js?pipe=sub&name=std-blank": [ + "../resources/log.js?pipe=sub&name=std-blank": [ "std:blank", - "./resources/log.js?pipe=sub&name=std-blank" + "../resources/log.js?pipe=sub&name=std-blank" ], - "./resources/log.js?pipe=sub&name=std-none": [ + "../resources/log.js?pipe=sub&name=std-none": [ "std:none", - "./resources/log.js?pipe=sub&name=std-none" + "../resources/log.js?pipe=sub&name=std-none" ], "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank": [ "std:blank", @@ -61,18 +61,18 @@ const tests = { // - dynamic import. // Result.URL indicates that the specifier was not re-mapped by import maps, // i.e. either considered as a relative path, or fallback occured. - "./resources/log.js?pipe=sub&name=blank": + "../resources/log.js?pipe=sub&name=blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], - "./resources/log.js?pipe=sub&name=none": + "../resources/log.js?pipe=sub&name=none": [Result.URL, Result.URL, Result.URL, Result.URL], "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none": [Result.URL, Result.URL, Result.URL, Result.URL], - "./resources/log.js?pipe=sub&name=std-blank": + "../resources/log.js?pipe=sub&name=std-blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], - "./resources/log.js?pipe=sub&name=std-none": + "../resources/log.js?pipe=sub&name=std-none": [Result.URL, Result.URL, Result.URL, Result.URL], "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], diff --git a/tests/wpt/web-platform-tests/import-maps/http.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/http.sub.tentative.html index bd24f353550..7689ae13bb5 100644 --- a/tests/wpt/web-platform-tests/import-maps/http.sub.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/http.sub.tentative.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="resources/test-helper.js"></script> +<script src="../resources/test-helper.js"></script> <script> // "bare/..." (i.e. without leading "./") are bare specifiers @@ -14,18 +14,10 @@ const importMap = ` { "imports": { - "bare": "./resources/log.js?pipe=sub&name=bare", - - "./resources/log.js?pipe=sub&name=foo": "./resources/log.js?pipe=sub&name=bar", - "./resources/log.js?pipe=sub&name=cross-origin-foo": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bar", - "./resources/log.js?pipe=sub&name=to-data": "data:text/javascript,log.push('dataURL')", - - "./resources/log.js?pipe=sub&name=std-blank": "std:blank", - "./resources/log.js?pipe=sub&name=blank": "@std/blank", - "./resources/log.js?pipe=sub&name=std-none": "std:none", - "./resources/log.js?pipe=sub&name=none": "@std/none", - - "./resources/log.js?pipe=sub&name=to-bare": "bare" + "../resources/log.js?pipe=sub&name=std-blank": "std:blank", + "../resources/log.js?pipe=sub&name=blank": "@std/blank", + "../resources/log.js?pipe=sub&name=std-none": "std:none", + "../resources/log.js?pipe=sub&name=none": "@std/none" } } `; @@ -42,16 +34,6 @@ const tests = { // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR // below. https://crbug.com/928435 - // HTTP(S) to HTTP(S). - "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=foo": - [Result.URL, Result.URL, "log:bar", "log:bar"], - "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo": - [Result.URL, Result.URL, "log:cross-origin-bar", "log:cross-origin-bar"], - - // HTTP(S) to data: - "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-data": - [Result.URL, Result.URL, "dataURL", "dataURL"], - // HTTP(S) to built-in. "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=std-blank": [Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN], @@ -61,10 +43,6 @@ const tests = { [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=none": [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], - - // HTTP(S) to bare mapping is disabled. - "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-bare": - [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], }; doTests(importMap, null, tests); diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html new file mode 100644 index 00000000000..0cc92ce3e5e --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-addresses.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-addresses.js +--> +<script type="module" src="resources/parsing-addresses.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html new file mode 100644 index 00000000000..9e3bca2935b --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-schema.js +--> +<script type="module" src="resources/parsing-schema.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html new file mode 100644 index 00000000000..be23c645d0b --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-scope-keys.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-scope-keys.js +--> +<script type="module" src="resources/parsing-scope-keys.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html new file mode 100644 index 00000000000..7bc2d4799f1 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/parsing-specifier-keys.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-specifier-keys.js +--> +<script type="module" src="resources/parsing-specifier-keys.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resolving-builtins.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-builtins.tentative.html index c1395c175c7..065cfa30964 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resolving-builtins.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-builtins.tentative.html @@ -2,7 +2,7 @@ <html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="../resources/jest-test-helper.js"></script> +<script src="../../resources/jest-test-helper.js"></script> <script type="module" src="resources/helpers/parsing.js"></script> <!-- diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resolving-not-yet-implemented.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html index 7db5f29f892..3bdd591fd0c 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resolving-not-yet-implemented.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html @@ -2,7 +2,7 @@ <html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="../resources/jest-test-helper.js"></script> +<script src="../../resources/jest-test-helper.js"></script> <script type="module" src="resources/helpers/parsing.js"></script> <!-- diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html new file mode 100644 index 00000000000..33b49352ccd --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-scopes.js +--> +<script type="module" src="resources/resolving-scopes.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving.tentative.html b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving.tentative.html new file mode 100644 index 00000000000..1d24eb2031e --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resolving.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js +--> +<script type="module" src="resources/resolving.js"></script> diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/helpers/parsing.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/helpers/parsing.js new file mode 100644 index 00000000000..daad6d26d22 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/helpers/parsing.js @@ -0,0 +1,44 @@ +'use strict'; +const { parseFromString } = require('../../lib/parser.js'); + +// Local modifications from upstream: +// Currently warnings and scopes are not checked in expectSpecifierMap(). +exports.expectSpecifierMap = (input, baseURL, output, warnings = []) => { + expect(parseFromString(`{ "imports": ${input} }`, baseURL)) + .toEqual({ imports: output, scopes: {} }); +}; + +exports.expectScopes = (inputArray, baseURL, outputArray, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + + const inputScopesAsStrings = inputArray.map(scopePrefix => `${JSON.stringify(scopePrefix)}: {}`); + const inputString = `{ "scopes": { ${inputScopesAsStrings.join(', ')} } }`; + + const outputScopesObject = {}; + for (const outputScopePrefix of outputArray) { + outputScopesObject[outputScopePrefix] = {}; + } + + expect(parseFromString(inputString, baseURL)).toEqual({ imports: {}, scopes: outputScopesObject }); + + checkWarnings(); +}; + +exports.expectBad = (input, baseURL, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + expect(() => parseFromString(input, baseURL)).toThrow(TypeError); + checkWarnings(); +}; + +exports.expectWarnings = (input, baseURL, output, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + expect(parseFromString(input, baseURL)).toEqual(output); + + checkWarnings(); +}; + +function testWarningHandler(expectedWarnings) { + // We don't check warnings on WPT tests, because there are no + // ways to catch console warnings from JavaScript. + return () => {}; +} diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-addresses.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-addresses.js new file mode 100644 index 00000000000..0f5fc73506b --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-addresses.js @@ -0,0 +1,351 @@ +'use strict'; +const { expectSpecifierMap } = require('./helpers/parsing.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +describe('Relative URL-like addresses', () => { + it('should accept strings prefixed with ./, ../, or /', () => { + expectSpecifierMap( + `{ + "dotSlash": "./foo", + "dotDotSlash": "../foo", + "slash": "/foo" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash: [expect.toMatchURL('https://base.example/path1/path2/foo')], + dotDotSlash: [expect.toMatchURL('https://base.example/path1/foo')], + slash: [expect.toMatchURL('https://base.example/foo')] + } + ); + }); + + it('should not accept strings prefixed with ./, ../, or / for data: base URLs', () => { + expectSpecifierMap( + `{ + "dotSlash": "./foo", + "dotDotSlash": "../foo", + "slash": "/foo" + }`, + 'data:text/html,test', + { + dotSlash: [], + dotDotSlash: [], + slash: [] + }, + [ + `Invalid address "./foo" for the specifier key "dotSlash".`, + `Invalid address "../foo" for the specifier key "dotDotSlash".`, + `Invalid address "/foo" for the specifier key "slash".` + ] + ); + }); + + it('should accept the literal strings ./, ../, or / with no suffix', () => { + expectSpecifierMap( + `{ + "dotSlash": "./", + "dotDotSlash": "../", + "slash": "/" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash: [expect.toMatchURL('https://base.example/path1/path2/')], + dotDotSlash: [expect.toMatchURL('https://base.example/path1/')], + slash: [expect.toMatchURL('https://base.example/')] + } + ); + }); + + it('should ignore percent-encoded variants of ./, ../, or /', () => { + expectSpecifierMap( + `{ + "dotSlash1": "%2E/", + "dotDotSlash1": "%2E%2E/", + "dotSlash2": ".%2F", + "dotDotSlash2": "..%2F", + "slash2": "%2F", + "dotSlash3": "%2E%2F", + "dotDotSlash3": "%2E%2E%2F" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash1: [], + dotDotSlash1: [], + dotSlash2: [], + dotDotSlash2: [], + slash2: [], + dotSlash3: [], + dotDotSlash3: [] + }, + [ + `Invalid address "%2E/" for the specifier key "dotSlash1".`, + `Invalid address "%2E%2E/" for the specifier key "dotDotSlash1".`, + `Invalid address ".%2F" for the specifier key "dotSlash2".`, + `Invalid address "..%2F" for the specifier key "dotDotSlash2".`, + `Invalid address "%2F" for the specifier key "slash2".`, + `Invalid address "%2E%2F" for the specifier key "dotSlash3".`, + `Invalid address "%2E%2E%2F" for the specifier key "dotDotSlash3".` + ] + ); + }); +}); + +describe('Built-in module addresses', () => { + it('should accept URLs using the built-in module scheme', () => { + expectSpecifierMap( + `{ + "foo": "${BUILT_IN_MODULE_SCHEME}:foo" + }`, + 'https://base.example/path1/path2/path3', + { + foo: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo`)] + } + ); + }); + + it('should ignore percent-encoded variants of the built-in module scheme', () => { + expectSpecifierMap( + `{ + "foo": "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" + }`, + 'https://base.example/path1/path2/path3', + { + foo: [] + }, + [`Invalid address "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" for the specifier key "foo".`] + ); + }); + + it('should allow built-in module URLs that contain "/" or "\\"', () => { + expectSpecifierMap( + `{ + "slashEnd": "${BUILT_IN_MODULE_SCHEME}:foo/", + "slashMiddle": "${BUILT_IN_MODULE_SCHEME}:foo/bar", + "backslash": "${BUILT_IN_MODULE_SCHEME}:foo\\\\baz" + }`, + 'https://base.example/path1/path2/path3', + { + slashEnd: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/`)], + slashMiddle: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/bar`)], + backslash: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo\\baz`)] + } + ); + }); +}); + +describe('Absolute URL addresses', () => { + it('should only accept absolute URL addresses with fetch schemes', () => { + expectSpecifierMap( + `{ + "about": "about:good", + "blob": "blob:good", + "data": "data:good", + "file": "file:///good", + "filesystem": "filesystem:good", + "http": "http://good/", + "https": "https://good/", + "ftp": "ftp://good/", + "import": "import:bad", + "mailto": "mailto:bad", + "javascript": "javascript:bad", + "wss": "wss:bad" + }`, + 'https://base.example/path1/path2/path3', + { + about: [expect.toMatchURL('about:good')], + blob: [expect.toMatchURL('blob:good')], + data: [expect.toMatchURL('data:good')], + file: [expect.toMatchURL('file:///good')], + filesystem: [expect.toMatchURL('filesystem:good')], + http: [expect.toMatchURL('http://good/')], + https: [expect.toMatchURL('https://good/')], + ftp: [expect.toMatchURL('ftp://good/')], + import: [], + mailto: [], + javascript: [], + wss: [] + }, + [ + `Invalid address "import:bad" for the specifier key "import".`, + `Invalid address "mailto:bad" for the specifier key "mailto".`, + `Invalid address "javascript:bad" for the specifier key "javascript".`, + `Invalid address "wss:bad" for the specifier key "wss".` + ] + ); + }); + + it('should only accept absolute URL addresses with fetch schemes inside arrays', () => { + expectSpecifierMap( + `{ + "about": ["about:good"], + "blob": ["blob:good"], + "data": ["data:good"], + "file": ["file:///good"], + "filesystem": ["filesystem:good"], + "http": ["http://good/"], + "https": ["https://good/"], + "ftp": ["ftp://good/"], + "import": ["import:bad"], + "mailto": ["mailto:bad"], + "javascript": ["javascript:bad"], + "wss": ["wss:bad"] + }`, + 'https://base.example/path1/path2/path3', + { + about: [expect.toMatchURL('about:good')], + blob: [expect.toMatchURL('blob:good')], + data: [expect.toMatchURL('data:good')], + file: [expect.toMatchURL('file:///good')], + filesystem: [expect.toMatchURL('filesystem:good')], + http: [expect.toMatchURL('http://good/')], + https: [expect.toMatchURL('https://good/')], + ftp: [expect.toMatchURL('ftp://good/')], + import: [], + mailto: [], + javascript: [], + wss: [] + }, + [ + `Invalid address "import:bad" for the specifier key "import".`, + `Invalid address "mailto:bad" for the specifier key "mailto".`, + `Invalid address "javascript:bad" for the specifier key "javascript".`, + `Invalid address "wss:bad" for the specifier key "wss".` + ] + ); + }); + + it('should parse absolute URLs, ignoring unparseable ones', () => { + expectSpecifierMap( + `{ + "unparseable1": "https://ex ample.org/", + "unparseable2": "https://example.com:demo", + "unparseable3": "http://[www.example.com]/", + "invalidButParseable1": "https:example.org", + "invalidButParseable2": "https://///example.com///", + "prettyNormal": "https://example.net", + "percentDecoding": "https://ex%41mple.com/", + "noPercentDecoding": "https://example.com/%41" + }`, + 'https://base.example/path1/path2/path3', + { + unparseable1: [], + unparseable2: [], + unparseable3: [], + invalidButParseable1: [expect.toMatchURL('https://example.org/')], + invalidButParseable2: [expect.toMatchURL('https://example.com///')], + prettyNormal: [expect.toMatchURL('https://example.net/')], + percentDecoding: [expect.toMatchURL('https://example.com/')], + noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] + }, + [ + `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, + `Invalid address "https://example.com:demo" for the specifier key "unparseable2".`, + `Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".` + ] + ); + }); + + it('should parse absolute URLs, ignoring unparseable ones inside arrays', () => { + expectSpecifierMap( + `{ + "unparseable1": ["https://ex ample.org/"], + "unparseable2": ["https://example.com:demo"], + "unparseable3": ["http://[www.example.com]/"], + "invalidButParseable1": ["https:example.org"], + "invalidButParseable2": ["https://///example.com///"], + "prettyNormal": ["https://example.net"], + "percentDecoding": ["https://ex%41mple.com/"], + "noPercentDecoding": ["https://example.com/%41"] + }`, + 'https://base.example/path1/path2/path3', + { + unparseable1: [], + unparseable2: [], + unparseable3: [], + invalidButParseable1: [expect.toMatchURL('https://example.org/')], + invalidButParseable2: [expect.toMatchURL('https://example.com///')], + prettyNormal: [expect.toMatchURL('https://example.net/')], + percentDecoding: [expect.toMatchURL('https://example.com/')], + noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] + }, + [ + `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, + `Invalid address "https://example.com:demo" for the specifier key "unparseable2".`, + `Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".` + ] + ); + }); +}); + +describe('Failing addresses: mismatched trailing slashes', () => { + it('should warn for the simple case', () => { + expectSpecifierMap( + `{ + "trailer/": "/notrailer", + "${BUILT_IN_MODULE_SCHEME}:trailer/": "/bim-notrailer" + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); + + it('should warn for a mismatch alone in an array', () => { + expectSpecifierMap( + `{ + "trailer/": ["/notrailer"], + "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-notrailer"] + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); + + it('should warn for a mismatch alongside non-mismatches in an array', () => { + expectSpecifierMap( + `{ + "trailer/": ["/atrailer/", "/notrailer"], + "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-atrailer/", "/bim-notrailer"] + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [expect.toMatchURL('https://base.example/atrailer/')], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [expect.toMatchURL('https://base.example/bim-atrailer/')] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); +}); + +describe('Other invalid addresses', () => { + it('should ignore unprefixed strings that are not absolute URLs', () => { + for (const bad of ['bar', '\\bar', '~bar', '#bar', '?bar']) { + expectSpecifierMap( + `{ + "foo": ${JSON.stringify(bad)} + }`, + 'https://base.example/path1/path2/path3', + { + foo: [] + }, + [`Invalid address "${bad}" for the specifier key "foo".`] + ); + } + }); +}); diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-schema.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-schema.js new file mode 100644 index 00000000000..695034533c7 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-schema.js @@ -0,0 +1,139 @@ +'use strict'; +const { parseFromString } = require('../lib/parser.js'); +const { expectBad, expectWarnings, expectSpecifierMap } = require('./helpers/parsing.js'); + +const nonObjectStrings = ['null', 'true', '1', '"foo"', '[]']; + +test('Invalid JSON', () => { + expect(() => parseFromString('{ imports: {} }', 'https://base.example/')).toThrow(SyntaxError); +}); + +describe('Mismatching the top-level schema', () => { + it('should throw for top-level non-objects', () => { + for (const nonObject of nonObjectStrings) { + expectBad(nonObject, 'https://base.example/'); + } + }); + + it('should throw if imports is a non-object', () => { + for (const nonObject of nonObjectStrings) { + expectBad(`{ "imports": ${nonObject} }`, 'https://base.example/'); + } + }); + + it('should throw if scopes is a non-object', () => { + for (const nonObject of nonObjectStrings) { + expectBad(`{ "scopes": ${nonObject} }`, 'https://base.example/'); + } + }); + + it('should ignore unspecified top-level entries', () => { + expectWarnings( + `{ + "imports": {}, + "new-feature": {}, + "scops": {} + }`, + 'https://base.example/', + { imports: {}, scopes: {} }, + [ + `Invalid top-level key "new-feature". Only "imports" and "scopes" can be present.`, + `Invalid top-level key "scops". Only "imports" and "scopes" can be present.` + ] + ); + }); +}); + +describe('Mismatching the specifier map schema', () => { + const invalidAddressStrings = ['true', '1', '{}']; + const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]']; + + it('should ignore entries where the address is not a string, array, or null', () => { + for (const invalid of invalidAddressStrings) { + expectSpecifierMap( + `{ + "foo": ${invalid}, + "bar": ["https://example.com/"] + }`, + 'https://base.example/', + { + bar: [expect.toMatchURL('https://example.com/')] + }, + [ + `Invalid address ${invalid} for the specifier key "foo". ` + + `Addresses must be strings, arrays, or null.` + ] + ); + } + }); + + it('should ignore entries where the specifier key is an empty string', () => { + expectSpecifierMap( + `{ + "": ["https://example.com/"] + }`, + 'https://base.example/', + {}, + [`Invalid empty string specifier key.`] + ); + }); + + it('should ignore members of an address array that are not strings', () => { + for (const invalid of invalidInsideArrayStrings) { + expectSpecifierMap( + `{ + "foo": ["https://example.com/", ${invalid}], + "bar": ["https://example.com/"] + }`, + 'https://base.example/', + { + foo: [expect.toMatchURL('https://example.com/')], + bar: [expect.toMatchURL('https://example.com/')] + }, + [ + `Invalid address ${invalid} inside the address array for the specifier key "foo". ` + + `Address arrays must only contain strings.` + ] + ); + } + }); + + it('should throw if a scope\'s value is not an object', () => { + for (const invalid of nonObjectStrings) { + expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/'); + } + }); +}); + +describe('Normalization', () => { + it('should normalize empty import maps to have imports and scopes keys', () => { + expect(parseFromString(`{}`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize an import map without imports to have imports', () => { + expect(parseFromString(`{ "scopes": {} }`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize an import map without scopes to have scopes', () => { + expect(parseFromString(`{ "imports": {} }`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize addresses to arrays', () => { + expectSpecifierMap( + `{ + "foo": "https://example.com/1", + "bar": ["https://example.com/2"], + "baz": null + }`, + 'https://base.example/', + { + foo: [expect.toMatchURL('https://example.com/1')], + bar: [expect.toMatchURL('https://example.com/2')], + baz: [] + } + ); + }); +}); diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-scope-keys.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-scope-keys.js new file mode 100644 index 00000000000..4993f3a9a8b --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-scope-keys.js @@ -0,0 +1,144 @@ +'use strict'; +const { expectScopes } = require('./helpers/parsing.js'); + +describe('Relative URL scope keys', () => { + it('should work with no prefix', () => { + expectScopes( + ['foo'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo'] + ); + }); + + it('should work with ./, ../, and / prefixes', () => { + expectScopes( + ['./foo', '../foo', '/foo'], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/foo', + 'https://base.example/path1/foo', + 'https://base.example/foo' + ] + ); + }); + + it('should work with /s, ?s, and #s', () => { + expectScopes( + ['foo/bar?baz#qux'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo/bar?baz#qux'] + ); + }); + + it('should work with an empty string scope key', () => { + expectScopes( + [''], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/path3'] + ); + }); + + it('should work with / suffixes', () => { + expectScopes( + ['foo/', './foo/', '../foo/', '/foo/', '/foo//'], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/foo/', + 'https://base.example/path1/path2/foo/', + 'https://base.example/path1/foo/', + 'https://base.example/foo/', + 'https://base.example/foo//' + ] + ); + }); + + it('should deduplicate based on URL parsing rules', () => { + expectScopes( + ['foo/\\', 'foo//', 'foo\\\\'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo//'] + ); + }); +}); + +describe('Absolute URL scope keys', () => { + it('should accept all absolute URL scope keys, with or without fetch schemes', () => { + expectScopes( + [ + 'about:good', + 'blob:good', + 'data:good', + 'file:///good', + 'filesystem:http://example.com/good/', + 'http://good/', + 'https://good/', + 'ftp://good/', + 'import:bad', + 'mailto:bad', + 'javascript:bad', + 'wss:ba' + ], + 'https://base.example/path1/path2/path3', + [ + 'about:good', + 'blob:good', + 'data:good', + 'file:///good', + 'filesystem:http://example.com/good/', + 'http://good/', + 'https://good/', + 'ftp://good/', + 'import:bad', + 'mailto:bad', + 'javascript:bad', + 'wss://ba/' + ], + [] + ); + }); + + it('should parse absolute URL scope keys, ignoring unparseable ones', () => { + expectScopes( + [ + 'https://ex ample.org/', + 'https://example.com:demo', + 'http://[www.example.com]/', + 'https:example.org', + 'https://///example.com///', + 'https://example.net', + 'https://ex%41mple.com/foo/', + 'https://example.com/%41' + ], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/example.org', // tricky case! remember we have a base URL + 'https://example.com///', + 'https://example.net/', + 'https://example.com/foo/', + 'https://example.com/%41' + ], + [ + 'Invalid scope "https://ex ample.org/" (parsed against base URL "https://base.example/path1/path2/path3").', + 'Invalid scope "https://example.com:demo" (parsed against base URL "https://base.example/path1/path2/path3").', + 'Invalid scope "http://[www.example.com]/" (parsed against base URL "https://base.example/path1/path2/path3").' + ] + ); + }); + + it('should ignore relative URL scope keys when the base URL is a data: URL', () => { + expectScopes( + [ + './foo', + '../foo', + '/foo' + ], + 'data:text/html,test', + [], + [ + 'Invalid scope "./foo" (parsed against base URL "data:text/html,test").', + 'Invalid scope "../foo" (parsed against base URL "data:text/html,test").', + 'Invalid scope "/foo" (parsed against base URL "data:text/html,test").' + ] + ); + }); +}); diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-specifier-keys.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-specifier-keys.js new file mode 100644 index 00000000000..9eb423a19eb --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/parsing-specifier-keys.js @@ -0,0 +1,159 @@ +'use strict'; +const { expectSpecifierMap } = require('./helpers/parsing.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`; + +describe('Relative URL-like specifier keys', () => { + it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => { + expectSpecifierMap( + `{ + "./foo": "/dotslash", + "../foo": "/dotdotslash", + "/foo": "/slash" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')], + 'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')], + 'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')] + } + ); + }); + + it('should not absolutize strings prefixed with ./, ../, or / with a data: URL base', () => { + expectSpecifierMap( + `{ + "./foo": "https://example.com/dotslash", + "../foo": "https://example.com/dotdotslash", + "/foo": "https://example.com/slash" + }`, + 'data:text/html,test', + { + './foo': [expect.toMatchURL('https://example.com/dotslash')], + '../foo': [expect.toMatchURL('https://example.com/dotdotslash')], + '/foo': [expect.toMatchURL('https://example.com/slash')] + } + ); + }); + + it('should absolutize the literal strings ./, ../, or / with no suffix', () => { + expectSpecifierMap( + `{ + "./": "/dotslash/", + "../": "/dotdotslash/", + "/": "/slash/" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')], + 'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')], + 'https://base.example/': [expect.toMatchURL('https://base.example/slash/')] + } + ); + }); + + it('should treat percent-encoded variants of ./, ../, or / as bare specifiers', () => { + expectSpecifierMap( + `{ + "%2E/": "/dotSlash1/", + "%2E%2E/": "/dotDotSlash1/", + ".%2F": "/dotSlash2", + "..%2F": "/dotDotSlash2", + "%2F": "/slash2", + "%2E%2F": "/dotSlash3", + "%2E%2E%2F": "/dotDotSlash3" + }`, + 'https://base.example/path1/path2/path3', + { + '%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')], + '%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')], + '.%2F': [expect.toMatchURL('https://base.example/dotSlash2')], + '..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')], + '%2F': [expect.toMatchURL('https://base.example/slash2')], + '%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')], + '%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')] + } + ); + }); +}); + +describe('Absolute URL specifier keys', () => { + it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => { + expectSpecifierMap( + `{ + "about:good": "/about", + "blob:good": "/blob", + "data:good": "/data", + "file:///good": "/file", + "filesystem:good": "/filesystem", + "http://good/": "/http/", + "https://good/": "/https/", + "ftp://good/": "/ftp/", + "import:bad": "/import", + "mailto:bad": "/mailto", + "javascript:bad": "/javascript", + "wss:bad": "/wss" + }`, + 'https://base.example/path1/path2/path3', + { + 'about:good': [expect.toMatchURL('https://base.example/about')], + 'blob:good': [expect.toMatchURL('https://base.example/blob')], + 'data:good': [expect.toMatchURL('https://base.example/data')], + 'file:///good': [expect.toMatchURL('https://base.example/file')], + 'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')], + 'http://good/': [expect.toMatchURL('https://base.example/http/')], + 'https://good/': [expect.toMatchURL('https://base.example/https/')], + 'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')], + 'import:bad': [expect.toMatchURL('https://base.example/import')], + 'mailto:bad': [expect.toMatchURL('https://base.example/mailto')], + 'javascript:bad': [expect.toMatchURL('https://base.example/javascript')], + 'wss:bad': [expect.toMatchURL('https://base.example/wss')] + } + ); + }); + + it('should parse absolute URLs, treating unparseable ones as bare specifiers', () => { + expectSpecifierMap( + `{ + "https://ex ample.org/": "/unparseable1/", + "https://example.com:demo": "/unparseable2", + "http://[www.example.com]/": "/unparseable3/", + "https:example.org": "/invalidButParseable1/", + "https://///example.com///": "/invalidButParseable2/", + "https://example.net": "/prettyNormal/", + "https://ex%41mple.com/": "/percentDecoding/", + "https://example.com/%41": "/noPercentDecoding" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')], + 'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')], + 'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')], + 'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')], + 'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')], + 'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')], + 'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')], + 'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')] + } + ); + }); + + it('should parse built-in module specifier keys, including with a "/"', () => { + expectSpecifierMap( + `{ + "${BLANK}": "/blank", + "${BLANK}/": "/blank/", + "${BLANK}/foo": "/blank/foo", + "${BLANK}\\\\foo": "/blank/backslashfoo" + }`, + 'https://base.example/path1/path2/path3', + { + [BLANK]: [expect.toMatchURL('https://base.example/blank')], + [`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')], + [`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')], + [`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')] + } + ); + }); +}); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-builtins.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-builtins.js index a9383df843d..a9383df843d 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-builtins.js +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-builtins.js diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-not-yet-implemented.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-not-yet-implemented.js index 93d782fdad8..93d782fdad8 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-not-yet-implemented.js +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-not-yet-implemented.js diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-scopes.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-scopes.js new file mode 100644 index 00000000000..ca19a668406 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving-scopes.js @@ -0,0 +1,230 @@ +'use strict'; +const { URL } = require('url'); +const { parseFromString } = require('../lib/parser.js'); +const { resolve } = require('../lib/resolver.js'); + +const mapBaseURL = new URL('https://example.com/app/index.html'); + +function makeResolveUnderTest(mapString) { + const map = parseFromString(mapString, mapBaseURL); + return (specifier, baseURL) => resolve(specifier, map, baseURL); +} + +describe('Mapped using scope instead of "imports"', () => { + const jsNonDirURL = new URL('https://example.com/js'); + const jsPrefixedURL = new URL('https://example.com/jsiscool'); + const inJSDirURL = new URL('https://example.com/js/app.mjs'); + const topLevelURL = new URL('https://example.com/app.mjs'); + + it('should fail when the mapping is to an empty array', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js/": { + "moment": null, + "lodash": [] + } + } + }`); + + expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('lodash', inJSDirURL)).toThrow(TypeError); + }); + + describe('Exact vs. prefix based matching', () => { + it('should match correctly when both are in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js": { + "moment": "/only-triggered-by-exact/moment", + "moment/": "/only-triggered-by-exact/moment/" + }, + "/js/": { + "moment": "/triggered-by-any-subpath/moment", + "moment/": "/triggered-by-any-subpath/moment/" + } + } + }`); + + expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment'); + expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo'); + + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo'); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + + it('should match correctly when only an exact match is in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js": { + "moment": "/only-triggered-by-exact/moment", + "moment/": "/only-triggered-by-exact/moment/" + } + } + }`); + + expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment'); + expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo'); + + expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', inJSDirURL)).toThrow(TypeError); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + + it('should match correctly when only a prefix match is in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js/": { + "moment": "/triggered-by-any-subpath/moment", + "moment/": "/triggered-by-any-subpath/moment/" + } + } + }`); + + expect(() => resolveUnderTest('moment', jsNonDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsNonDirURL)).toThrow(TypeError); + + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo'); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + }); + + describe('Package-like scenarios', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "moment": "/node_modules/moment/src/moment.js", + "moment/": "/node_modules/moment/src/", + "lodash-dot": "./node_modules/lodash-es/lodash.js", + "lodash-dot/": "./node_modules/lodash-es/", + "lodash-dotdot": "../node_modules/lodash-es/lodash.js", + "lodash-dotdot/": "../node_modules/lodash-es/" + }, + "scopes": { + "/": { + "moment": "/node_modules_3/moment/src/moment.js", + "vue": "/node_modules_3/vue/dist/vue.runtime.esm.js" + }, + "/js/": { + "lodash-dot": "./node_modules_2/lodash-es/lodash.js", + "lodash-dot/": "./node_modules_2/lodash-es/", + "lodash-dotdot": "../node_modules_2/lodash-es/lodash.js", + "lodash-dotdot/": "../node_modules_2/lodash-es/" + } + } + }`); + + it('should resolve scoped', () => { + expect(resolveUnderTest('lodash-dot', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dotdot', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dot/foo', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/foo'); + expect(resolveUnderTest('lodash-dotdot/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/foo'); + }); + + it('should apply best scope match', () => { + expect(resolveUnderTest('moment', topLevelURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js'); + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js'); + expect(resolveUnderTest('vue', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/vue/dist/vue.runtime.esm.js'); + }); + + it('should fallback to "imports"', () => { + expect(resolveUnderTest('moment/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/moment/src/foo'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules/moment/src/foo'); + expect(resolveUnderTest('lodash-dot', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dotdot', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dot/foo', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/foo'); + expect(resolveUnderTest('lodash-dotdot/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/foo'); + }); + + it('should still fail for package-like specifiers that are not declared', () => { + expect(() => resolveUnderTest('underscore/', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('underscore/foo', inJSDirURL)).toThrow(TypeError); + }); + }); + + describe('The scope inheritance example from the README', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/a-1.mjs", + "b": "/b-1.mjs", + "c": "/c-1.mjs" + }, + "scopes": { + "/scope2/": { + "a": "/a-2.mjs" + }, + "/scope2/scope3/": { + "b": "/b-3.mjs" + } + } + }`); + + const scope1URL = new URL('https://example.com/scope1/foo.mjs'); + const scope2URL = new URL('https://example.com/scope2/foo.mjs'); + const scope3URL = new URL('https://example.com/scope2/scope3/foo.mjs'); + + it('should fall back to "imports" when none match', () => { + expect(resolveUnderTest('a', scope1URL)).toMatchURL('https://example.com/a-1.mjs'); + expect(resolveUnderTest('b', scope1URL)).toMatchURL('https://example.com/b-1.mjs'); + expect(resolveUnderTest('c', scope1URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + + it('should use a direct scope override', () => { + expect(resolveUnderTest('a', scope2URL)).toMatchURL('https://example.com/a-2.mjs'); + expect(resolveUnderTest('b', scope2URL)).toMatchURL('https://example.com/b-1.mjs'); + expect(resolveUnderTest('c', scope2URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + + it('should use an indirect scope override', () => { + expect(resolveUnderTest('a', scope3URL)).toMatchURL('https://example.com/a-2.mjs'); + expect(resolveUnderTest('b', scope3URL)).toMatchURL('https://example.com/b-3.mjs'); + expect(resolveUnderTest('c', scope3URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + }); + + describe('Relative URL scope keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/a-1.mjs", + "b": "/b-1.mjs", + "c": "/c-1.mjs" + }, + "scopes": { + "": { + "a": "/a-empty-string.mjs" + }, + "./": { + "b": "/b-dot-slash.mjs" + }, + "../": { + "c": "/c-dot-dot-slash.mjs" + } + } + }`); + const inSameDirAsMap = new URL('./foo.mjs', mapBaseURL); + const inDirAboveMap = new URL('../foo.mjs', mapBaseURL); + + it('should resolve an empty string scope using the import map URL', () => { + expect(resolveUnderTest('a', mapBaseURL)).toMatchURL('https://example.com/a-empty-string.mjs'); + expect(resolveUnderTest('a', inSameDirAsMap)).toMatchURL('https://example.com/a-1.mjs'); + }); + + it('should resolve a ./ scope using the import map URL\'s directory', () => { + expect(resolveUnderTest('b', mapBaseURL)).toMatchURL('https://example.com/b-dot-slash.mjs'); + expect(resolveUnderTest('b', inSameDirAsMap)).toMatchURL('https://example.com/b-dot-slash.mjs'); + }); + + it('should resolve a ../ scope using the import map URL\'s directory', () => { + expect(resolveUnderTest('c', mapBaseURL)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + expect(resolveUnderTest('c', inSameDirAsMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + expect(resolveUnderTest('c', inDirAboveMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + }); + }); +}); + diff --git a/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving.js new file mode 100644 index 00000000000..29ee31ccbc9 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/imported/resources/resolving.js @@ -0,0 +1,270 @@ +'use strict'; +const { URL } = require('url'); +const { parseFromString } = require('../lib/parser.js'); +const { resolve } = require('../lib/resolver.js'); + +const mapBaseURL = new URL('https://example.com/app/index.html'); +const scriptURL = new URL('https://example.com/js/app.mjs'); + +function makeResolveUnderTest(mapString) { + const map = parseFromString(mapString, mapBaseURL); + return specifier => resolve(specifier, map, scriptURL); +} + +describe('Unmapped', () => { + const resolveUnderTest = makeResolveUnderTest(`{}`); + + it('should resolve ./ specifiers as URLs', () => { + expect(resolveUnderTest('./foo')).toMatchURL('https://example.com/js/foo'); + expect(resolveUnderTest('./foo/bar')).toMatchURL('https://example.com/js/foo/bar'); + expect(resolveUnderTest('./foo/../bar')).toMatchURL('https://example.com/js/bar'); + expect(resolveUnderTest('./foo/../../bar')).toMatchURL('https://example.com/bar'); + }); + + it('should resolve ../ specifiers as URLs', () => { + expect(resolveUnderTest('../foo')).toMatchURL('https://example.com/foo'); + expect(resolveUnderTest('../foo/bar')).toMatchURL('https://example.com/foo/bar'); + expect(resolveUnderTest('../../../foo/bar')).toMatchURL('https://example.com/foo/bar'); + }); + + it('should resolve / specifiers as URLs', () => { + expect(resolveUnderTest('/foo')).toMatchURL('https://example.com/foo'); + expect(resolveUnderTest('/foo/bar')).toMatchURL('https://example.com/foo/bar'); + expect(resolveUnderTest('/../../foo/bar')).toMatchURL('https://example.com/foo/bar'); + expect(resolveUnderTest('/../foo/../bar')).toMatchURL('https://example.com/bar'); + }); + + it('should parse absolute fetch-scheme URLs', () => { + expect(resolveUnderTest('about:good')).toMatchURL('about:good'); + expect(resolveUnderTest('https://example.net')).toMatchURL('https://example.net/'); + expect(resolveUnderTest('https://ex%41mple.com/')).toMatchURL('https://example.com/'); + expect(resolveUnderTest('https:example.org')).toMatchURL('https://example.org/'); + expect(resolveUnderTest('https://///example.com///')).toMatchURL('https://example.com///'); + }); + + it('should fail for absolute non-fetch-scheme URLs', () => { + expect(() => resolveUnderTest('mailto:bad')).toThrow(TypeError); + expect(() => resolveUnderTest('import:bad')).toThrow(TypeError); + expect(() => resolveUnderTest('javascript:bad')).toThrow(TypeError); + expect(() => resolveUnderTest('wss:bad')).toThrow(TypeError); + }); + + it('should fail for strings not parseable as absolute URLs and not starting with ./ ../ or /', () => { + expect(() => resolveUnderTest('foo')).toThrow(TypeError); + expect(() => resolveUnderTest('\\foo')).toThrow(TypeError); + expect(() => resolveUnderTest(':foo')).toThrow(TypeError); + expect(() => resolveUnderTest('@foo')).toThrow(TypeError); + expect(() => resolveUnderTest('%2E/foo')).toThrow(TypeError); + expect(() => resolveUnderTest('%2E%2E/foo')).toThrow(TypeError); + expect(() => resolveUnderTest('.%2Ffoo')).toThrow(TypeError); + expect(() => resolveUnderTest('https://ex ample.org/')).toThrow(TypeError); + expect(() => resolveUnderTest('https://example.com:demo')).toThrow(TypeError); + expect(() => resolveUnderTest('http://[www.example.com]/')).toThrow(TypeError); + }); +}); + +describe('Mapped using the "imports" key only (no scopes)', () => { + it('should fail when the mapping is to an empty array', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "moment": null, + "lodash": [] + } + }`); + + expect(() => resolveUnderTest('moment')).toThrow(TypeError); + expect(() => resolveUnderTest('lodash')).toThrow(TypeError); + }); + + describe('Package-like scenarios', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "moment": "/node_modules/moment/src/moment.js", + "moment/": "/node_modules/moment/src/", + "lodash-dot": "./node_modules/lodash-es/lodash.js", + "lodash-dot/": "./node_modules/lodash-es/", + "lodash-dotdot": "../node_modules/lodash-es/lodash.js", + "lodash-dotdot/": "../node_modules/lodash-es/", + "nowhere/": [] + } + }`); + + it('should work for package main modules', () => { + expect(resolveUnderTest('moment')).toMatchURL('https://example.com/node_modules/moment/src/moment.js'); + expect(resolveUnderTest('lodash-dot')).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dotdot')).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js'); + }); + + it('should work for package submodules', () => { + expect(resolveUnderTest('moment/foo')).toMatchURL('https://example.com/node_modules/moment/src/foo'); + expect(resolveUnderTest('lodash-dot/foo')).toMatchURL('https://example.com/app/node_modules/lodash-es/foo'); + expect(resolveUnderTest('lodash-dotdot/foo')).toMatchURL('https://example.com/node_modules/lodash-es/foo'); + }); + + it('should work for package names that end in a slash by just passing through', () => { + // TODO: is this the right behavior, or should we throw? + expect(resolveUnderTest('moment/')).toMatchURL('https://example.com/node_modules/moment/src/'); + }); + + it('should still fail for package modules that are not declared', () => { + expect(() => resolveUnderTest('underscore/')).toThrow(TypeError); + expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError); + }); + + it('should fail for package submodules that map to nowhere', () => { + expect(() => resolveUnderTest('nowhere/foo')).toThrow(TypeError); + }); + }); + + describe('Tricky specifiers', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "package/withslash": "/node_modules/package-with-slash/index.mjs", + "not-a-package": "/lib/not-a-package.mjs", + ".": "/lib/dot.mjs", + "..": "/lib/dotdot.mjs", + "..\\\\": "/lib/dotdotbackslash.mjs", + "%2E": "/lib/percent2e.mjs", + "%2F": "/lib/percent2f.mjs" + } + }`); + + it('should work for explicitly-mapped specifiers that happen to have a slash', () => { + expect(resolveUnderTest('package/withslash')).toMatchURL('https://example.com/node_modules/package-with-slash/index.mjs'); + }); + + it('should work when the specifier has punctuation', () => { + expect(resolveUnderTest('.')).toMatchURL('https://example.com/lib/dot.mjs'); + expect(resolveUnderTest('..')).toMatchURL('https://example.com/lib/dotdot.mjs'); + expect(resolveUnderTest('..\\')).toMatchURL('https://example.com/lib/dotdotbackslash.mjs'); + expect(resolveUnderTest('%2E')).toMatchURL('https://example.com/lib/percent2e.mjs'); + expect(resolveUnderTest('%2F')).toMatchURL('https://example.com/lib/percent2f.mjs'); + }); + + it('should fail for attempting to get a submodule of something not declared with a trailing slash', () => { + expect(() => resolveUnderTest('not-a-package/foo')).toThrow(TypeError); + }); + }); + + describe('URL-like specifiers', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "/node_modules/als-polyfill/index.mjs": "std:kv-storage", + + "/lib/foo.mjs": "./more/bar.mjs", + "./dotrelative/foo.mjs": "/lib/dot.mjs", + "../dotdotrelative/foo.mjs": "/lib/dotdot.mjs", + + "/lib/no.mjs": null, + "./dotrelative/no.mjs": [], + + "/": "/lib/slash-only/", + "./": "/lib/dotslash-only/", + + "/test/": "/lib/url-trailing-slash/", + "./test/": "/lib/url-trailing-slash-dot/", + + "/test": "/lib/test1.mjs", + "../test": "/lib/test2.mjs" + } + }`); + + it('should remap to other URLs', () => { + expect(resolveUnderTest('https://example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs'); + expect(resolveUnderTest('https://///example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs'); + expect(resolveUnderTest('/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs'); + + expect(resolveUnderTest('https://example.com/app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs'); + expect(resolveUnderTest('../app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs'); + + expect(resolveUnderTest('https://example.com/dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs'); + expect(resolveUnderTest('../dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs'); + }); + + it('should fail for URLs that remap to empty arrays', () => { + expect(() => resolveUnderTest('https://example.com/lib/no.mjs')).toThrow(TypeError); + expect(() => resolveUnderTest('/lib/no.mjs')).toThrow(TypeError); + expect(() => resolveUnderTest('../lib/no.mjs')).toThrow(TypeError); + + expect(() => resolveUnderTest('https://example.com/app/dotrelative/no.mjs')).toThrow(TypeError); + expect(() => resolveUnderTest('/app/dotrelative/no.mjs')).toThrow(TypeError); + expect(() => resolveUnderTest('../app/dotrelative/no.mjs')).toThrow(TypeError); + }); + + it('should remap URLs that are just composed from / and .', () => { + expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only/'); + expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only/'); + expect(resolveUnderTest('../')).toMatchURL('https://example.com/lib/slash-only/'); + + expect(resolveUnderTest('https://example.com/app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + expect(resolveUnderTest('/app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + expect(resolveUnderTest('../app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + }); + + it('should remap URLs that are prefix-matched by keys with trailing slashes', () => { + expect(resolveUnderTest('/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash/foo.mjs'); + expect(resolveUnderTest('https://example.com/app/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash-dot/foo.mjs'); + }); + + it('should use the last entry\'s address when URL-like specifiers parse to the same absolute URL', () => { + expect(resolveUnderTest('/test')).toMatchURL('https://example.com/lib/test2.mjs'); + }); + }); + + describe('Overlapping entries with trailing slashes', () => { + it('should favor the most-specific key (no empty arrays)', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/1", + "a/": "/2/", + "a/b": "/3", + "a/b/": "/4/" + } + }`); + + expect(resolveUnderTest('a')).toMatchURL('https://example.com/1'); + expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/'); + expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3'); + expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/'); + expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); + }); + + it('should favor the most-specific key when empty arrays are involved for less-specific keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": [], + "a/": [], + "a/b": "/3", + "a/b/": "/4/" + } + }`); + + expect(() => resolveUnderTest('a')).toThrow(TypeError); + expect(() => resolveUnderTest('a/')).toThrow(TypeError); + expect(() => resolveUnderTest('a/x')).toThrow(TypeError); + expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3'); + expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/'); + expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); + expect(() => resolveUnderTest('a/x/c')).toThrow(TypeError); + }); + + it('should favor the most-specific key when empty arrays are involved for more-specific keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/1", + "a/": "/2/", + "a/b": [], + "a/b/": [] + } + }`); + + expect(resolveUnderTest('a')).toMatchURL('https://example.com/1'); + expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/'); + expect(resolveUnderTest('a/x')).toMatchURL('https://example.com/2/x'); + expect(() => resolveUnderTest('a/b')).toThrow(TypeError); + expect(() => resolveUnderTest('a/b/')).toThrow(TypeError); + expect(() => resolveUnderTest('a/b/c')).toThrow(TypeError); + expect(resolveUnderTest('a/x/c')).toMatchURL('https://example.com/2/x/c'); + }); + }); +}); diff --git a/tests/wpt/web-platform-tests/import-maps/static-import.js b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/static-import.js index 1686fc123a7..1686fc123a7 100644 --- a/tests/wpt/web-platform-tests/import-maps/static-import.js +++ b/tests/wpt/web-platform-tests/import-maps/builtin-support.tentative/static-import.js diff --git a/tests/wpt/web-platform-tests/import-maps/core/bare.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/core/bare.sub.tentative.html new file mode 100644 index 00000000000..7fb769e09a2 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/core/bare.sub.tentative.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/test-helper.js"></script> + +<script> +// "bare/..." (i.e. without leading "./") are bare specifiers +// (not relative paths). +const importMap = ` +{ + "imports": { + "bare/bare": "../resources/log.js?pipe=sub&name=bare", + "bare/cross-origin-bare": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bare", + "bare/to-data": "data:text/javascript,log.push('dataURL')", + + "bare/to-bare": "bare/bare" + } +} +`; + +const tests = { + // Arrays of expected results for: + // - <script src type="module">, + // - <script src> (classic script), + // - static import, and + // - dynamic import. + + // Currently, Chromium's implementation resolves import maps as a part of + // specifier resolution, and thus failure in import map resolution causes + // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR + // below. https://crbug.com/928435 + + // Bare to HTTP(S). + "bare/bare": + [Result.URL, Result.URL, "log:bare", "log:bare"], + "bare/cross-origin-bare": + [Result.URL, Result.URL, "log:cross-origin-bare", "log:cross-origin-bare"], + + // Bare to data: + "bare/to-data": + [Result.URL, Result.URL, "dataURL", "dataURL"], + + // Bare to bare mapping is disabled. + "bare/to-bare": + [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], +}; + +doTests(importMap, null, tests); +</script> +<body> diff --git a/tests/wpt/web-platform-tests/import-maps/core/bare/__dir__.headers b/tests/wpt/web-platform-tests/import-maps/core/bare/__dir__.headers new file mode 100644 index 00000000000..e7ec0d6699d --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/core/bare/__dir__.headers @@ -0,0 +1 @@ +Content-Type: text/javascript diff --git a/tests/wpt/web-platform-tests/import-maps/bare/bare b/tests/wpt/web-platform-tests/import-maps/core/bare/bare index 1011e866b81..1011e866b81 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/bare +++ b/tests/wpt/web-platform-tests/import-maps/core/bare/bare diff --git a/tests/wpt/web-platform-tests/import-maps/bare/cross-origin-bare b/tests/wpt/web-platform-tests/import-maps/core/bare/cross-origin-bare index 64851cc8e24..64851cc8e24 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/cross-origin-bare +++ b/tests/wpt/web-platform-tests/import-maps/core/bare/cross-origin-bare diff --git a/tests/wpt/web-platform-tests/import-maps/bare/to-bare b/tests/wpt/web-platform-tests/import-maps/core/bare/to-bare index bdb3791bc94..bdb3791bc94 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/to-bare +++ b/tests/wpt/web-platform-tests/import-maps/core/bare/to-bare diff --git a/tests/wpt/web-platform-tests/import-maps/bare/to-data b/tests/wpt/web-platform-tests/import-maps/core/bare/to-data index 6f25c5af124..6f25c5af124 100644 --- a/tests/wpt/web-platform-tests/import-maps/bare/to-data +++ b/tests/wpt/web-platform-tests/import-maps/core/bare/to-data diff --git a/tests/wpt/web-platform-tests/import-maps/core/data.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/core/data.sub.tentative.html new file mode 100644 index 00000000000..25c18c45b7d --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/core/data.sub.tentative.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/test-helper.js"></script> + +<script> +// "bare/..." (i.e. without leading "./") are bare specifiers +// (not relative paths). +const importMap = ` +{ + "imports": { + "bare": "../resources/log.js?pipe=sub&name=bare", + + "data:text/javascript,log.push('data:foo')": "../resources/log.js?pipe=sub&name=foo", + "data:text/javascript,log.push('data:cross-origin-foo')": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo", + "data:text/javascript,log.push('data:to-data')": "data:text/javascript,log.push('dataURL')", + + "data:text/javascript,log.push('data:to-bare')": "bare" + } +} +`; + +const tests = { + // Arrays of expected results for: + // - <script src type="module">, + // - <script src> (classic script), + // - static import, and + // - dynamic import. + + // Currently, Chromium's implementation resolves import maps as a part of + // specifier resolution, and thus failure in import map resolution causes + // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR + // below. https://crbug.com/928435 + + // data: to HTTP(S). + "data:text/javascript,log.push('data:foo')": + [Result.URL, Result.URL, "log:foo", "log:foo"], + "data:text/javascript,log.push('data:cross-origin-foo')": + [Result.URL, Result.URL, "log:cross-origin-foo", "log:cross-origin-foo"], + + // data: to data: + "data:text/javascript,log.push('data:to-data')": + [Result.URL, Result.URL, "dataURL", "dataURL"], + + // data: to bare mapping is disabled. + "data:text/javascript,log.push('data:to-bare')": + [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], +}; + +doTests(importMap, null, tests); +</script> +<body> diff --git a/tests/wpt/web-platform-tests/import-maps/core/http.sub.tentative.html b/tests/wpt/web-platform-tests/import-maps/core/http.sub.tentative.html new file mode 100644 index 00000000000..a33a0945e31 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/core/http.sub.tentative.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/test-helper.js"></script> + +<script> +// "bare/..." (i.e. without leading "./") are bare specifiers +// (not relative paths). +const importMap = ` +{ + "imports": { + "bare": "../resources/log.js?pipe=sub&name=bare", + + "../resources/log.js?pipe=sub&name=foo": "../resources/log.js?pipe=sub&name=bar", + "../resources/log.js?pipe=sub&name=cross-origin-foo": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bar", + "../resources/log.js?pipe=sub&name=to-data": "data:text/javascript,log.push('dataURL')", + + "../resources/log.js?pipe=sub&name=to-bare": "bare" + } +} +`; + +const tests = { + // Arrays of expected results for: + // - <script src type="module">, + // - <script src> (classic script), + // - static import, and + // - dynamic import. + + // Currently, Chromium's implementation resolves import maps as a part of + // specifier resolution, and thus failure in import map resolution causes + // a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR + // below. https://crbug.com/928435 + + // HTTP(S) to HTTP(S). + "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=foo": + [Result.URL, Result.URL, "log:bar", "log:bar"], + "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo": + [Result.URL, Result.URL, "log:cross-origin-bar", "log:cross-origin-bar"], + + // HTTP(S) to data: + "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-data": + [Result.URL, Result.URL, "dataURL", "dataURL"], + + // HTTP(S) to bare mapping is disabled. + "{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-bare": + [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR], +}; + +doTests(importMap, null, tests); +</script> +<body> diff --git a/tests/wpt/web-platform-tests/import-maps/module-map-key.tentative.html b/tests/wpt/web-platform-tests/import-maps/core/module-map-key.tentative.html index 13bd122c673..6f2f18a02e1 100644 --- a/tests/wpt/web-platform-tests/import-maps/module-map-key.tentative.html +++ b/tests/wpt/web-platform-tests/import-maps/core/module-map-key.tentative.html @@ -5,7 +5,7 @@ <script type="importmap"> { "imports": { - "./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B" + "../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B" } } </script> @@ -17,8 +17,8 @@ const log = []; // key will become the URL/specifier BEFORE import map resolution. // https://crbug.com/928435 promise_test(() => { - return import("./resources/log.js?pipe=sub&name=A") - .then(() => import("./resources/log.js?pipe=sub&name=B")) + return import("../resources/log.js?pipe=sub&name=A") + .then(() => import("../resources/log.js?pipe=sub&name=B")) .then(() => assert_array_equals(log, ["log:B"])) }, "Module map's key is the URL after import map resolution"); diff --git a/tests/wpt/web-platform-tests/import-maps/core/static-import.js b/tests/wpt/web-platform-tests/import-maps/core/static-import.js new file mode 100644 index 00000000000..1686fc123a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/import-maps/core/static-import.js @@ -0,0 +1 @@ +import "{{GET[url]}}"; diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/helpers/parsing.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/helpers/parsing.js index 5c22f6de710..daad6d26d22 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/helpers/parsing.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/helpers/parsing.js @@ -38,13 +38,7 @@ exports.expectWarnings = (input, baseURL, output, warnings = []) => { }; function testWarningHandler(expectedWarnings) { - const warnings = []; - const { warn } = console; - console.warn = warning => { - warnings.push(warning); - }; - return () => { - console.warn = warn; - expect(warnings).toEqual(expectedWarnings); - }; + // We don't check warnings on WPT tests, because there are no + // ways to catch console warnings from JavaScript. + return () => {}; } diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-addresses.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-addresses.js index 0f5fc73506b..92d7714ade9 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-addresses.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-addresses.js @@ -1,6 +1,5 @@ 'use strict'; const { expectSpecifierMap } = require('./helpers/parsing.js'); -const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); describe('Relative URL-like addresses', () => { it('should accept strings prefixed with ./, ../, or /', () => { @@ -12,9 +11,9 @@ describe('Relative URL-like addresses', () => { }`, 'https://base.example/path1/path2/path3', { - dotSlash: [expect.toMatchURL('https://base.example/path1/path2/foo')], - dotDotSlash: [expect.toMatchURL('https://base.example/path1/foo')], - slash: [expect.toMatchURL('https://base.example/foo')] + dotSlash: expect.toMatchURL('https://base.example/path1/path2/foo'), + dotDotSlash: expect.toMatchURL('https://base.example/path1/foo'), + slash: expect.toMatchURL('https://base.example/foo') } ); }); @@ -28,9 +27,6 @@ describe('Relative URL-like addresses', () => { }`, 'data:text/html,test', { - dotSlash: [], - dotDotSlash: [], - slash: [] }, [ `Invalid address "./foo" for the specifier key "dotSlash".`, @@ -49,9 +45,9 @@ describe('Relative URL-like addresses', () => { }`, 'https://base.example/path1/path2/path3', { - dotSlash: [expect.toMatchURL('https://base.example/path1/path2/')], - dotDotSlash: [expect.toMatchURL('https://base.example/path1/')], - slash: [expect.toMatchURL('https://base.example/')] + dotSlash: expect.toMatchURL('https://base.example/path1/path2/'), + dotDotSlash: expect.toMatchURL('https://base.example/path1/'), + slash: expect.toMatchURL('https://base.example/') } ); }); @@ -69,13 +65,6 @@ describe('Relative URL-like addresses', () => { }`, 'https://base.example/path1/path2/path3', { - dotSlash1: [], - dotDotSlash1: [], - dotSlash2: [], - dotDotSlash2: [], - slash2: [], - dotSlash3: [], - dotDotSlash3: [] }, [ `Invalid address "%2E/" for the specifier key "dotSlash1".`, @@ -90,49 +79,6 @@ describe('Relative URL-like addresses', () => { }); }); -describe('Built-in module addresses', () => { - it('should accept URLs using the built-in module scheme', () => { - expectSpecifierMap( - `{ - "foo": "${BUILT_IN_MODULE_SCHEME}:foo" - }`, - 'https://base.example/path1/path2/path3', - { - foo: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo`)] - } - ); - }); - - it('should ignore percent-encoded variants of the built-in module scheme', () => { - expectSpecifierMap( - `{ - "foo": "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" - }`, - 'https://base.example/path1/path2/path3', - { - foo: [] - }, - [`Invalid address "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" for the specifier key "foo".`] - ); - }); - - it('should allow built-in module URLs that contain "/" or "\\"', () => { - expectSpecifierMap( - `{ - "slashEnd": "${BUILT_IN_MODULE_SCHEME}:foo/", - "slashMiddle": "${BUILT_IN_MODULE_SCHEME}:foo/bar", - "backslash": "${BUILT_IN_MODULE_SCHEME}:foo\\\\baz" - }`, - 'https://base.example/path1/path2/path3', - { - slashEnd: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/`)], - slashMiddle: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/bar`)], - backslash: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo\\baz`)] - } - ); - }); -}); - describe('Absolute URL addresses', () => { it('should only accept absolute URL addresses with fetch schemes', () => { expectSpecifierMap( @@ -141,7 +87,7 @@ describe('Absolute URL addresses', () => { "blob": "blob:good", "data": "data:good", "file": "file:///good", - "filesystem": "filesystem:good", + "filesystem": "filesystem:http://example.com/good/", "http": "http://good/", "https": "https://good/", "ftp": "ftp://good/", @@ -152,65 +98,20 @@ describe('Absolute URL addresses', () => { }`, 'https://base.example/path1/path2/path3', { - about: [expect.toMatchURL('about:good')], - blob: [expect.toMatchURL('blob:good')], - data: [expect.toMatchURL('data:good')], - file: [expect.toMatchURL('file:///good')], - filesystem: [expect.toMatchURL('filesystem:good')], - http: [expect.toMatchURL('http://good/')], - https: [expect.toMatchURL('https://good/')], - ftp: [expect.toMatchURL('ftp://good/')], - import: [], - mailto: [], - javascript: [], - wss: [] + about: expect.toMatchURL('about:good'), + blob: expect.toMatchURL('blob:good'), + data: expect.toMatchURL('data:good'), + file: expect.toMatchURL('file:///good'), + filesystem: expect.toMatchURL('filesystem:http://example.com/good/'), + http: expect.toMatchURL('http://good/'), + https: expect.toMatchURL('https://good/'), + ftp: expect.toMatchURL('ftp://good/'), + import: expect.toMatchURL('import:bad'), + javascript: expect.toMatchURL('javascript:bad'), + mailto: expect.toMatchURL('mailto:bad'), + wss: expect.toMatchURL('wss://bad/') }, - [ - `Invalid address "import:bad" for the specifier key "import".`, - `Invalid address "mailto:bad" for the specifier key "mailto".`, - `Invalid address "javascript:bad" for the specifier key "javascript".`, - `Invalid address "wss:bad" for the specifier key "wss".` - ] - ); - }); - - it('should only accept absolute URL addresses with fetch schemes inside arrays', () => { - expectSpecifierMap( - `{ - "about": ["about:good"], - "blob": ["blob:good"], - "data": ["data:good"], - "file": ["file:///good"], - "filesystem": ["filesystem:good"], - "http": ["http://good/"], - "https": ["https://good/"], - "ftp": ["ftp://good/"], - "import": ["import:bad"], - "mailto": ["mailto:bad"], - "javascript": ["javascript:bad"], - "wss": ["wss:bad"] - }`, - 'https://base.example/path1/path2/path3', - { - about: [expect.toMatchURL('about:good')], - blob: [expect.toMatchURL('blob:good')], - data: [expect.toMatchURL('data:good')], - file: [expect.toMatchURL('file:///good')], - filesystem: [expect.toMatchURL('filesystem:good')], - http: [expect.toMatchURL('http://good/')], - https: [expect.toMatchURL('https://good/')], - ftp: [expect.toMatchURL('ftp://good/')], - import: [], - mailto: [], - javascript: [], - wss: [] - }, - [ - `Invalid address "import:bad" for the specifier key "import".`, - `Invalid address "mailto:bad" for the specifier key "mailto".`, - `Invalid address "javascript:bad" for the specifier key "javascript".`, - `Invalid address "wss:bad" for the specifier key "wss".` - ] + [] ); }); @@ -228,45 +129,11 @@ describe('Absolute URL addresses', () => { }`, 'https://base.example/path1/path2/path3', { - unparseable1: [], - unparseable2: [], - unparseable3: [], - invalidButParseable1: [expect.toMatchURL('https://example.org/')], - invalidButParseable2: [expect.toMatchURL('https://example.com///')], - prettyNormal: [expect.toMatchURL('https://example.net/')], - percentDecoding: [expect.toMatchURL('https://example.com/')], - noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] - }, - [ - `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, - `Invalid address "https://example.com:demo" for the specifier key "unparseable2".`, - `Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".` - ] - ); - }); - - it('should parse absolute URLs, ignoring unparseable ones inside arrays', () => { - expectSpecifierMap( - `{ - "unparseable1": ["https://ex ample.org/"], - "unparseable2": ["https://example.com:demo"], - "unparseable3": ["http://[www.example.com]/"], - "invalidButParseable1": ["https:example.org"], - "invalidButParseable2": ["https://///example.com///"], - "prettyNormal": ["https://example.net"], - "percentDecoding": ["https://ex%41mple.com/"], - "noPercentDecoding": ["https://example.com/%41"] - }`, - 'https://base.example/path1/path2/path3', - { - unparseable1: [], - unparseable2: [], - unparseable3: [], - invalidButParseable1: [expect.toMatchURL('https://example.org/')], - invalidButParseable2: [expect.toMatchURL('https://example.com///')], - prettyNormal: [expect.toMatchURL('https://example.net/')], - percentDecoding: [expect.toMatchURL('https://example.com/')], - noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] + invalidButParseable1: expect.toMatchURL('https://example.org/'), + invalidButParseable2: expect.toMatchURL('https://example.com///'), + prettyNormal: expect.toMatchURL('https://example.net/'), + percentDecoding: expect.toMatchURL('https://example.com/'), + noPercentDecoding: expect.toMatchURL('https://example.com/%41') }, [ `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, @@ -281,54 +148,12 @@ describe('Failing addresses: mismatched trailing slashes', () => { it('should warn for the simple case', () => { expectSpecifierMap( `{ - "trailer/": "/notrailer", - "${BUILT_IN_MODULE_SCHEME}:trailer/": "/bim-notrailer" + "trailer/": "/notrailer" }`, 'https://base.example/path1/path2/path3', { - 'trailer/': [], - [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] }, - [ - `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, - `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` - ] - ); - }); - - it('should warn for a mismatch alone in an array', () => { - expectSpecifierMap( - `{ - "trailer/": ["/notrailer"], - "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-notrailer"] - }`, - 'https://base.example/path1/path2/path3', - { - 'trailer/': [], - [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] - }, - [ - `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, - `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` - ] - ); - }); - - it('should warn for a mismatch alongside non-mismatches in an array', () => { - expectSpecifierMap( - `{ - "trailer/": ["/atrailer/", "/notrailer"], - "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-atrailer/", "/bim-notrailer"] - }`, - 'https://base.example/path1/path2/path3', - { - 'trailer/': [expect.toMatchURL('https://base.example/atrailer/')], - [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [expect.toMatchURL('https://base.example/bim-atrailer/')] - }, - [ - `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, - `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` - ] + [`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`] ); }); }); @@ -342,7 +167,6 @@ describe('Other invalid addresses', () => { }`, 'https://base.example/path1/path2/path3', { - foo: [] }, [`Invalid address "${bad}" for the specifier key "foo".`] ); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-schema.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-schema.js index 695034533c7..f60422ae62b 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-schema.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-schema.js @@ -45,24 +45,20 @@ describe('Mismatching the top-level schema', () => { }); describe('Mismatching the specifier map schema', () => { - const invalidAddressStrings = ['true', '1', '{}']; - const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]']; + const invalidAddressStrings = ['null', 'true', '1', '{}', '[]', '["https://example.com/"]']; - it('should ignore entries where the address is not a string, array, or null', () => { + it('should ignore entries where the address is not a string', () => { for (const invalid of invalidAddressStrings) { expectSpecifierMap( `{ "foo": ${invalid}, - "bar": ["https://example.com/"] + "bar": "https://example.com/" }`, 'https://base.example/', { - bar: [expect.toMatchURL('https://example.com/')] + bar: expect.toMatchURL('https://example.com/') }, - [ - `Invalid address ${invalid} for the specifier key "foo". ` + - `Addresses must be strings, arrays, or null.` - ] + [`Invalid address ${invalid} for the specifier key "foo". Addresses must be strings.`] ); } }); @@ -70,7 +66,7 @@ describe('Mismatching the specifier map schema', () => { it('should ignore entries where the specifier key is an empty string', () => { expectSpecifierMap( `{ - "": ["https://example.com/"] + "": "https://example.com/" }`, 'https://base.example/', {}, @@ -78,26 +74,6 @@ describe('Mismatching the specifier map schema', () => { ); }); - it('should ignore members of an address array that are not strings', () => { - for (const invalid of invalidInsideArrayStrings) { - expectSpecifierMap( - `{ - "foo": ["https://example.com/", ${invalid}], - "bar": ["https://example.com/"] - }`, - 'https://base.example/', - { - foo: [expect.toMatchURL('https://example.com/')], - bar: [expect.toMatchURL('https://example.com/')] - }, - [ - `Invalid address ${invalid} inside the address array for the specifier key "foo". ` + - `Address arrays must only contain strings.` - ] - ); - } - }); - it('should throw if a scope\'s value is not an object', () => { for (const invalid of nonObjectStrings) { expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/'); @@ -120,20 +96,4 @@ describe('Normalization', () => { expect(parseFromString(`{ "imports": {} }`, 'https://base.example/')) .toEqual({ imports: {}, scopes: {} }); }); - - it('should normalize addresses to arrays', () => { - expectSpecifierMap( - `{ - "foo": "https://example.com/1", - "bar": ["https://example.com/2"], - "baz": null - }`, - 'https://base.example/', - { - foo: [expect.toMatchURL('https://example.com/1')], - bar: [expect.toMatchURL('https://example.com/2')], - baz: [] - } - ); - }); }); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-scope-keys.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-scope-keys.js index cd1d9b34890..4993f3a9a8b 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-scope-keys.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-scope-keys.js @@ -62,14 +62,14 @@ describe('Relative URL scope keys', () => { }); describe('Absolute URL scope keys', () => { - it('should only accept absolute URL scope keys with fetch schemes', () => { + it('should accept all absolute URL scope keys, with or without fetch schemes', () => { expectScopes( [ 'about:good', 'blob:good', 'data:good', 'file:///good', - 'filesystem:good', + 'filesystem:http://example.com/good/', 'http://good/', 'https://good/', 'ftp://good/', @@ -84,17 +84,16 @@ describe('Absolute URL scope keys', () => { 'blob:good', 'data:good', 'file:///good', - 'filesystem:good', + 'filesystem:http://example.com/good/', 'http://good/', 'https://good/', - 'ftp://good/' + 'ftp://good/', + 'import:bad', + 'mailto:bad', + 'javascript:bad', + 'wss://ba/' ], - [ - 'Invalid scope "import:bad". Scope URLs must have a fetch scheme.', - 'Invalid scope "mailto:bad". Scope URLs must have a fetch scheme.', - 'Invalid scope "javascript:bad". Scope URLs must have a fetch scheme.', - 'Invalid scope "wss://ba/". Scope URLs must have a fetch scheme.' - ] + [] ); }); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-specifier-keys.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-specifier-keys.js index 9eb423a19eb..7ac24bf867b 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-specifier-keys.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/parsing-specifier-keys.js @@ -1,8 +1,5 @@ 'use strict'; const { expectSpecifierMap } = require('./helpers/parsing.js'); -const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); - -const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`; describe('Relative URL-like specifier keys', () => { it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => { @@ -14,9 +11,9 @@ describe('Relative URL-like specifier keys', () => { }`, 'https://base.example/path1/path2/path3', { - 'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')], - 'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')], - 'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')] + 'https://base.example/path1/path2/foo': expect.toMatchURL('https://base.example/dotslash'), + 'https://base.example/path1/foo': expect.toMatchURL('https://base.example/dotdotslash'), + 'https://base.example/foo': expect.toMatchURL('https://base.example/slash') } ); }); @@ -30,9 +27,9 @@ describe('Relative URL-like specifier keys', () => { }`, 'data:text/html,test', { - './foo': [expect.toMatchURL('https://example.com/dotslash')], - '../foo': [expect.toMatchURL('https://example.com/dotdotslash')], - '/foo': [expect.toMatchURL('https://example.com/slash')] + './foo': expect.toMatchURL('https://example.com/dotslash'), + '../foo': expect.toMatchURL('https://example.com/dotdotslash'), + '/foo': expect.toMatchURL('https://example.com/slash') } ); }); @@ -46,9 +43,9 @@ describe('Relative URL-like specifier keys', () => { }`, 'https://base.example/path1/path2/path3', { - 'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')], - 'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')], - 'https://base.example/': [expect.toMatchURL('https://base.example/slash/')] + 'https://base.example/path1/path2/': expect.toMatchURL('https://base.example/dotslash/'), + 'https://base.example/path1/': expect.toMatchURL('https://base.example/dotdotslash/'), + 'https://base.example/': expect.toMatchURL('https://base.example/slash/') } ); }); @@ -66,27 +63,27 @@ describe('Relative URL-like specifier keys', () => { }`, 'https://base.example/path1/path2/path3', { - '%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')], - '%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')], - '.%2F': [expect.toMatchURL('https://base.example/dotSlash2')], - '..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')], - '%2F': [expect.toMatchURL('https://base.example/slash2')], - '%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')], - '%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')] + '%2E/': expect.toMatchURL('https://base.example/dotSlash1/'), + '%2E%2E/': expect.toMatchURL('https://base.example/dotDotSlash1/'), + '.%2F': expect.toMatchURL('https://base.example/dotSlash2'), + '..%2F': expect.toMatchURL('https://base.example/dotDotSlash2'), + '%2F': expect.toMatchURL('https://base.example/slash2'), + '%2E%2F': expect.toMatchURL('https://base.example/dotSlash3'), + '%2E%2E%2F': expect.toMatchURL('https://base.example/dotDotSlash3') } ); }); }); describe('Absolute URL specifier keys', () => { - it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => { + it('Accept all absolute URL specifier keys even with fetch schemes as URLs', () => { expectSpecifierMap( `{ "about:good": "/about", "blob:good": "/blob", "data:good": "/data", "file:///good": "/file", - "filesystem:good": "/filesystem", + "filesystem:http://example.com/good/": "/filesystem/", "http://good/": "/http/", "https://good/": "/https/", "ftp://good/": "/ftp/", @@ -97,18 +94,18 @@ describe('Absolute URL specifier keys', () => { }`, 'https://base.example/path1/path2/path3', { - 'about:good': [expect.toMatchURL('https://base.example/about')], - 'blob:good': [expect.toMatchURL('https://base.example/blob')], - 'data:good': [expect.toMatchURL('https://base.example/data')], - 'file:///good': [expect.toMatchURL('https://base.example/file')], - 'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')], - 'http://good/': [expect.toMatchURL('https://base.example/http/')], - 'https://good/': [expect.toMatchURL('https://base.example/https/')], - 'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')], - 'import:bad': [expect.toMatchURL('https://base.example/import')], - 'mailto:bad': [expect.toMatchURL('https://base.example/mailto')], - 'javascript:bad': [expect.toMatchURL('https://base.example/javascript')], - 'wss:bad': [expect.toMatchURL('https://base.example/wss')] + 'about:good': expect.toMatchURL('https://base.example/about'), + 'blob:good': expect.toMatchURL('https://base.example/blob'), + 'data:good': expect.toMatchURL('https://base.example/data'), + 'file:///good': expect.toMatchURL('https://base.example/file'), + 'filesystem:http://example.com/good/': expect.toMatchURL('https://base.example/filesystem/'), + 'http://good/': expect.toMatchURL('https://base.example/http/'), + 'https://good/': expect.toMatchURL('https://base.example/https/'), + 'ftp://good/': expect.toMatchURL('https://base.example/ftp/'), + 'import:bad': expect.toMatchURL('https://base.example/import'), + 'mailto:bad': expect.toMatchURL('https://base.example/mailto'), + 'javascript:bad': expect.toMatchURL('https://base.example/javascript'), + 'wss://bad/': expect.toMatchURL('https://base.example/wss') } ); }); @@ -127,32 +124,40 @@ describe('Absolute URL specifier keys', () => { }`, 'https://base.example/path1/path2/path3', { - 'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')], - 'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')], - 'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')], - 'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')], - 'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')], - 'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')], - 'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')], - 'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')] + 'https://ex ample.org/': expect.toMatchURL('https://base.example/unparseable1/'), + 'https://example.com:demo': expect.toMatchURL('https://base.example/unparseable2'), + 'http://[www.example.com]/': expect.toMatchURL('https://base.example/unparseable3/'), + 'https://example.org/': expect.toMatchURL('https://base.example/invalidButParseable1/'), + 'https://example.com///': expect.toMatchURL('https://base.example/invalidButParseable2/'), + 'https://example.net/': expect.toMatchURL('https://base.example/prettyNormal/'), + 'https://example.com/': expect.toMatchURL('https://base.example/percentDecoding/'), + 'https://example.com/%41': expect.toMatchURL('https://base.example/noPercentDecoding') } ); }); - it('should parse built-in module specifier keys, including with a "/"', () => { + it('should sort correctly (issue #181)', () => { expectSpecifierMap( `{ - "${BLANK}": "/blank", - "${BLANK}/": "/blank/", - "${BLANK}/foo": "/blank/foo", - "${BLANK}\\\\foo": "/blank/backslashfoo" + "https://example.com/aaa": "https://example.com/aaa", + "https://example.com/a": "https://example.com/a" }`, - 'https://base.example/path1/path2/path3', + 'https://base.example/', + { + 'https://example.com/aaa': expect.toMatchURL('https://example.com/aaa'), + 'https://example.com/a': expect.toMatchURL('https://example.com/a') + } + ); + + expectSpecifierMap( + `{ + "https://example.com/a": "https://example.com/a", + "https://example.com/aaa": "https://example.com/aaa" + }`, + 'https://base.example/', { - [BLANK]: [expect.toMatchURL('https://base.example/blank')], - [`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')], - [`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')], - [`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')] + 'https://example.com/aaa': expect.toMatchURL('https://example.com/aaa'), + 'https://example.com/a': expect.toMatchURL('https://example.com/a') } ); }); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-scopes.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-scopes.js index ca19a668406..d133b50bd2b 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-scopes.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving-scopes.js @@ -16,20 +16,6 @@ describe('Mapped using scope instead of "imports"', () => { const inJSDirURL = new URL('https://example.com/js/app.mjs'); const topLevelURL = new URL('https://example.com/app.mjs'); - it('should fail when the mapping is to an empty array', () => { - const resolveUnderTest = makeResolveUnderTest(`{ - "scopes": { - "/js/": { - "moment": null, - "lodash": [] - } - } - }`); - - expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError); - expect(() => resolveUnderTest('lodash', inJSDirURL)).toThrow(TypeError); - }); - describe('Exact vs. prefix based matching', () => { it('should match correctly when both are in the map', () => { const resolveUnderTest = makeResolveUnderTest(`{ @@ -153,14 +139,17 @@ describe('Mapped using scope instead of "imports"', () => { "imports": { "a": "/a-1.mjs", "b": "/b-1.mjs", - "c": "/c-1.mjs" + "c": "/c-1.mjs", + "d": "/d-1.mjs" }, "scopes": { "/scope2/": { - "a": "/a-2.mjs" + "a": "/a-2.mjs", + "d": "/d-2.mjs" }, "/scope2/scope3/": { - "b": "/b-3.mjs" + "b": "/b-3.mjs", + "d": "/d-3.mjs" } } }`); @@ -173,18 +162,21 @@ describe('Mapped using scope instead of "imports"', () => { expect(resolveUnderTest('a', scope1URL)).toMatchURL('https://example.com/a-1.mjs'); expect(resolveUnderTest('b', scope1URL)).toMatchURL('https://example.com/b-1.mjs'); expect(resolveUnderTest('c', scope1URL)).toMatchURL('https://example.com/c-1.mjs'); + expect(resolveUnderTest('d', scope1URL)).toMatchURL('https://example.com/d-1.mjs'); }); it('should use a direct scope override', () => { expect(resolveUnderTest('a', scope2URL)).toMatchURL('https://example.com/a-2.mjs'); expect(resolveUnderTest('b', scope2URL)).toMatchURL('https://example.com/b-1.mjs'); expect(resolveUnderTest('c', scope2URL)).toMatchURL('https://example.com/c-1.mjs'); + expect(resolveUnderTest('d', scope2URL)).toMatchURL('https://example.com/d-2.mjs'); }); it('should use an indirect scope override', () => { expect(resolveUnderTest('a', scope3URL)).toMatchURL('https://example.com/a-2.mjs'); expect(resolveUnderTest('b', scope3URL)).toMatchURL('https://example.com/b-3.mjs'); expect(resolveUnderTest('c', scope3URL)).toMatchURL('https://example.com/c-1.mjs'); + expect(resolveUnderTest('d', scope3URL)).toMatchURL('https://example.com/d-3.mjs'); }); }); diff --git a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving.js b/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving.js index 29ee31ccbc9..ef8a4f87d25 100644 --- a/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving.js +++ b/tests/wpt/web-platform-tests/import-maps/imported/resources/resolving.js @@ -42,11 +42,11 @@ describe('Unmapped', () => { expect(resolveUnderTest('https://///example.com///')).toMatchURL('https://example.com///'); }); - it('should fail for absolute non-fetch-scheme URLs', () => { - expect(() => resolveUnderTest('mailto:bad')).toThrow(TypeError); - expect(() => resolveUnderTest('import:bad')).toThrow(TypeError); - expect(() => resolveUnderTest('javascript:bad')).toThrow(TypeError); - expect(() => resolveUnderTest('wss:bad')).toThrow(TypeError); + it('should parse absolute non-fetch-scheme URLs', () => { + expect(resolveUnderTest('mailto:bad')).toMatchURL('mailto:bad'); + expect(resolveUnderTest('import:bad')).toMatchURL('import:bad'); + expect(resolveUnderTest('javascript:bad')).toMatchURL('javascript:bad'); + expect(resolveUnderTest('wss:bad')).toMatchURL('wss://bad/'); }); it('should fail for strings not parseable as absolute URLs and not starting with ./ ../ or /', () => { @@ -64,18 +64,6 @@ describe('Unmapped', () => { }); describe('Mapped using the "imports" key only (no scopes)', () => { - it('should fail when the mapping is to an empty array', () => { - const resolveUnderTest = makeResolveUnderTest(`{ - "imports": { - "moment": null, - "lodash": [] - } - }`); - - expect(() => resolveUnderTest('moment')).toThrow(TypeError); - expect(() => resolveUnderTest('lodash')).toThrow(TypeError); - }); - describe('Package-like scenarios', () => { const resolveUnderTest = makeResolveUnderTest(`{ "imports": { @@ -84,8 +72,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => { "lodash-dot": "./node_modules/lodash-es/lodash.js", "lodash-dot/": "./node_modules/lodash-es/", "lodash-dotdot": "../node_modules/lodash-es/lodash.js", - "lodash-dotdot/": "../node_modules/lodash-es/", - "nowhere/": [] + "lodash-dotdot/": "../node_modules/lodash-es/" } }`); @@ -110,10 +97,6 @@ describe('Mapped using the "imports" key only (no scopes)', () => { expect(() => resolveUnderTest('underscore/')).toThrow(TypeError); expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError); }); - - it('should fail for package submodules that map to nowhere', () => { - expect(() => resolveUnderTest('nowhere/foo')).toThrow(TypeError); - }); }); describe('Tricky specifiers', () => { @@ -121,6 +104,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => { "imports": { "package/withslash": "/node_modules/package-with-slash/index.mjs", "not-a-package": "/lib/not-a-package.mjs", + "only-slash/": "/lib/only-slash/", ".": "/lib/dot.mjs", "..": "/lib/dotdot.mjs", "..\\\\": "/lib/dotdotbackslash.mjs", @@ -144,20 +128,19 @@ describe('Mapped using the "imports" key only (no scopes)', () => { it('should fail for attempting to get a submodule of something not declared with a trailing slash', () => { expect(() => resolveUnderTest('not-a-package/foo')).toThrow(TypeError); }); + + it('should fail for attempting to get a module if only a trailing-slash version is present', () => { + expect(() => resolveUnderTest('only-slash')).toThrow(TypeError); + }); }); describe('URL-like specifiers', () => { const resolveUnderTest = makeResolveUnderTest(`{ "imports": { - "/node_modules/als-polyfill/index.mjs": "std:kv-storage", - "/lib/foo.mjs": "./more/bar.mjs", "./dotrelative/foo.mjs": "/lib/dot.mjs", "../dotdotrelative/foo.mjs": "/lib/dotdot.mjs", - "/lib/no.mjs": null, - "./dotrelative/no.mjs": [], - "/": "/lib/slash-only/", "./": "/lib/dotslash-only/", @@ -181,16 +164,6 @@ describe('Mapped using the "imports" key only (no scopes)', () => { expect(resolveUnderTest('../dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs'); }); - it('should fail for URLs that remap to empty arrays', () => { - expect(() => resolveUnderTest('https://example.com/lib/no.mjs')).toThrow(TypeError); - expect(() => resolveUnderTest('/lib/no.mjs')).toThrow(TypeError); - expect(() => resolveUnderTest('../lib/no.mjs')).toThrow(TypeError); - - expect(() => resolveUnderTest('https://example.com/app/dotrelative/no.mjs')).toThrow(TypeError); - expect(() => resolveUnderTest('/app/dotrelative/no.mjs')).toThrow(TypeError); - expect(() => resolveUnderTest('../app/dotrelative/no.mjs')).toThrow(TypeError); - }); - it('should remap URLs that are just composed from / and .', () => { expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only/'); expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only/'); @@ -212,7 +185,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => { }); describe('Overlapping entries with trailing slashes', () => { - it('should favor the most-specific key (no empty arrays)', () => { + it('should favor the most-specific key', () => { const resolveUnderTest = makeResolveUnderTest(`{ "imports": { "a": "/1", @@ -229,11 +202,9 @@ describe('Mapped using the "imports" key only (no scopes)', () => { expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); }); - it('should favor the most-specific key when empty arrays are involved for less-specific keys', () => { + it('should favor the most-specific key when there are no mappings for less-specific keys', () => { const resolveUnderTest = makeResolveUnderTest(`{ "imports": { - "a": [], - "a/": [], "a/b": "/3", "a/b/": "/4/" } @@ -247,24 +218,15 @@ describe('Mapped using the "imports" key only (no scopes)', () => { expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); expect(() => resolveUnderTest('a/x/c')).toThrow(TypeError); }); + }); - it('should favor the most-specific key when empty arrays are involved for more-specific keys', () => { - const resolveUnderTest = makeResolveUnderTest(`{ - "imports": { - "a": "/1", - "a/": "/2/", - "a/b": [], - "a/b/": [] - } - }`); + it('should deal with data: URL bases', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "foo/": "data:text/javascript,foo/" + } + }`); - expect(resolveUnderTest('a')).toMatchURL('https://example.com/1'); - expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/'); - expect(resolveUnderTest('a/x')).toMatchURL('https://example.com/2/x'); - expect(() => resolveUnderTest('a/b')).toThrow(TypeError); - expect(() => resolveUnderTest('a/b/')).toThrow(TypeError); - expect(() => resolveUnderTest('a/b/c')).toThrow(TypeError); - expect(resolveUnderTest('a/x/c')).toMatchURL('https://example.com/2/x/c'); - }); + expect(() => resolveUnderTest('foo/bar')).toThrow(TypeError); }); }); diff --git a/tests/wpt/web-platform-tests/import-maps/resources/jest-test-helper.js b/tests/wpt/web-platform-tests/import-maps/resources/jest-test-helper.js index 8d9236a84d8..8fa7b65adb5 100644 --- a/tests/wpt/web-platform-tests/import-maps/resources/jest-test-helper.js +++ b/tests/wpt/web-platform-tests/import-maps/resources/jest-test-helper.js @@ -15,6 +15,22 @@ function require(name) { }, exports); } +// Sort keys and then stringify for comparison. +function stringifyImportMap(importMap) { + function getKeys(m) { + if (typeof m !== 'object') + return []; + + let keys = []; + for (const key in m) { + keys.push(key); + keys = keys.concat(getKeys(m[key])); + } + return keys; + } + return JSON.stringify(importMap, getKeys(importMap).sort()); +} + function expect(v) { return { toMatchURL: expected => assert_equals(v, expected), @@ -34,10 +50,8 @@ function expect(v) { const actualParsedImportMap = JSON.parse( internals.getParsedImportMap(v.contentDocument)); assert_equals( - JSON.stringify(actualParsedImportMap, - Object.keys(actualParsedImportMap).sort()), - JSON.stringify(expected.imports, - Object.keys(expected.imports).sort()) + stringifyImportMap(actualParsedImportMap), + stringifyImportMap(expected) ); } else { assert_object_equals(v, expected); @@ -75,6 +89,11 @@ function it(message, f) { // Currently document.write() is used to make everything synchronous, which // is just needed for running the existing Jest-based tests easily. function parseFromString(mapString, mapBaseURL) { + // We can't test data: base URLs because <base> rejects data: URLs. + if (new URL(mapBaseURL).protocol === 'data:') { + throw Error('test helper does not support data: base URLs'); + } + const iframe = document.createElement('iframe'); document.body.appendChild(iframe); iframe.contentDocument.write(` diff --git a/tests/wpt/web-platform-tests/import-maps/resources/test-helper.js b/tests/wpt/web-platform-tests/import-maps/resources/test-helper.js index 2447bfb9435..f21ad935baa 100644 --- a/tests/wpt/web-platform-tests/import-maps/resources/test-helper.js +++ b/tests/wpt/web-platform-tests/import-maps/resources/test-helper.js @@ -153,7 +153,7 @@ function testStaticImport(importMapString, importMapBaseURL, specifier, expected const script = document.createElement("script"); script.setAttribute("type", "module"); script.setAttribute("src", - "/import-maps/static-import.js?pipe=sub(none)&url=" + + "static-import.js?pipe=sub(none)&url=" + encodeURIComponent("${specifier}")); script.addEventListener("load", handlers[Handler.ScriptLoadEvent]); script.addEventListener("error", handlers[Handler.ScriptErrorEvent]); diff --git a/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini new file mode 100644 index 00000000000..8587775d8fc --- /dev/null +++ b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini @@ -0,0 +1,3 @@ +[ahem.html] + expected: + if product == "safari": FAIL # system fonts not loaded since macOS Mojave diff --git a/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini index c9fbabede6d..c6f136d9715 100644 --- a/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini +++ b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini @@ -2,7 +2,10 @@ expected: if product == "safari": ERROR # https://bugs.webkit.org/show_bug.cgi?id=190775 - [<audio> autoplay] expected: if product == "safari": FAIL # https://bugs.webkit.org/show_bug.cgi?id=190775 + + [<video> autoplay] + expected: + if product == "safari": TIMEOUT # https://bugs.webkit.org/show_bug.cgi?id=190775 diff --git a/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/actions/elementTiming.html.ini b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/actions/elementTiming.html.ini new file mode 100644 index 00000000000..fb4b51df66d --- /dev/null +++ b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/actions/elementTiming.html.ini @@ -0,0 +1,4 @@ +[elementTiming.html] + [TestDriver actions: element timing] + expected: + if product == "safari": FAIL diff --git a/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini new file mode 100644 index 00000000000..d652b02787f --- /dev/null +++ b/tests/wpt/web-platform-tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini @@ -0,0 +1,31 @@ +[bless.html] + expected: + if product == "safari": TIMEOUT + + [functions in the absence of a `body` element] + expected: + if product == "safari": TIMEOUT + + [user activation] + expected: + if product == "safari": NOTRUN + + [no action function provided] + expected: + if product == "safari": NOTRUN + + [synchronous return value] + expected: + if product == "safari": NOTRUN + + [synchronous error] + expected: + if product == "safari": NOTRUN + + [asynchronous return value] + expected: + if product == "safari": NOTRUN + + [asynchronous error] + expected: + if product == "safari": NOTRUN diff --git a/tests/wpt/web-platform-tests/interfaces/META.yml b/tests/wpt/web-platform-tests/interfaces/META.yml index 6895a5fc567..c1dd8dddf9e 100644 --- a/tests/wpt/web-platform-tests/interfaces/META.yml +++ b/tests/wpt/web-platform-tests/interfaces/META.yml @@ -1,3 +1,2 @@ suggested_reviewers: - foolip - - lukebjerring diff --git a/tests/wpt/web-platform-tests/interfaces/README.md b/tests/wpt/web-platform-tests/interfaces/README.md index f70ffd2e11e..e0cdf0bc8fb 100644 --- a/tests/wpt/web-platform-tests/interfaces/README.md +++ b/tests/wpt/web-platform-tests/interfaces/README.md @@ -2,4 +2,4 @@ This directory contains [Web IDL](https://heycam.github.io/webidl/) interface de The `.idl` files are extracted from specs by [Reffy](https://github.com/tidoust/reffy) into [reffy-reports](https://github.com/tidoust/reffy-reports), and a [sync script](https://github.com/tidoust/reffy-reports/blob/master/wpt-sync/sync.js) sends [automatic PRs](https://github.com/web-platform-tests/wpt/pulls/autofoolip). The PRs require manual review but can be approved/merged by anyone with write access. -If some IDL in this directory is not up to date with the spec, first look for an [open PR](https://github.com/web-platform-tests/wpt/pulls/autofoolip) and if there is none [file an issue on reffy-reports](https://github.com/tidoust/reffy-reports/issues) and notify @foolip and @lukebjerring. +If some IDL in this directory is not up to date with the spec, first look for an [open PR](https://github.com/web-platform-tests/wpt/pulls/autofoolip) and if there is none [file an issue on reffy-reports](https://github.com/tidoust/reffy-reports/issues) and notify @foolip. diff --git a/tests/wpt/web-platform-tests/interfaces/css-shadow-parts.idl b/tests/wpt/web-platform-tests/interfaces/css-shadow-parts.idl new file mode 100644 index 00000000000..66aaeba73a7 --- /dev/null +++ b/tests/wpt/web-platform-tests/interfaces/css-shadow-parts.idl @@ -0,0 +1,8 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into reffy-reports +// (https://github.com/tidoust/reffy-reports) +// Source: CSS Shadow Parts (http://drafts.csswg.org/css-shadow-parts/) + +partial interface Element { + [SameObject, PutForwards=value] readonly attribute DOMTokenList part; +}; diff --git a/tests/wpt/web-platform-tests/interfaces/reporting.idl b/tests/wpt/web-platform-tests/interfaces/reporting.idl index 05d5a42458b..f5370e8f1e6 100644 --- a/tests/wpt/web-platform-tests/interfaces/reporting.idl +++ b/tests/wpt/web-platform-tests/interfaces/reporting.idl @@ -5,10 +5,12 @@ [Exposed=(Window,Worker)] interface ReportBody { + [Default] object toJSON(); }; [Exposed=(Window,Worker)] interface Report { + [Default] object toJSON(); readonly attribute DOMString type; readonly attribute DOMString url; readonly attribute ReportBody? body; @@ -33,6 +35,7 @@ typedef sequence<Report> ReportList; [Exposed=(Window,Worker)] interface DeprecationReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString id; readonly attribute Date? anticipatedRemoval; readonly attribute DOMString message; @@ -43,6 +46,7 @@ interface DeprecationReportBody : ReportBody { [Exposed=(Window,Worker)] interface InterventionReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString id; readonly attribute DOMString message; readonly attribute DOMString? sourceFile; @@ -52,6 +56,7 @@ interface InterventionReportBody : ReportBody { [Exposed=(Window,Worker)] interface CrashReportBody : ReportBody { + [Default] object toJSON(); readonly attribute DOMString? reason; }; diff --git a/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl b/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl index 6ff45e7050c..be58b63b2c3 100644 --- a/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl +++ b/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl @@ -3,7 +3,6 @@ typedef (DOMString or TrustedHTML) HTMLString; typedef (DOMString or TrustedScript) ScriptString; typedef (DOMString or TrustedScriptURL) ScriptURLString; -typedef (USVString or TrustedURL) URLString; [Exposed=(Window, Worker)] interface TrustedHTML { @@ -21,11 +20,6 @@ interface TrustedScriptURL { }; [Exposed=(Window, Worker)] -interface TrustedURL { - stringifier; -}; - -[Exposed=(Window, Worker)] interface TrustedTypePolicyFactory { [Unforgeable] TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions); // All the policy object names that have been created @@ -38,14 +32,12 @@ interface TrustedTypePolicy { [Unforgeable] TrustedHTML createHTML(DOMString input); [Unforgeable] TrustedScript createScript(DOMString input); [Unforgeable] TrustedScriptURL createScriptURL(DOMString input); - [Unforgeable] TrustedURL createURL(DOMString input); }; dictionary TrustedTypePolicyOptions { CreateHTMLCallback createHTML; CreateScriptCallback createScript; CreateURLCallback createScriptURL; - CreateURLCallback createURL; }; callback CreateHTMLCallback = DOMString (DOMString input); diff --git a/tests/wpt/web-platform-tests/interfaces/web-nfc.idl b/tests/wpt/web-platform-tests/interfaces/web-nfc.idl index 4e0dc072516..5f0dd23a1cd 100644 --- a/tests/wpt/web-platform-tests/interfaces/web-nfc.idl +++ b/tests/wpt/web-platform-tests/interfaces/web-nfc.idl @@ -10,16 +10,20 @@ interface NDEFMessage { }; dictionary NDEFMessageInit { - sequence<NDEFRecordInit> records; + required sequence<NDEFRecordInit> records; }; [Exposed=Window] interface NDEFRecord { constructor(NDEFRecordInit recordInit); - readonly attribute NDEFRecordType recordType; + readonly attribute USVString recordType; readonly attribute USVString mediaType; readonly attribute USVString id; + readonly attribute DataView? data; + + readonly attribute USVString? encoding; + readonly attribute USVString? lang; USVString? text(); [NewObject] ArrayBuffer? arrayBuffer(); @@ -28,16 +32,17 @@ interface NDEFRecord { }; dictionary NDEFRecordInit { - NDEFRecordType recordType; + required USVString recordType; USVString mediaType; USVString id; + USVString encoding; + USVString lang; + any data; }; -typedef DOMString NDEFRecordType; - -typedef (DOMString or ArrayBuffer or NDEFMessageInit) NDEFMessageSource; +typedef (DOMString or BufferSource or NDEFMessageInit) NDEFMessageSource; [SecureContext, Exposed=Window] interface NFCWriter { @@ -84,6 +89,7 @@ dictionary NFCPushOptions { NFCPushTarget target = "any"; unrestricted double timeout = Infinity; boolean ignoreRead = true; + boolean overwrite = true; AbortSignal? signal; }; @@ -95,7 +101,7 @@ enum NFCPushTarget { dictionary NFCScanOptions { USVString id = ""; - NDEFRecordType recordType; + USVString recordType; USVString mediaType = ""; AbortSignal? signal; }; diff --git a/tests/wpt/web-platform-tests/intersection-observer/document-scrolling-element-root.html b/tests/wpt/web-platform-tests/intersection-observer/document-scrolling-element-root.html new file mode 100644 index 00000000000..9996299312c --- /dev/null +++ b/tests/wpt/web-platform-tests/intersection-observer/document-scrolling-element-root.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./resources/intersection-observer-test-utils.js"></script> + +<style> +pre, #log { + position: absolute; + top: 0; + left: 200px; +} +iframe { + height: 250px; + width: 150px; + border: 0; +} +</style> +<iframe id="target-iframe" src="resources/iframe-no-root-subframe.html"></iframe> + +<script> +var iframe = document.getElementById("target-iframe"); +var target; +var root; +var entries = []; + +iframe.onload = function() { + runTestCycle(function() { + assert_true(!!iframe, "iframe exists"); + + root = iframe.contentDocument.scrollingElement; + assert_true(!!root, "Root element exists."); + target = iframe.contentDocument.getElementById("target"); + assert_true(!!target, "Target element exists."); + var observer = new IntersectionObserver(function(changes) { + entries = entries.concat(changes) + }, { root: root }); + observer.observe(target); + entries = entries.concat(observer.takeRecords()); + assert_equals(entries.length, 0, "No initial notifications."); + runTestCycle(step0, "First rAF."); + }, "Observer with explicit root which is the document's scrolling element."); +}; + +function step0() { + let vw = iframe.contentDocument.documentElement.clientWidth; + let vh = iframe.contentDocument.documentElement.clientHeight; + // The target element is partially clipped by the iframe's root scroller, so + // height of the intersection rect is (250 - 208) == 42. + checkLastEntry(entries, 0, [8, 108, 208, 308, 8, 108, 208, 250, 0, vw, 0, vh, true]); +} +</script> diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html b/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html new file mode 100644 index 00000000000..a49a83f346d --- /dev/null +++ b/tests/wpt/web-platform-tests/largest-contentful-paint/first-paint-equals-lcp-text.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>LargestContentfulPaint compared with FirstPaint and FirstContentfulPaint on single text page.</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + async_test(function (t) { + if (!window.PerformancePaintTiming) { + assert_unreached("PerformancePaintTiming is not implemented"); + } + if (!window.LargestContentfulPaint) { + assert_unreached("LargestContentfulPaint is not implemented"); + } + let firstPaintTime = 0; + let firstContentfulPaintTime = 0; + let largestContentfulPaintTime = 0; + const observer = new PerformanceObserver( + t.step_func(function(entryList) { + entryList.getEntries().forEach(entry => { + if (entry.name === 'first-paint') { + assert_equals(firstPaintTime, 0, 'Only one first-paint entry.'); + assert_equals(entry.entryType, 'paint'); + firstPaintTime = entry.startTime; + } else if (entry.name === 'first-contentful-paint') { + assert_equals(firstContentfulPaintTime, 0, 'Only one first-contentful-paint entry.'); + assert_equals(entry.entryType, 'paint'); + firstContentfulPaintTime = entry.startTime; + } else { + assert_equals(largestContentfulPaintTime, 0, 'Only one largest-contentful-paint entry.'); + assert_equals(entry.entryType, 'largest-contentful-paint'); + largestContentfulPaintTime = entry.renderTime; + } + if (firstPaintTime && firstContentfulPaintTime && largestContentfulPaintTime) { + assert_less_than_equal(firstPaintTime, firstContentfulPaintTime, 'FP should be less than or equal to FCP.'); + assert_equals(firstContentfulPaintTime, largestContentfulPaintTime, 'FCP should equal LCP.'); + t.done(); + } + }); + }) + ); + observer.observe({type: 'largest-contentful-paint', buffered: true}); + observer.observe({type: 'paint', buffered: true}); + }, 'FCP and LCP are the same when there is a single text element in the page.'); +</script> +<p>Text</p> +</body> diff --git a/tests/wpt/web-platform-tests/lint.whitelist b/tests/wpt/web-platform-tests/lint.whitelist index d9ea5c17c7c..afdc20b67b5 100644 --- a/tests/wpt/web-platform-tests/lint.whitelist +++ b/tests/wpt/web-platform-tests/lint.whitelist @@ -313,6 +313,7 @@ SET TIMEOUT: html/cross-origin-embedder-policy/resources/navigate-none.sub.html SET TIMEOUT: html/cross-origin-embedder-policy/resources/navigate-require-corp.sub.html SET TIMEOUT: html/dom/documents/dom-tree-accessors/Document.currentScript.html SET TIMEOUT: html/webappapis/timers/* +SET TIMEOUT: portals/history/resources/portal-harness.js SET TIMEOUT: resources/chromium/* SET TIMEOUT: resources/test/tests/functional/add_cleanup.html SET TIMEOUT: resources/test/tests/functional/add_cleanup_async.html diff --git a/tests/wpt/web-platform-tests/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html b/tests/wpt/web-platform-tests/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html index fa9a5fb3c5b..b9172dddb4c 100644 --- a/tests/wpt/web-platform-tests/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html +++ b/tests/wpt/web-platform-tests/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html @@ -27,7 +27,7 @@ var captureGot = false; - setup({ explicit_done: true }); + setup({ single_test: true }); add_completion_callback(showPointerTypes); function run() { @@ -49,9 +49,7 @@ // When the setPointerCapture method is invoked, if the specified pointer is not in active button state, then the method must have no effect on subsequent pointer events. // TA: 13.2 on_event(target0, "pointerout", function (event) { - test(function() { - assert_false(captureGot, "pointer capture is not set while button state is inactive") - }, "pointer capture is not set while button state is inactive"); + assert_false(captureGot, "pointer capture is not set while button state is inactive") // Make sure the test finishes after all the input actions are completed. actions_promise.then( () => { done(); diff --git a/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal-with-subframes.html b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal-with-subframes.html new file mode 100644 index 00000000000..8f69182f646 --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal-with-subframes.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/run-test-in-portal.js"></script> +<body> +<script> + var portalSrc = + 'resources/portal-manipulate-history-with-subframes.sub.html'; + + // Runs before and after the history manipulation in the portal to confirm + // that the session history of the portal host is not affected by any history + // changes in the portal. + function assertInitialHistoryState() { + assert_equals(history.length, 1); + assert_false(!!history.state); + } + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testIFrameSrcInPortal'); + assertInitialHistoryState(); + }, 'Setting iframe src navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testCrossSiteIFrameSrcInPortal'); + assertInitialHistoryState(); + }, 'Setting cross site iframe src navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testIFrameNavInPortal'); + assertInitialHistoryState(); + }, 'iframe navigates itself independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testCrossSiteIFrameNavInPortal'); + assertInitialHistoryState(); + }, 'Cross site iframe navigates itself independently in a portal'); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html new file mode 100644 index 00000000000..0fe88c4ea11 --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/history-manipulation-inside-portal.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/run-test-in-portal.js"></script> +<body> +<script> + var portalSrc = + 'resources/portal-manipulate-history.html'; + + // Runs before and after the history manipulation in the portal to confirm + // that the session history of the portal host is not affected by any history + // changes in the portal. + function assertInitialHistoryState() { + assert_equals(history.length, 1); + assert_false(!!history.state); + } + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testHistoryPushStateInPortal'); + assertInitialHistoryState(); + }, 'history.pushState navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testHistoryReplaceStateInPortal'); + assertInitialHistoryState(); + }, 'history.replaceState navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testLocationAssignInPortal'); + assertInitialHistoryState(); + }, 'location.assign navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testLocationReplaceInPortal'); + assertInitialHistoryState(); + }, 'location.replace navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testSetLocationHrefInPortal'); + assertInitialHistoryState(); + }, 'Setting location.href navigates independently in a portal'); + + promise_test(async () => { + assertInitialHistoryState(); + await runTestInPortal(portalSrc, 'testSyntheticAnchorClickInPortal'); + assertInitialHistoryState(); + }, 'Synthetic anchor click navigates independently in a portal'); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/portals/history/resources/inner-iframe.html b/tests/wpt/web-platform-tests/portals/history/resources/inner-iframe.html new file mode 100644 index 00000000000..5c6daa22a55 --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/resources/inner-iframe.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<body> + <script> + window.onmessage = (e) => { + if (e.data == 'reportHistoryLength') { + e.source.postMessage(history.length, '*'); + } else if (e.data == 'navigate') { + location.href = '#test'; + e.source.postMessage('Done', '*'); + } + }; + </script> +</body> diff --git a/tests/wpt/web-platform-tests/portals/history/resources/portal-harness.js b/tests/wpt/web-platform-tests/portals/history/resources/portal-harness.js new file mode 100644 index 00000000000..9761ac9268b --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/resources/portal-harness.js @@ -0,0 +1,30 @@ +// We don't have the test harness in this context, so we roll our own +// which communicates with our host which is actually running the tests. + +window.onload = async () => { + let urlParams = new URLSearchParams(window.location.search); + let testName = urlParams.get('testName'); + let testFn = window[testName]; + if (!testFn) { + window.portalHost.postMessage('Missing test: ' + testName, '*'); + return; + } + + // The document load event is not finished at this point, so navigations + // would be done with replacement. This interferes with our tests. We wait + // for the next task before navigating to avoid this. + await new Promise((resolve) => { window.setTimeout(resolve); }); + + try { + await testFn(); + window.portalHost.postMessage('Passed', '*'); + } catch (e) { + window.portalHost.postMessage( + 'Failed: ' + e.name + ': ' + e.message, '*'); + } +}; + +function assert(condition, message) { + if (!condition) + throw new Error('Assertion failed: ' + message); +} diff --git a/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history-with-subframes.sub.html b/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history-with-subframes.sub.html new file mode 100644 index 00000000000..4b3e8cf2d92 --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history-with-subframes.sub.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<script src="portal-harness.js"></script> +<body> +<script> + function messageFrameAndAwaitResponse(frame, message) { + return new Promise((resolve) => { + window.onmessage = (e) => { + resolve(e.data); + }; + frame.contentWindow.postMessage(message, '*'); + }); + } + + function innerFrameUrl(crossSite) { + return (crossSite ? + 'https://{{hosts[alt][www]}}:{{ports[https][0]}}' : '') + + '/portals/history/resources/inner-iframe.html' + } + + async function runTestIFrameSrcInPortal(crossSite) { + assert(history.length == 1, 'Initial history length'); + + let iframe = document.createElement('iframe'); + iframe.src = innerFrameUrl(crossSite); + await new Promise((resolve) => { + iframe.onload = resolve; + document.body.appendChild(iframe); + }); + + let frameHistoryLength = + await messageFrameAndAwaitResponse(iframe, 'reportHistoryLength'); + assert(history.length == 1, 'History length unchanged when iframe added'); + assert(frameHistoryLength == 1, 'History length in iframe when added'); + + iframe.src = iframe.src + '#test'; + + frameHistoryLength = + await messageFrameAndAwaitResponse(iframe, 'reportHistoryLength'); + assert( + history.length == 2, 'History length changed when iframe src set'); + assert( + frameHistoryLength == 2, + 'History length in iframe changed when iframe src set'); + } + + function testIFrameSrcInPortal() { + return runTestIFrameSrcInPortal(false); + } + + function testCrossSiteIFrameSrcInPortal() { + return runTestIFrameSrcInPortal(true); + } + + async function runTestIFrameNavInPortal(crossSite) { + assert(history.length == 1, 'Initial history length'); + + let iframe = document.createElement('iframe'); + iframe.src = innerFrameUrl(crossSite); + await new Promise((resolve) => { + iframe.onload = resolve; + document.body.appendChild(iframe); + }); + + await messageFrameAndAwaitResponse(iframe, 'navigate'); + + let frameHistoryLength = + await messageFrameAndAwaitResponse(iframe, 'reportHistoryLength'); + assert( + history.length == 2, 'History length changed when iframe navigates'); + assert( + frameHistoryLength == 2, + 'History length in iframe changed when iframe navigates'); + } + + function testIFrameNavInPortal() { + return runTestIFrameNavInPortal(false); + } + + function testCrossSiteIFrameNavInPortal() { + return runTestIFrameNavInPortal(true); + } +</script> +</body> diff --git a/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history.html b/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history.html new file mode 100644 index 00000000000..591fd2193c1 --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/resources/portal-manipulate-history.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<script src="portal-harness.js"></script> +<body> +<script> + function testHistoryPushStateInPortal() { + assert(history.length == 1, 'Initial history length'); + assert(!history.state, 'Initial history state'); + + history.pushState('teststate', null, null); + + assert(history.length == 2, 'History length changed'); + assert(history.state == 'teststate', 'Update state'); + } + + function testHistoryReplaceStateInPortal() { + assert(history.length == 1, 'Initial history length'); + assert(!history.state, 'Initial history state'); + + history.replaceState('teststate', null, null); + + assert(history.length == 1, 'History length unchanged'); + assert(history.state == 'teststate', 'Update state'); + } + + function testLocationAssignInPortal() { + assert(history.length == 1, 'Initial history length'); + let initialLocation = location.href; + location.assign('#test'); + + assert(history.length == 2, 'History length changed'); + assert(location.href != initialLocation, 'Update location'); + } + + function testLocationReplaceInPortal() { + assert(history.length == 1, 'Initial history length'); + let initialLocation = location.href; + location.replace('#test'); + + assert(history.length == 1, 'History length unchanged'); + assert(location.href != initialLocation, 'Update location'); + } + + function testSetLocationHrefInPortal() { + assert(history.length == 1, 'Initial history length'); + let initialLocation = location.href; + location.href = '#test'; + + assert(history.length == 2, 'History length changed'); + assert(location.href != initialLocation, 'Update location'); + } + + function testSyntheticAnchorClickInPortal() { + assert(history.length == 1, 'Initial history length'); + let initialLocation = location.href; + + var anchor = document.createElement('a'); + anchor.href = '#test'; + document.body.appendChild(anchor); + + anchor.click(); + + assert(history.length == 2, 'History length changed'); + assert(location.href != initialLocation, 'Update location'); + } +</script> +</body> diff --git a/tests/wpt/web-platform-tests/portals/history/resources/run-test-in-portal.js b/tests/wpt/web-platform-tests/portals/history/resources/run-test-in-portal.js new file mode 100644 index 00000000000..c982a1fac8e --- /dev/null +++ b/tests/wpt/web-platform-tests/portals/history/resources/run-test-in-portal.js @@ -0,0 +1,16 @@ +// This is called from the portal host which is running with the test harness. +// This creates a portal and communicates with our ad hoc test harness in the +// portal context which performs the history manipulation in the portal. We +// confirm that the history manipulation works as expected in the portal. +async function runTestInPortal(portalSrc, testName) { + let portal = document.createElement('portal'); + portal.src = portalSrc + '?testName=' + testName; + let result = await new Promise((resolve) => { + portal.onmessage = (e) => { + resolve(e.data); + }; + document.body.appendChild(portal); + }); + + assert_equals(result, 'Passed'); +} diff --git a/tests/wpt/web-platform-tests/resource-timing/SyntheticResponse.py b/tests/wpt/web-platform-tests/resource-timing/SyntheticResponse.py index 26e0a8017d6..c5158002f18 100644 --- a/tests/wpt/web-platform-tests/resource-timing/SyntheticResponse.py +++ b/tests/wpt/web-platform-tests/resource-timing/SyntheticResponse.py @@ -1,6 +1,4 @@ import urllib -import sys, os -sys.path.append(os.path.join(os.path.dirname(__file__), "../common/")) import sleep def main(request, response): diff --git a/tests/wpt/web-platform-tests/common/sleep.py b/tests/wpt/web-platform-tests/resource-timing/sleep.py index 2e803b1b262..2e803b1b262 100644 --- a/tests/wpt/web-platform-tests/common/sleep.py +++ b/tests/wpt/web-platform-tests/resource-timing/sleep.py diff --git a/tests/wpt/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https.html b/tests/wpt/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https.html index 889c5ec7bbb..7c888450f0d 100644 --- a/tests/wpt/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https.html +++ b/tests/wpt/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https.html @@ -9,58 +9,120 @@ <body> <script> -var worker = 'resources/fetch-waits-for-activate-worker.js'; -var expected_url = normalizeURL(worker); -var scope = 'resources/fetch-waits-for-activate/'; - -promise_test(function(t) { - var registration; - var frameLoadPromise; - var frame; - return service_worker_unregister_and_register(t, worker, scope).then(function(reg) { - t.add_cleanup(function() { - return service_worker_unregister(t, scope); - }); - - registration = reg; - return wait_for_state(t, reg.installing, 'activating'); - }).then(function() { - assert_equals(registration.active.scriptURL, expected_url, - 'active worker should be present'); - assert_equals(registration.active.state, 'activating', - 'active worker should be in activating state'); - - // This should block until we message the worker to tell it to complete - // the activate event. - frameLoadPromise = with_iframe(scope).then(function(f) { - frame = f; - }); - - // Wait some time to allow frame loading to proceed. It should not, - // however, if the fetch event is blocked on the activate. I don't - // see any way to force this race without a timeout, unfortunately. - return new Promise(function(resolve) { - setTimeout(resolve, 1000); - }); - }).then(function() { - assert_equals(frame, undefined, 'frame should not be loaded'); - assert_equals(registration.active.scriptURL, expected_url, - 'active worker should be present'); - assert_equals(registration.active.state, 'activating', - 'active worker should be in activating state'); - - // This signals the activate event to complete. The frame should now - // load. - registration.active.postMessage('GO'); - return frameLoadPromise; - }).then(function() { - assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL, - expected_url, 'frame should now be loaded and controlled'); - assert_equals(registration.active.state, 'activated', - 'active worker should be in activated state'); - frame.remove(); +const worker_url = 'resources/fetch-waits-for-activate-worker.js'; +const normalized_worker_url = normalizeURL(worker_url); +const worker_scope = 'resources/fetch-waits-for-activate/'; + +// Resolves with the Service Worker's registration once it's reached the +// "activating" state. (The Service Worker should remain "activating" until +// explicitly told advance to the "activated" state). +async function registerAndWaitForActivating(t) { + const registration = await service_worker_unregister_and_register( + t, worker_url, worker_scope); + t.add_cleanup(() => service_worker_unregister(t, worker_scope)); + + await wait_for_state(t, registration.installing, 'activating'); + + return registration; +} + +// Attempts to ensure that the "Handle Fetch" algorithm has reached the step +// +// "If activeWorker’s state is "activating", wait for activeWorker’s state to +// become "activated"." +// +// by waiting for some time to pass. +// +// WARNING: whether the algorithm has reached that step isn't directly +// observable, so this is best effort and can race. Note that this can only +// result in false positives (where the algorithm hasn't reached that step yet +// and any functional events haven't actually been handled by the Service +// Worker). +async function ensureFunctionalEventsAreWaiting(registration) { + await (new Promise(resolve => { setTimeout(resolve, 1000); })); + + assert_equals(registration.active.scriptURL, normalized_worker_url, + 'active worker should be present'); + assert_equals(registration.active.state, 'activating', + 'active worker should be in activating state'); +} + +promise_test(async t => { + const registration = await registerAndWaitForActivating(t); + + let frame = null; + t.add_cleanup(() => { + if (frame) { + frame.remove(); + } + }); + + // This should block until we message the worker to tell it to complete + // the activate event. + const frameLoadPromise = with_iframe(worker_scope).then(function(f) { + frame = f; + }); + + await ensureFunctionalEventsAreWaiting(registration); + assert_equals(frame, null, 'frame should not be loaded'); + + registration.active.postMessage('ACTIVATE'); + + await frameLoadPromise; + assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL, + normalized_worker_url, + 'frame should now be loaded and controlled'); + assert_equals(registration.active.state, 'activated', + 'active worker should be in activated state'); +}, 'Navigation fetch events should wait for the activate event to complete.'); + +promise_test(async t => { + const frame = await with_iframe(worker_scope); + t.add_cleanup(() => { frame.remove(); }); + + const registration = await registerAndWaitForActivating(t); + + // Make the Service Worker control the frame so the frame can perform an + // intercepted fetch. + await (new Promise(resolve => { + navigator.serviceWorker.onmessage = e => { + assert_equals( + frame.contentWindow.navigator.serviceWorker.controller.scriptURL, + normalized_worker_url, 'frame should be controlled'); + resolve(); + }; + + registration.active.postMessage('CLAIM'); + })); + + const fetch_url = `${worker_scope}non/existent/path`; + const expected_fetch_result = 'Hello world'; + let fetch_promise_settled = false; + + // This should block until we message the worker to tell it to complete + // the activate event. + const fetchPromise = frame.contentWindow.fetch(fetch_url, { + method: 'POST', + body: expected_fetch_result, + }).then(response => { + fetch_promise_settled = true; + return response; }); -}, 'Fetch events should wait for the activate event to complete.'); + + await ensureFunctionalEventsAreWaiting(registration); + assert_false(fetch_promise_settled, + "fetch()-ing a Service Worker-controlled scope shouldn't have " + + "settled yet"); + + registration.active.postMessage('ACTIVATE'); + + const response = await fetchPromise; + assert_equals(await response.text(), expected_fetch_result, + "Service Worker should have responded to request to" + + fetch_url) + assert_equals(registration.active.state, 'activated', + 'active worker should be in activated state'); +}, 'Subresource fetch events should wait for the activate event to complete.'); </script> </body> diff --git a/tests/wpt/web-platform-tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js b/tests/wpt/web-platform-tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js index 66f3e593619..92a96ff88fb 100644 --- a/tests/wpt/web-platform-tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js +++ b/tests/wpt/web-platform-tests/service-workers/service-worker/resources/fetch-waits-for-activate-worker.js @@ -6,9 +6,23 @@ addEventListener('activate', function(evt) { })); }); -addEventListener('message', function(evt) { - if (typeof activatePromiseResolve === 'function') { - activatePromiseResolve(); +addEventListener('message', async function(evt) { + switch (evt.data) { + case 'CLAIM': + evt.waitUntil(new Promise(async resolve => { + await clients.claim(); + evt.source.postMessage('CLAIMED'); + resolve(); + })); + break; + case 'ACTIVATE': + if (typeof activatePromiseResolve !== 'function') { + throw new Error('Not activating!'); + } + activatePromiseResolve(); + break; + default: + throw new Error('Unknown message!'); } }); diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-click-method.html b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-click-method.html new file mode 100644 index 00000000000..92212cd85b8 --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-click-method.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: click on shadow host with delegatesFocus</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> + +<body> +<div id="host"> + <div id="slotted">slotted</div> +</div> +<div id="outside">outside</div> +</body> + +<script> +const host = document.getElementById("host"); +const slotted = document.getElementById("slotted"); + +const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true }); +const aboveSlot = document.createElement("div"); +aboveSlot.innerText = "aboveSlot"; +const slot = document.createElement("slot"); +shadowRoot.appendChild(aboveSlot); +shadowRoot.appendChild(slot); + +const elementsInFlatTreeOrder = [host, aboveSlot, slot, slotted, outside]; + +// Final structure: +// <div #host> (delegatesFocus=true) +// #shadowRoot +// <div #aboveSlot> +// <slot #slot> +// (slotted) <div #slotted> +// <div #outside> + +function setAllTabIndex(value) { + setTabIndex(elementsInFlatTreeOrder, value); +} + +function removeAllTabIndex() { + removeTabIndex(elementsInFlatTreeOrder); +} + +function resetTabIndexAndFocus() { + removeAllTabIndex(); + resetFocus(document); + resetFocus(shadowRoot); +} + +test(() => { + resetTabIndexAndFocus(); + setAllTabIndex(0); + host.click(); + assert_equals(shadowRoot.activeElement, null); + assert_equals(document.activeElement, document.body); +}, "call click() on host with delegatesFocus, all tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setAllTabIndex(0); + slotted.click(); + assert_equals(shadowRoot.activeElement, null); + assert_equals(document.activeElement, document.body); +}, "call click() on slotted element in delegatesFocus shadow tree, all tabindex=0"); +</script> diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html new file mode 100644 index 00000000000..4051db128a9 --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-varies.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: click on shadow host with delegatesFocus</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> + +<body> +<div id="host"> + <div id="slotted">slotted</div> +</div> +<div id="outside">outside</div> +</body> + +<script> +const host = document.getElementById("host"); +const slotted = document.getElementById("slotted"); + +const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true }); +const aboveSlot = document.createElement("div"); +aboveSlot.innerText = "aboveSlot"; +const slot = document.createElement("slot"); +// Add an unfocusable spacer, because test_driver.click will click on the +// center point of #host, and we don't want the click to land on #aboveSlot +// or #slot. +const spacer = document.createElement("div"); +spacer.style = "height: 1000px;"; +shadowRoot.appendChild(spacer); +shadowRoot.appendChild(aboveSlot); +shadowRoot.appendChild(slot); + +const elementsInFlatTreeOrder = [host, aboveSlot, spacer, slot, slotted, outside]; + +// Final structure: +// <div #host> (delegatesFocus=true) +// #shadowRoot +// <div #spacer> +// <div #aboveSlot> +// <slot #slot> +// (slotted) <div #slotted> +// <div #outside> + +function setAllTabIndex(value) { + setTabIndex(elementsInFlatTreeOrder, value); +} + +function removeAllTabIndex() { + removeTabIndex(elementsInFlatTreeOrder); +} + +function resetTabIndexAndFocus() { + removeAllTabIndex(); + resetFocus(document); + resetFocus(shadowRoot); +} + +promise_test(async () => { + resetTabIndexAndFocus(); + setTabIndex([aboveSlot], 2); + setTabIndex([slot, slotted], 1); + await test_driver.click(host); + assert_equals(shadowRoot.activeElement, aboveSlot); + assert_equals(document.activeElement, host); +}, "click on host with delegatesFocus, #aboveSlot tabindex = 2, #slot and #slotted tabindex = 1"); + +</script> diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html new file mode 100644 index 00000000000..5f7914f2a4e --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/click-focus-delegatesFocus-tabindex-zero.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: click on shadow host with delegatesFocus</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> + +<body> +<div id="host"> + <div id="slotted">slotted</div> +</div> +<div id="outside">outside</div> +</body> + +<script> +const host = document.getElementById("host"); +const slotted = document.getElementById("slotted"); + +const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true }); +const aboveSlot = document.createElement("div"); +aboveSlot.innerText = "aboveSlot"; +const slot = document.createElement("slot"); +// Add an unfocusable spacer, because test_driver.click will click on the +// center point of #host, and we don't want the click to land on #aboveSlot +// or #slot. +const spacer = document.createElement("div"); +spacer.style = "height: 1000px;"; +shadowRoot.appendChild(spacer); +shadowRoot.appendChild(aboveSlot); +shadowRoot.appendChild(slot); + +const elementsInFlatTreeOrder = [host, aboveSlot, spacer, slot, slotted, outside]; + +// Final structure: +// <div #host> (delegatesFocus=true) +// #shadowRoot +// <div #spacer> +// <div #aboveSlot> +// <slot #slot> +// (slotted) <div #slotted> +// <div #outside> + +function setAllTabIndex(value) { + setTabIndex(elementsInFlatTreeOrder, value); +} + +function removeAllTabIndex() { + removeTabIndex(elementsInFlatTreeOrder); +} + +function resetTabIndexAndFocus() { + removeAllTabIndex(); + resetFocus(document); + resetFocus(shadowRoot); +} + +promise_test(async () => { + resetTabIndexAndFocus(); + setAllTabIndex(0); + removeTabIndex([spacer]); + await test_driver.click(host); + assert_equals(shadowRoot.activeElement, aboveSlot); + assert_equals(document.activeElement, host); +}, "click on host with delegatesFocus, all tabindex=0 except spacer"); + +</script> diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/focus-method-delegatesFocus.html b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-method-delegatesFocus.html new file mode 100644 index 00000000000..462542e3f7b --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-method-delegatesFocus.html @@ -0,0 +1,232 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focus() on shadow host with delegatesFocus</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> + +<body> +<div id="host"> + <div id="slottedToSecondSlot" slot="secondSlot">slottedToSecondSlot</div> + <div id="slottedToFirstSlot" slot="firstSlot">slottedToFirstSlot</div> +</div> +<div id="outside">outside</div> +</body> + +<script> +const host = document.getElementById("host"); +const slottedToSecondSlot = document.getElementById("slottedToSecondSlot"); +const slottedToFirstSlot = document.getElementById("slottedToFirstSlot"); +const outside = document.getElementById("outside"); + +const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true }); +const aboveSlots = document.createElement("div"); +aboveSlots.innerText = "aboveSlots"; +const firstSlot = document.createElement("slot"); +firstSlot.name = "firstSlot"; +const secondSlot = document.createElement("slot"); +secondSlot.name = "secondSlot"; +const belowSlots = document.createElement("div"); +belowSlots.innerText = "belowSlots"; +shadowRoot.appendChild(aboveSlots); +shadowRoot.appendChild(firstSlot); +shadowRoot.appendChild(secondSlot); +shadowRoot.appendChild(belowSlots); + +const elementsInFlatTreeOrder = [host, aboveSlots, firstSlot, + slottedToFirstSlot, secondSlot, slottedToSecondSlot, belowSlots, outside]; + +// Final structure: +// <div #host> (delegatesFocus=true) +// #shadowRoot +// <div #aboveSlots> +// <slot #firstSlot> +// (slotted) <div #slottedToFirstSlot> +// <slot #secondSlot> +// (slotted) <div #slottedToSecondSlot> +// <div #belowSlots> +// <div #outside> + + +function setAllTabIndex(value) { + setTabIndex(elementsInFlatTreeOrder, value); +} + +function removeAllTabIndex() { + removeTabIndex(elementsInFlatTreeOrder); +} + +function resetTabIndexAndFocus() { + removeAllTabIndex(); + resetFocus(document); + resetFocus(shadowRoot); +} + +test(() => { + resetTabIndexAndFocus(); + setAllTabIndex(0); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> tabindex=0 + // <slot #firstSlot> tabindex=0 + // (slotted) <div #slottedToFirstSlot> tabindex=0 + // <slot #secondSlot> tabindex=0 + // (slotted) <div #slottedToSecondSlot> tabindex=0 + // <div #belowSlots> tabindex=0 + // <div #outside> tabindex=0 + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus, all tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setAllTabIndex(0); + setTabIndex([host], -1); + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & tabindex =-1, all other tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setTabIndex([aboveSlots, slottedToFirstSlot, slottedToSecondSlot, belowSlots], 0); + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & no tabindex, all other tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setAllTabIndex(-1); + setTabIndex([host], 0); + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & tabindex = 0, all other tabindex=-1"); + +test(() => { + resetTabIndexAndFocus(); + removeAllTabIndex(); + // No focusable element under #host in the flat tree. + host.focus(); + assert_equals(shadowRoot.activeElement, null); + assert_equals(document.activeElement, document.body); +}, "focus() on host with delegatesFocus, all without tabindex"); + +test(() => { + resetTabIndexAndFocus(); + // First focusable = #aboveSlots + setAllTabIndex(-1); + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus, all tabindex=-1"); + +test(() => { + resetTabIndexAndFocus(); + removeAllTabIndex(); + setTabIndex([host, belowSlots], 0); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> + // <slot #firstSlot> + // (slotted) <div #slottedToFirstSlot> + // <slot #secondSlot> + // (slotted) <div #slottedToSecondSlot> + // <div #belowSlots> tabindex=0 + // <div #outside> + // First focusable = #belowSlots + host.focus(); + assert_equals(shadowRoot.activeElement, belowSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & tabindex=0, #belowSlots with tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + removeAllTabIndex(); + setTabIndex([host, outside], 0); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> + // <slot #firstSlot> + // (slotted) <div #slottedToFirstSlot> + // <slot #secondSlot> + // (slotted) <div #slottedToSecondSlot> + // <div #belowSlots> + // <div #outside> tabindex=0 + // No focusable element under #host in the flat tree. + host.focus(); + assert_equals(shadowRoot.activeElement, null); + assert_equals(document.activeElement, document.body); +}, "focus() on host with delegatesFocus & tabindex=0, #outside with tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setTabIndex([host, aboveSlots, belowSlots], 0); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> tabindex=0 + // <slot #firstSlot> + // (slotted) <div #slottedToFirstSlot> + // <slot #secondSlot> + // (slotted) <div #slottedToSecondSlot> + // <div #belowSlots> tabindex=0 + // <div #outside> + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & tabindex=0, #aboveSlots and #belowSlots with tabindex=0"); + +test(() => { + resetTabIndexAndFocus(); + setTabIndex([host, aboveSlots], 0); + setTabIndex([belowSlots], 1); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> tabindex=0 + // <slot #firstSlot> + // (slotted) <div #slottedToFirstSlot> + // <slot #secondSlot> + // (slotted) <div #slottedToSecondSlot> + // <div #belowSlots> tabindex=1 + // <div #outside> + // First focusable = #aboveSlots + host.focus(); + assert_equals(shadowRoot.activeElement, aboveSlots); + assert_equals(document.activeElement, host); +}, "focus() on host with delegatesFocus & tabindex=0, #aboveSlots with tabindex=0 and #belowSlots with tabindex=1"); + +test(() => { + resetTabIndexAndFocus(); + setTabIndex([host, slottedToFirstSlot, slottedToSecondSlot, belowSlots], 0); + // Structure: + // <div #host> (delegatesFocus=true) tabindex=0 + // #shadowRoot + // <div #aboveSlots> + // <slot #firstSlot> + // (slotted) <div #slottedToFirstSlot> tabindex=0 + // <slot #secondSlot> + // (slotted) <div #slottedToSecondSlot> tabindex=0 + // <div #belowSlots> tabindex=0 + // <div #outside> + // First focusable = #slottedToFirstSlot + host.focus(); + assert_equals(shadowRoot.activeElement, null); + assert_equals(document.activeElement, slottedToFirstSlot); +}, "focus() on host with delegatesFocus & tabindex=0, #slottedToFirstSlot, #slottedToSecondSlot, #belowSlots with tabindex=0"); + +</script> + diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html new file mode 100644 index 00000000000..356b0bb329e --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-negative-delegatesFocus.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focus - the sequential focus navigation order with shadow dom that delegates focus and all tabindex=-1 in shadow tree</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> +<body> +<script> +// Structure: +// <div #aboveHost tabindex=0> +// <div #host tabindex=0> +// #shadowRoot (delegatesFocus) +// <div #aboveSlot tabindex=-1> +// <slot #slotAbove tabindex=-1> +// (slotted) <div #slottedAbove tabindex=-1> +// <slot #slotBelow tabindex=-1> +// (slotted) <div #slottedBelow tabindex=-1> +// <div #belowSlot tabindex=-1> +// <div #belowHost tabindex=0> + +promise_test(() => { + let elementsInFlatTreeOrder; + let [aboveHost, host, aboveSlot, slotAbove, slottedAbove, slotBelow, slottedBelow, belowSlot, belowHost] = elementsInFlatTreeOrder = prepareDOM(document.body, true); + setTabIndex(elementsInFlatTreeOrder, -1); + setTabIndex([aboveHost, host, belowHost], 0); + resetFocus(); + // Focus should only land on #aboveHost and #belowHost (all others are non-sequentially focusable). + return assertFocusOrder([aboveHost, belowHost]); +}, "Order when all tabindex=-1 is and delegatesFocus = true"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html new file mode 100644 index 00000000000..67899cff4a9 --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-varying-delegatesFocus.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focus - the sequential focus navigation order with shadow dom that delegates focus and tabindex in shadow tree varies</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> +<body> +<script> +// Structure: +// <div #aboveHost tabindex=0> +// <div #host tabindex=0> +// #shadowRoot (delegatesFocus) +// <div #aboveSlot tabindex=0> +// <slot #slotAbove tabindex=1> +// (slotted) <div #slottedAbove tabindex=3> +// <slot #slotBelow tabindex=2> +// (slotted) <div #slottedBelow tabindex=1> +// <div #belowSlot tabindex=-1> +// <div #belowHost tabindex=0> + +promise_test(() => { + let elementsInFlatTreeOrder; + let [aboveHost, host, aboveSlot, slotAbove, slottedAbove, slotBelow, slottedBelow, belowSlot, belowHost] = elementsInFlatTreeOrder = prepareDOM(document.body, true); + setTabIndex(elementsInFlatTreeOrder, -1); + setTabIndex([aboveHost, host, aboveSlot, belowHost], 0); + setTabIndex([slotAbove, slottedBelow], 1); + setTabIndex([slotBelow], 2); + setTabIndex([slottedAbove], 3); + resetFocus(); + return assertFocusOrder([aboveHost, slottedAbove, slottedBelow, aboveSlot, belowHost]); +}, "Order when tabindex varies and delegatesFocus = true"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html new file mode 100644 index 00000000000..5e6ab3a90f8 --- /dev/null +++ b/tests/wpt/web-platform-tests/shadow-dom/focus/focus-tabindex-order-shadow-zero-delegatesFocus.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>HTML Test: focus - the sequential focus navigation order with shadow dom that delegates focus and all tabindex=0</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/shadow-utils.js"></script> +<body> +<script> +// Structure: +// <div #aboveHost tabindex=0> +// <div #host tabindex=0> +// #shadowRoot (delegatesFocus) +// <div #aboveSlot tabindex=0> +// <slot #slotAbove tabindex=0> +// (slotted) <div #slottedAbove tabindex=0> +// <slot #slotBelow tabindex=0> +// (slotted) <div #slottedBelow tabindex=0> +// <div #belowSlot tabindex=0> +// <div #belowHost tabindex=0> + +promise_test(() => { + let elementsInFlatTreeOrder; + let [aboveHost, host, aboveSlot, slotAbove, slottedAbove, slotBelow, slottedBelow, belowSlot, belowHost] = elementsInFlatTreeOrder = prepareDOM(document.body, true); + setTabIndex(elementsInFlatTreeOrder, 0); + resetFocus(); + // Focus should move in flat tree order since every one of them has tabindex ==0, + // but doesn't include slots and #host. + return assertFocusOrder([aboveHost, aboveSlot, slottedAbove, slottedBelow, belowSlot, belowHost]); +}, "Order when all tabindex=0 is and delegatesFocus = true"); +</script> +</body> diff --git a/tests/wpt/web-platform-tests/storage-access-api/idl.window.js b/tests/wpt/web-platform-tests/storage-access-api/idlharness.window.js index a0b4c37d916..a0b4c37d916 100644 --- a/tests/wpt/web-platform-tests/storage-access-api/idl.window.js +++ b/tests/wpt/web-platform-tests/storage-access-api/idlharness.window.js diff --git a/tests/wpt/web-platform-tests/svg/animations/syncbase-remove-add-while-running.html b/tests/wpt/web-platform-tests/svg/animations/syncbase-remove-add-while-running.html index 5b3ae94488f..61b9604a7b6 100644 --- a/tests/wpt/web-platform-tests/svg/animations/syncbase-remove-add-while-running.html +++ b/tests/wpt/web-platform-tests/svg/animations/syncbase-remove-add-while-running.html @@ -1,4 +1,5 @@ <!DOCTYPE html> +<meta charset="utf-8"> <title>Remove/Add syncbase while animation is running</title> <link rel="help" href="https://www.w3.org/TR/SMIL3/smil-timing.html#q26"> <link rel="author" title="Edvard Thörnros" href="mailto:edvardt@opera.com"> diff --git a/tests/wpt/web-platform-tests/svg/text/reftests/dominant-baseline-hanging-small-font-size.svg b/tests/wpt/web-platform-tests/svg/text/reftests/dominant-baseline-hanging-small-font-size.svg new file mode 100644 index 00000000000..aa27ec9c094 --- /dev/null +++ b/tests/wpt/web-platform-tests/svg/text/reftests/dominant-baseline-hanging-small-font-size.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml"> + <metadata> + <title>'dominant-baseline: hanging' on <text> with small font-size</title> + <h:link rel="help" href="https://svgwg.org/svg2-draft/text.html#TextAnchoringProperties"/> + <h:link rel="match" href="../../embedded/reference/green-rect-100x100.svg"/> + <h:link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/> + </metadata> + <rect width="100" height="100" fill="red"/> + <svg viewBox="0 0 0.4 0.4" width="100" height="100"> + <text dominant-baseline="hanging" fill="green" + font-size="0.5" font-family="Ahem">X</text> + </svg> +</svg> diff --git a/tests/wpt/web-platform-tests/tools/ci/azure/install_safari.yml b/tests/wpt/web-platform-tests/tools/ci/azure/install_safari.yml index bfb6afc332b..2c4a25c83a4 100644 --- a/tests/wpt/web-platform-tests/tools/ci/azure/install_safari.yml +++ b/tests/wpt/web-platform-tests/tools/ci/azure/install_safari.yml @@ -5,12 +5,8 @@ parameters: steps: - ${{ if eq(parameters.channel, 'preview') }}: - script: | - # This is equivalent to `Homebrew/homebrew-cask-versions/safari-technology-preview`, - # but the raw URL is used to bypass caching. - # Safari Technology Preview version 83 includes a regression that - # interferes with results collection. The version of the installation - # script referenced here installs STP at version 82. - HOMEBREW_NO_AUTO_UPDATE=1 brew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask-versions/dbde508bb83254c53be4eb6387dbd9fbf9797a35/Casks/safari-technology-preview.rb + # Pinned to Safari Technology Preview version 94. + HOMEBREW_NO_AUTO_UPDATE=1 brew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask-versions/02e2aff2d578cc7d8545cf035bffa45293bb1de1/Casks/safari-technology-preview.rb sudo "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --enable defaults write com.apple.SafariTechnologyPreview WebKitJavaScriptCanOpenWindowsAutomatically 1 defaults write com.apple.SafariTechnologyPreview ExperimentalServerTimingEnabled 1 diff --git a/tests/wpt/web-platform-tests/tools/ci/run_tc.py b/tests/wpt/web-platform-tests/tools/ci/run_tc.py index 956d1c353e5..60f17580871 100755 --- a/tests/wpt/web-platform-tests/tools/ci/run_tc.py +++ b/tests/wpt/web-platform-tests/tools/ci/run_tc.py @@ -42,6 +42,8 @@ import re import subprocess import sys import tempfile +from socket import error as SocketError # NOQA: N812 +import errno try: from urllib2 import urlopen except ImportError: @@ -161,15 +163,41 @@ def install_webkitgtk_from_apt_repository(channel): run(["sudo", "apt-get", "-qqy", "-t", "bionic-wpt-webkit-updates", "install", "webkit2gtk-driver"]) +# Download an URL in chunks and saves it to a file descriptor (truncating it) +# It doesn't close the descriptor, but flushes it on success. +# It retries the download in case of ECONNRESET up to max_retries. +def download_url_to_descriptor(fd, url, max_retries=3): + download_succeed = False + if max_retries < 0: + max_retries = 0 + for current_retry in range(max_retries+1): + try: + resp = urlopen(url) + # We may come here in a retry, ensure to truncate fd before start writing. + fd.seek(0) + fd.truncate(0) + while True: + chunk = resp.read(16*1024) + if not chunk: + break # Download finished + fd.write(chunk) + fd.flush() + download_succeed = True + break # Sucess + except SocketError as e: + if e.errno != errno.ECONNRESET: + raise # Unknown error + if current_retry < max_retries: + print("ERROR: Connection reset by peer. Retrying ...") + continue # Retry + return download_succeed + + def install_webkitgtk_from_tarball_bundle(channel): with tempfile.NamedTemporaryFile(suffix=".tar.xz") as temp_tarball: - resp = urlopen("https://webkitgtk.org/built-products/nightly/webkitgtk-nightly-build-last.tar.xz") - while True: - chunk = resp.read(16*1024) - if not chunk: - break - temp_tarball.write(chunk) - temp_tarball.flush() + download_url = "https://webkitgtk.org/built-products/nightly/webkitgtk-nightly-build-last.tar.xz" + if not download_url_to_descriptor(temp_tarball, download_url): + raise RuntimeError("Can't download %s. Aborting" % download_url) run(["sudo", "tar", "xfa", temp_tarball.name, "-C", "/"]) # Install dependencies run(["sudo", "apt-get", "-qqy", "update"]) diff --git a/tests/wpt/web-platform-tests/tools/wpt/commands.json b/tests/wpt/web-platform-tests/tools/wpt/commands.json index 178eda9c265..60fe1621af0 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/commands.json +++ b/tests/wpt/web-platform-tests/tools/wpt/commands.json @@ -63,6 +63,13 @@ "help": "Print branch point from master", "virtualenv": false }, + "rev-list": { + "path": "revlist.py", + "script": "run_rev_list", + "parser": "get_parser", + "help": "List tagged revisions at regular intervals", + "virtualenv": false + }, "install-android-emulator": { "path": "android.py", "script": "run_install", diff --git a/tests/wpt/web-platform-tests/tools/wpt/revlist.py b/tests/wpt/web-platform-tests/tools/wpt/revlist.py new file mode 100644 index 00000000000..f750311914a --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/wpt/revlist.py @@ -0,0 +1,118 @@ +import argparse +import logging +import os +import time +from tools.wpt.testfiles import get_git_cmd + +here = os.path.dirname(__file__) +wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir)) + +logger = logging.getLogger() + +MYPY = False +if MYPY: + # MYPY is set to True when run under Mypy. + from typing import Any + from typing import Dict + from typing import List + from typing import Text + + +def calculate_cutoff_date(until, epoch, offset): + return ((((until - offset) // epoch)) * epoch) + offset + + +def parse_epoch(string): + # type: (str) -> int + UNIT_DICT = {"h": 3600, "d": 86400, "w": 604800} + base = string[:-1] + unit = string[-1:] + if base.isdigit() and unit in UNIT_DICT: + return int(base) * UNIT_DICT[unit] + raise argparse.ArgumentTypeError('must be digits followed by h/d/w') + + +def get_tagged_revisions(pattern): + # type: (bytes) -> List[..., Dict] + ''' + Returns the tagged revisions indexed by the committer date. + ''' + git = get_git_cmd(wpt_root) + args = [ + pattern, + '--sort=-committerdate', + '--format=%(refname:lstrip=2) %(objectname) %(committerdate:raw)', + '--count=100000' + ] + for line in git("for-each-ref", *args).splitlines(): + tag, commit, date, _ = line.split(" ") + date = int(date) + yield tag, commit, date + + +def list_tagged_revisons(epoch, max_count): + # type: (**Any) -> List[Text] + logger.debug("list_tagged_revisons(%s, %s)" % (epoch, max_count)) + # Set an offset to start to count the the weekly epoch from + # Monday 00:00:00. This is particularly important for the weekly epoch + # because fix the start of the epoch to Monday. This offset is calculated + # from Thursday, 1 January 1970 0:00:00 to Monday, 5 January 1970 0:00:00 + epoch_offset = 345600 + # "epoch_threshold" set a safety margin after this time it is fine to + # consider that any tags are created and pushed. + epoch_threshold = 600 + epoch_until = int(time.time()) - epoch_threshold + count = 0 + + # Iterates the tagged revisions in descending order finding the more + # recent commit still older than a "cutoff_date" value. + # When a commit is found "cutoff_date" is set to a new value multiplier of + # "epoch" but still below of the date of the current commit found. + # This needed to deal with intervals where no candidates were found + # for the current "epoch" and the next candidate found is yet below + # the lower values of the interval (it is the case of J and I for the + # interval between Wed and Tue, in the example). The algorithm fix + # the next "cutoff_date" value based on the date value of the current one + # skipping the intermediate values. + # The loop ends once we reached the required number of revisions to return + # or the are no more tagged revisions or the cutoff_date reach zero. + # + # Fri Sat Sun Mon Tue Wed Thu Fri Sat + # | | | | | | | | | + # -A---B-C---DEF---G---H--IJ----------K-----L-M----N--O-- + # ^ + # now + # Expected result: N,M,K,J,H,G,F,C,A + + cutoff_date = calculate_cutoff_date(epoch_until, epoch, epoch_offset) + for _, commit, date in get_tagged_revisions("refs/tags/merge_pr_*"): + if count >= max_count: + return + if date < cutoff_date: + print(commit) + count += 1 + cutoff_date = calculate_cutoff_date(date, epoch, epoch_offset) + + +def get_parser(): + # type: () -> argparse.ArgumentParser + parser = argparse.ArgumentParser() + parser.add_argument("--epoch", + default="1d", + type=parse_epoch, + help="regular interval of time selected to get the " + "tagged revisions. Valid values are digits " + "followed by h/d/w (e.x. 9h, 9d, 9w ...) where " + "the mimimun selectable interval is one hour " + "(1h)") + parser.add_argument("--max-count", + default=1, + type=int, + help="maximum number of revisions to be returned by " + "the command") + return parser + + +def run_rev_list(**kwargs): + # type: (**Any) -> None + list_tagged_revisons(kwargs["epoch"], kwargs["max_count"]) diff --git a/tests/wpt/web-platform-tests/tools/wpt/tests/test_revlist.py b/tests/wpt/web-platform-tests/tools/wpt/tests/test_revlist.py new file mode 100644 index 00000000000..7b13106d0f5 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/wpt/tests/test_revlist.py @@ -0,0 +1,15 @@ +from tools.wpt import revlist + + +def test_calculate_cutoff_date(): + assert revlist.calculate_cutoff_date(3601, 3600, 0) == 3600 + assert revlist.calculate_cutoff_date(3600, 3600, 0) == 3600 + assert revlist.calculate_cutoff_date(3599, 3600, 0) == 0 + assert revlist.calculate_cutoff_date(3600, 3600, 1) == 1 + assert revlist.calculate_cutoff_date(3600, 3600, -1) == 3599 + + +def test_parse_epoch(): + assert revlist.parse_epoch(b"10h") == 36000 + assert revlist.parse_epoch(b"10d") == 864000 + assert revlist.parse_epoch(b"10w") == 6048000 diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/android_webview.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/android_webview.py index dd45c0494b6..dc687b48ed7 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/android_webview.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/android_webview.py @@ -54,7 +54,7 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data, capabilities["goog:chromeOptions"]["androidPackage"] = \ "org.chromium.webview_shell" capabilities["goog:chromeOptions"]["androidActivity"] = ".WebPlatformTestsActivity" - if 'device_serial' in kwargs: + if kwargs.get('device_serial'): capabilities["goog:chromeOptions"]["androidDeviceSerial"] = kwargs['device_serial'] # Workaround: driver.quit() cannot quit SystemWebViewShell. diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py index 781d7e31c43..6cf784fd010 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/browsers/firefox.py @@ -198,7 +198,7 @@ def run_info_browser_version(binary): def update_properties(): - return (["os", "debug", "webrender", "fisson", "e10s", "sw-e10s", "processor"], + return (["os", "debug", "webrender", "fission", "e10s", "sw-e10s", "processor"], {"os": ["version"], "processor": ["bits"]}) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/formatters/wptreport.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/formatters/wptreport.py index d73911f6a94..6d4401ae5aa 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/formatters/wptreport.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/formatters/wptreport.py @@ -62,15 +62,15 @@ class WptreportFormatter(BaseFormatter): if 'run_info' in data: self.results['run_info'] = data['run_info'] self.results['time_start'] = data['time'] + self.results["results"] = [] def suite_end(self, data): self.results['time_end'] = data['time'] - self.results["results"] = [] for test_name in self.raw_results: result = {"test": test_name} result.update(self.raw_results[test_name]) self.results["results"].append(result) - return json.dumps(self.results) + return json.dumps(self.results) + "\n" def find_or_create_test(self, data): test_name = data["test"] @@ -126,6 +126,11 @@ class WptreportFormatter(BaseFormatter): for item in data["extra"]["reftest_screenshots"] if type(item) == dict } + test_name = data["test"] + result = {"test": data["test"]} + result.update(self.raw_results[test_name]) + self.results["results"].append(result) + self.raw_results.pop(test_name) def assertion_count(self, data): test = self.find_or_create_test(data) diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/metadata.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/metadata.py index 15bbf94c33c..c328dcefa72 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/metadata.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/metadata.py @@ -353,18 +353,41 @@ class ExpectedUpdater(object): self.tests_visited = {} def update_from_log(self, log_file): + # We support three possible formats: + # * wptreport format; one json object in the file, possibly pretty-printed + # * wptreport format; one run per line + # * raw log format + + # Try reading a single json object in wptreport format self.run_info = None + success = self.get_wptreport_data(log_file.read()) + + if success: + return + + # Try line-separated json objects in wptreport format + log_file.seek(0) + for line in log_file: + success = self.get_wptreport_data(line) + if not success: + break + else: + return + + # Assume the file is a raw log + log_file.seek(0) + self.update_from_raw_log(log_file) + + def get_wptreport_data(self, input_str): try: - data = json.load(log_file) + data = json.loads(input_str) except Exception: pass else: if "action" not in data and "results" in data: self.update_from_wptreport_log(data) - return - - log_file.seek(0) - self.update_from_raw_log(log_file) + return True + return False def update_from_raw_log(self, log_file): action_map = self.action_map @@ -642,6 +665,11 @@ class TestFileData(object): expected_subtest = test.get_subtest(item) if not self.is_disabled(expected_subtest): rv.append(expected_subtest) + for name in seen_subtests: + subtest = test.get_subtest(name) + # If any of the items have children (ie subsubtests) we want to prune thes + if subtest.children: + rv.extend(subtest.children) return rv diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/tests/test_update.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/tests/test_update.py index d453ae5b464..5d900a3d6c9 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/tests/test_update.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/tests/test_update.py @@ -717,6 +717,39 @@ def test_full_update(): @pytest.mark.xfail(sys.version[0] == "3", reason="metadata doesn't support py3") +def test_full_orphan(): + tests = [("path/to/test.htm", [test_id], "testharness", + """[test.htm] + [test1] + expected: FAIL + [subsub test] + expected: TIMEOUT + [test2] + expected: ERROR +""")] + + log_0 = suite_log([("test_start", {"test": test_id}), + ("test_status", {"test": test_id, + "subtest": "test1", + "status": "FAIL", + "expected": "FAIL"}), + ("test_end", {"test": test_id, + "status": "OK"})]) + + + updated = update(tests, log_0, full_update=True) + + new_manifest = updated[0][1] + + assert not new_manifest.is_empty + assert len(new_manifest.get_test(test_id).children[0].children) == 0 + assert new_manifest.get_test(test_id).children[0].get( + "expected", default_run_info) == "FAIL" + assert len(new_manifest.get_test(test_id).children) == 1 + + +@pytest.mark.xfail(sys.version[0] == "3", + reason="metadata doesn't support py3") def test_update_reorder_expected_full_conditions(): tests = [("path/to/test.htm", [test_id], "testharness", """[test.htm] diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py index 43225a1e728..aacd7857072 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py @@ -359,6 +359,7 @@ class ManifestItem(object): def _remove_child(self, child): self.children.remove(child) child.parent = None + child.node.remove() def iterchildren(self, name=None): for item in self.children: diff --git a/tests/wpt/web-platform-tests/trusted-types/Element-setAttribute.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Element-setAttribute.tentative.html index a284b2f8355..cd6617915bd 100644 --- a/tests/wpt/web-platform-tests/trusted-types/Element-setAttribute.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/Element-setAttribute.tentative.html @@ -6,29 +6,6 @@ </head> <body> <script> - // TrustedURL Assignments - let testCases = [ - [ 'a', 'href' ], - [ 'area', 'href' ], - [ 'base', 'href' ], - [ 'frame', 'src' ], - [ 'iframe', 'src' ], - [ 'img', 'src' ], - [ 'input', 'src' ], - [ 'link', 'href' ], - [ 'video', 'src' ], - [ 'object', 'data' ], - [ 'object', 'codeBase' ], - [ 'source', 'src' ], - [ 'track', 'src' ] - ]; - - testCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_url_explicit_set(window, c, t, c[0], c[1], RESULTS.URL); - }, c[0] + "." + c[1] + " assigned via policy (successful URL transformation)"); - }); - // TrustedScriptURL Assignments let scriptTestCases = [ [ 'embed', 'src' ], @@ -54,8 +31,8 @@ // Other attributes can be assigned with TrustedTypes or strings or null values test(t => { - assert_element_accepts_trusted_url_explicit_set(window, 'arel', t, 'a', 'rel', RESULTS.URL); - }, "a.rel assigned via policy (successful URL transformation)"); + assert_element_accepts_trusted_script_url_explicit_set(window, 'scriptsrc1', t, 'script', 'src', RESULTS.SCRIPTURL); + }, "script.src assigned via policy (successful script transformation)"); test(t => { assert_element_accepts_non_trusted_type_explicit_set('a', 'rel', 'A string', 'A string'); diff --git a/tests/wpt/web-platform-tests/trusted-types/Element-setAttributeNS.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Element-setAttributeNS.tentative.html index 374e6a9cfa3..67e8236febd 100644 --- a/tests/wpt/web-platform-tests/trusted-types/Element-setAttributeNS.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/Element-setAttributeNS.tentative.html @@ -18,10 +18,8 @@ assert_element_accepts_trusted_script_url_set_ns(window, '2', t, 'a', 'b', RESULTS.SCRIPTURL); }, "Element.setAttributeNS assigned via policy (successful ScriptURL transformation)"); - test(t => { - assert_element_accepts_trusted_url_set_ns(window, '3', t, 'a', 'b', RESULTS.URL); - }, "Element.setAttributeNS assigned via policy (successful URL transformation)"); - +// TODO: Is there any non-URL, namespaced accessor left? +/* test(t => { let p = createURL_policy(window, '5'); let url = p.createURL(INPUTS.URL); @@ -31,5 +29,6 @@ let attr_node = elem.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href"); assert_equals(attr_node.value + "", RESULTS.URL); }, "Element.setAttributeNS accepts a URL on <svg:image xlink:href/>"); +*/ </script> diff --git a/tests/wpt/web-platform-tests/trusted-types/HTMLElement-generic.tentative.html b/tests/wpt/web-platform-tests/trusted-types/HTMLElement-generic.tentative.html index d1fafa70cd2..3ec6cfa60da 100644 --- a/tests/wpt/web-platform-tests/trusted-types/HTMLElement-generic.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/HTMLElement-generic.tentative.html @@ -7,28 +7,6 @@ <body> <script> var testnb = 0; - // TrustedURL Assignments - const URLTestCases = [ - [ 'a', 'href' ], - [ 'area', 'href' ], - [ 'base', 'href' ], - [ 'frame', 'src' ], - [ 'iframe', 'src' ], - [ 'img', 'src' ], - [ 'input', 'src' ], - [ 'link', 'href' ], - [ 'video', 'src' ], - [ 'object', 'data' ], - [ 'object', 'codeBase' ], - [ 'source', 'src' ], - [ 'track', 'src' ] - ]; - - URLTestCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_url(window, ++testnb, t, c[0], c[1], RESULTS.URL); - }, c[0] + "." + c[1] + " assigned via policy (successful URL transformation)"); - }); // TrustedScriptURL Assignments const scriptURLTestCases = [ diff --git a/tests/wpt/web-platform-tests/trusted-types/Location-assign.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Location-assign.tentative.html deleted file mode 100644 index 62f98e96d7f..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/Location-assign.tentative.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="support/helper.sub.js"></script> -<body> -<script> - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.assign(url); - assert_equals("" + url, location.href, "location href"); - }, "location.assign via policy (successful URL transformation)."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/Location-href.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Location-href.tentative.html deleted file mode 100644 index bacadf6a91b..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/Location-href.tentative.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="support/helper.sub.js"></script> -<body> -<script> - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.href = url; - assert_equals("" + url, location.href, "location href"); - }, "location.href assigned via policy (successful URL transformation)."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/Location-replace.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Location-replace.tentative.html deleted file mode 100644 index 4fb53d02609..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/Location-replace.tentative.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="support/helper.sub.js"></script> -<body> -<script> - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.replace(url); - assert_equals("" + url, location.href, "location href"); - }, "location.replace via policy (successful URL transformation)."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicy-createXXX.tentative.html b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicy-createXXX.tentative.html index 73ed8c72b23..34fbf5587da 100644 --- a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicy-createXXX.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicy-createXXX.tentative.html @@ -12,10 +12,8 @@ createScript: s => s }); assert_throws(new TypeError(), _ => { p1.createScriptURL("foo"); }); - assert_throws(new TypeError(), _ => { p1.createURL("foo"); }); const p2 = trustedTypes.createPolicy("policyURLAndScriptURL", { - createURL: s => s, createScriptURL: s => s }); assert_throws(new TypeError(), _ => { p2.createHTML("foo"); }); @@ -26,23 +24,18 @@ const noopPolicy = { createHTML: (s) => s, createScriptURL: (s) => s, - createURL: (s) => s, createScript: (s) => s, }; policy = trustedTypes.createPolicy(Math.random(), noopPolicy, true); let el = document.createElement("div"); - el.title = policy.createHTML(INPUTS.URL); - assert_equals(el.title, INPUTS.URL); - - el.title = policy.createURL(INPUTS.HTML); - assert_equals(el.title, INPUTS.HTML); + el.title = policy.createHTML(INPUTS.SCRIPTURL); + assert_equals(el.title, INPUTS.SCRIPTURL); }, "Attributes without type constraints will work as before."); test(t => { const policy = trustedTypes.createPolicy("nullpolicy", null); assert_throws(new TypeError(), _ => { policy.createScriptURL("foo"); }); - assert_throws(new TypeError(), _ => { policy.createURL("foo"); }); assert_throws(new TypeError(), _ => { policy.createHTML("foo"); }); assert_throws(new TypeError(), _ => { policy.createScript("foo"); }); }, "trustedTypes.createPolicy(.., null) creates empty policy."); @@ -95,7 +88,6 @@ const testCases = [ [TrustedHTML, "createHTML", "whatever", stringTestCases], [TrustedScript, "createScript", "whatever", stringTestCases], - [TrustedURL, "createURL", INPUTS.SCRIPTURL, urlTestCases], [TrustedScriptURL, "createScriptURL", INPUTS.SCRIPTURL, urlTestCases], ]; diff --git a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html index 05c7301af71..8608bcc24fe 100644 --- a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html @@ -224,79 +224,4 @@ p.createURL(INPUTS.URL); }); }, "createScriptURL defined - calling undefined callbacks throws"); - - - //URL tests - function createURLTest(policyName, policy, expectedURL, t) { - let p = window.trustedTypes.createPolicy(policyName, policy); - let url = p.createURL(INPUTS.URL); - assert_true(url instanceof TrustedURL); - assert_true(trustedTypes.isURL(url)); - assert_equals(url + "", expectedURL); - } - - test(t => { - createURLTest('TestPolicyURL1', { createURL: s => s }, INPUTS.URL, t); - }, "url = identity function"); - - test(t => { - createURLTest('TestPolicyURL2', { createURL: s => null }, "", t); - }, "url = null"); - - var URLstr = '#x'; - test(t => { - createURLTest('TestPolicyURL3', { createURL: s => s + URLstr }, INPUTS.URL + URLstr, t); - }, "url = string + global string"); - - var URLx = 'global'; - test(t => { - createURLTest('TestPolicyURL4', { createURL: s => { URLx = s; return s; } }, INPUTS.URL, t); - assert_equals(URLx, INPUTS.URL); - }, "url = identity function, global string changed"); - - test(t => { - let p = window.trustedTypes.createPolicy('TestPolicyURL5', { - createURL: s => { throw new Error(); } - }); - assert_throws(new Error(), _ => { - p.createURL(INPUTS.URL); - }); - }, "url = callback that throws"); - - function getURL(s) { - return s + this.bar; - } - - var obj = { - "bar": "#x" - } - - test(t => { - createURLTest('TestPolicyURL6', { createURL: getURL.bind(obj) }, INPUTS.URL + "#x", t); - }, "url = this bound to an object"); - - var bar = "#x"; - test(t => { - createURLTest('TestPolicyURL7', { createURL: s => getURL(s) }, INPUTS.URL + bar, t); - }, "url = this without bind"); - - test(t => { - let p = window.trustedTypes.createPolicy('TestPolicyURL8', null); - assert_throws(new TypeError(), _ => { - p.createURL(INPUTS.URL); - }); - }, "url - calling undefined callback throws"); - - test(t => { - let p = window.trustedTypes.createPolicy('TestPolicyURL9', { createURL: createURLJS }); - assert_throws(new TypeError(), _ => { - p.createHTML(INPUTS.HTML); - }); - assert_throws(new TypeError(), _ => { - p.createScript(INPUTS.SCRIPT); - }); - assert_throws(new TypeError(), _ => { - p.createScriptURL(INPUTS.SCRIPTURL); - }); - }, "createURL defined - calling undefined callbacks throws"); </script> diff --git a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html index f9ba8f27822..0e5a0f51c80 100644 --- a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html @@ -8,10 +8,11 @@ <div id="target"></div> <script> test(t => { - assert_equals(trustedTypes.getPropertyType("a", "href"), "TrustedURL"); - assert_equals(trustedTypes.getPropertyType("a", "id"), null); - assert_equals(trustedTypes.getPropertyType("a", "b"), null); - }, "sanity check trustedTypes.getPropertyType for the HTML a element."); + assert_equals(trustedTypes.getPropertyType("script", "text"), "TrustedScript"); + assert_equals(trustedTypes.getPropertyType("script", "src"), "TrustedScriptURL"); + assert_equals(trustedTypes.getPropertyType("script", "id"), null); + assert_equals(trustedTypes.getPropertyType("script", "b"), null); + }, "sanity check trustedTypes.getPropertyType for the HTML script element."); test(t => { assert_equals(trustedTypes.getAttributeType("img", "onerror"), "TrustedScript"); @@ -28,11 +29,9 @@ test(t => { // returns the proper type for attribute-related properties assert_equals(trustedTypes.getPropertyType("script", "src"), "TrustedScriptURL"); - assert_equals(trustedTypes.getPropertyType("img", "src"), "TrustedURL"); // is case insensitive for tag names assert_equals(trustedTypes.getPropertyType("SCRIPT", "src"), "TrustedScriptURL"); - assert_equals(trustedTypes.getPropertyType("ImG", "src"), "TrustedURL"); // is case sensitive for property names assert_equals(trustedTypes.getPropertyType("script", "sRc"), null); @@ -53,7 +52,6 @@ test(t => { // returns the proper type assert_equals(trustedTypes.getAttributeType('script', 'src'), 'TrustedScriptURL'); - assert_equals(trustedTypes.getAttributeType('img', 'src'), 'TrustedURL'); // ignores attributes from unknown namespaces assert_equals(trustedTypes.getAttributeType( @@ -61,11 +59,9 @@ // is case insensitive for element names assert_equals(trustedTypes.getAttributeType('SCRIPT', 'src'), 'TrustedScriptURL'); - assert_equals(trustedTypes.getAttributeType('imG', 'src'), 'TrustedURL'); // is case insensitive for the attribute names assert_equals(trustedTypes.getAttributeType('script', 'SRC'), 'TrustedScriptURL'); - assert_equals(trustedTypes.getAttributeType('imG', 'srC'), 'TrustedURL'); // supports the inline event handlers assert_equals(trustedTypes.getAttributeType('img', 'onerror'), 'TrustedScript'); @@ -82,7 +78,6 @@ // Spot testing some values. assert_equals(map["script"].attributes.src, "TrustedScriptURL"); - assert_equals(map["img"].attributes.src, "TrustedURL"); assert_equals(map["*"].properties.innerHTML, "TrustedHTML"); assert_equals(map["foo"], undefined); diff --git a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html index efaac5d90d8..c620451ba8f 100644 --- a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html @@ -10,7 +10,6 @@ const noopPolicy = { 'createHTML': (s) => s, 'createScriptURL': (s) => s, - 'createURL': (s) => s, 'createScript': (s) => s, }; @@ -65,23 +64,6 @@ assert_false(trustedTypes.isScriptURL(script3)); }, 'TrustedTypePolicyFactory.isScriptURL requires the object to be created via policy.'); - // isURL tests - test(t => { - const p = trustedTypes.createPolicy('url', noopPolicy); - let url = p.createURL(INPUTS.URL); - - assert_true(trustedTypes.isURL(url)); - let url2 = Object.create(url); - - // instanceof can pass, but we rely on isScript - assert_true(url2 instanceof TrustedURL); - assert_false(trustedTypes.isURL(url2)); - - let url3 = Object.assign({}, url, {toString: () => 'fake'}); - - assert_false(trustedTypes.isURL(url3)); - }, 'TrustedTypePolicyFactory.isURL requires the object to be created via policy.'); - // Test non-object parameters. test(t => { assert_false(trustedTypes.isHTML(null)); @@ -94,11 +76,6 @@ assert_false(trustedTypes.isScript(0.5)); assert_false(trustedTypes.isScript('test')); assert_false(trustedTypes.isScript({})); - assert_false(trustedTypes.isURL(null)); - assert_false(trustedTypes.isURL(123)); - assert_false(trustedTypes.isURL(0.5)); - assert_false(trustedTypes.isURL('test')); - assert_false(trustedTypes.isURL({})); assert_false(trustedTypes.isScriptURL(null)); assert_false(trustedTypes.isScriptURL(123)); assert_false(trustedTypes.isScriptURL(0.5)); @@ -126,30 +103,19 @@ assert_false(trustedTypes.isScriptURL({})); }, 'TrustedTypePolicyFactory.isScriptURL cannot be redefined.'); - test(t => { - try { trustedTypes.isURL = () => 'fake'; } catch { } - assert_false(trustedTypes.isURL({})); - }, 'TrustedTypePolicyFactory.isURL cannot be redefined.'); - // Redefinition tests, via Object.defineProperty. test(t => { - try { Object.defineProperty(TrustedTypes, 'isHTML', () => 'fake'); } catch { } + try { Object.defineProperty(trustedTypes, 'isHTML', () => 'fake'); } catch { } assert_false(trustedTypes.isHTML({})); }, 'TrustedTypePolicyFactory.IsHTML cannot be redefined via defineProperty.'); test(t => { - try { Object.defineProperty(TrustedTypes, 'isScript', () => 'fake'); } catch { } + try { Object.defineProperty(trustedTypes, 'isScript', () => 'fake'); } catch { } assert_false(trustedTypes.isScript({})); }, 'TrustedTypePolicyFactory.isScript cannot be redefined via definePropert.'); test(t => { - try { Object.defineProperty(TrustedTypes, 'isScriptURL', () => 'fake'); } catch { } + try { Object.defineProperty(trustedTypes, 'isScriptURL', () => 'fake'); } catch { } assert_false(trustedTypes.isScriptURL({})); }, 'TrustedTypePolicyFactory.isScriptURL cannot be redefined via definePropert.'); - - test(t => { - try { Object.defineProperty(TrustedTypes, 'isURL', () => 'fake'); } catch { } - assert_false(trustedTypes.isURL({})); - }, 'TrustedTypePolicyFactory.isURL cannot be redefined via definePropert.'); - </script> diff --git a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html index 70f77b1bb55..da7d1b4f877 100644 --- a/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html @@ -8,18 +8,15 @@ <body> <div id="target"></div> <script> - const policy = trustedTypes.createPolicy("anythinggoes", { "createHTML": x => x, "createScript": x => x, - "createURL": x => x, "createScriptURL": x => x, }); const create_value = { "TrustedHTML": policy.createHTML("hello"), "TrustedScript": policy.createScript("x => x + x"), - "TrustedURL": policy.createURL("https://url.invalid/"), "TrustedScriptURL": policy.createScriptURL("https://url.invalid/blubb.js"), null: "empty", }; @@ -34,8 +31,7 @@ // Also add several event handlers (onclick). let elements = ['madeup', 'b']; let properties = ['madeup', 'id', "onerror", "onclick"]; - const types = [null, "TrustedHTML", "TrustedScript", "TrustedScriptURL", - "TrustedURL"]; + const types = [null, "TrustedHTML", "TrustedScript", "TrustedScriptURL"]; // We'll wrap construction of the elements/properties list in a test, mainly // so we'll get decent error messages when it might fail. @@ -112,6 +108,11 @@ // return and hence skip the result comparison. case "outerHTML": return; + // URL-typed accessors + case "src": + if (elem == "iframe") + return; + break; // Properties starting with "on" are usually error handlers, // which will parse their input as a function. In this case, // also skip the result comparison. @@ -142,6 +143,5 @@ } } } - </script> </body> diff --git a/tests/wpt/web-platform-tests/trusted-types/Window-open.tentative.html b/tests/wpt/web-platform-tests/trusted-types/Window-open.tentative.html deleted file mode 100644 index 172d566e57f..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/Window-open.tentative.html +++ /dev/null @@ -1,25 +0,0 @@ -<!DOCTYPE html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="support/helper.sub.js"></script> -<body> -<script> - // helper functions for the tests - function testWindowOpen(t, win, testNumber) { - let p = createURL_policy(window, testNumber); - let url = p.createURL(INPUTS.URL); - let child_window = win.open(url, "", ""); - child_window.onload = t.step_func_done(_ => { - assert_equals(child_window.location.href, "" + url); - child_window.close(); - }); - } - - test(t => { - testWindowOpen(t, window, 1); - }, "window.open via policy (successful URL transformation)."); - - test(t => { - testWindowOpen(t, document, 2); - }, "document.open via policy (successful URL transformation)."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html index 3cae5d29b44..1d6f3f6fe62 100644 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html @@ -11,33 +11,6 @@ <script> const nullPolicy = trustedTypes.createPolicy('NullPolicy', {createScript: s => s}); - // TrustedURL Assignments - const URLTestCases = [ - [ 'a', 'href' ], - [ 'area', 'href' ], - [ 'base', 'href' ], - [ 'button', 'formAction' ], - [ 'form', 'action' ], - [ 'frame', 'src' ], - [ 'iframe', 'src' ], - [ 'img', 'src' ], - [ 'input', 'formAction' ], - [ 'input', 'src' ], - [ 'link', 'href' ], - [ 'video', 'src' ], - [ 'source', 'src' ], - [ 'track', 'src' ] - ]; - - URLTestCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_url_explicit_set(window, c, t, c[0], c[1], RESULTS.URL); - assert_throws_no_trusted_type_explicit_set(c[0], c[1], 'A string'); - assert_throws_no_trusted_type_explicit_set(c[0], c[1], null); - assert_throws_no_trusted_type_explicit_set(c[0], c[1], nullPolicy.createScript('script')); - }, c[0] + "." + c[1] + " accepts only TrustedURL"); - }); - // TrustedScriptURL Assignments const scriptURLTestCases = [ [ 'embed', 'src' ], @@ -83,24 +56,17 @@ }); test(t => { - let el = document.createElement('iframe'); + let el = document.createElement('script'); assert_throws(new TypeError(), _ => { el.setAttribute('SrC', INPUTS.URL); }); assert_equals(el.src, ''); - }, "`Element.prototype.setAttribute.SrC = string` throws."); + }, "`Script.prototype.setAttribute.SrC = string` throws."); // After default policy creation string and null assignments implicitly call createXYZ - let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS, createScript: createScriptJS }, true); - URLTestCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_type(c[0], c[1], INPUTS.URL, RESULTS.URL); - assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null")); - }, c[0] + "." + c[1] + " accepts string and null after default policy was created."); - }); - + let p = window.trustedTypes.createPolicy("default", { createScriptURL: createScriptURLJS, createHTML: createHTMLJS, createScript: createScriptJS }, true); scriptURLTestCases.forEach(c => { test(t => { assert_element_accepts_trusted_type(c[0], c[1], INPUTS.SCRIPTURL, RESULTS.SCRIPTURL); @@ -124,10 +90,6 @@ // Other attributes can be assigned with TrustedTypes or strings or null values test(t => { - assert_element_accepts_trusted_url_explicit_set(window, 'arel', t, 'a', 'rel', RESULTS.URL); - }, "a.rel assigned via policy (successful URL transformation)"); - - test(t => { assert_element_accepts_non_trusted_type_explicit_set('a', 'rel', 'A string', 'A string'); }, "a.rel accepts strings"); @@ -136,14 +98,14 @@ }, "a.rel accepts null"); test(t => { - let div = document.createElement('div'); - let span = document.createElement('span'); + let embed = document.createElement('embed'); + let script = document.createElement('script'); - div.setAttribute('src', INPUTS.URL); - let attr = div.getAttributeNode('src'); - div.removeAttributeNode(attr); - span.setAttributeNode(attr); + embed.setAttribute('src', INPUTS.SCRIPTURL); + let attr = embed.getAttributeNode('src'); + embed.removeAttributeNode(attr); + script.setAttributeNode(attr); - assert_equals(span.getAttribute('src'), INPUTS.URL); - }, "`span.src = setAttributeNode(div.src)` with string works."); + assert_equals(script.getAttribute('src'), RESULTS.SCRIPTURL); + }, "`script.src = setAttributeNode(embed.src)` with string works."); </script> diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html index 76a639a6227..5754521b2bd 100644 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html @@ -21,10 +21,6 @@ assert_element_accepts_trusted_script_url_set_ns(window, '2', t, 'a', 'b', RESULTS.SCRIPTURL); }, "Element.setAttributeNS assigned via policy (successful ScriptURL transformation)"); - test(t => { - assert_element_accepts_trusted_url_set_ns(window, '3', t, 'a', 'b', RESULTS.URL); - }, "Element.setAttributeNS assigned via policy (successful URL transformation)"); - // Unknown, namespaced attributes should not be TT checked: test(t => { assert_element_accepts_non_trusted_type_set_ns('a', 'b', 'A string', 'A string'); @@ -35,84 +31,12 @@ }, "Element.setAttributeNS accepts null for non-specced accessor"); // Setup trusted values for use in subsequent tests. - const url = createURL_policy(window, '4').createURL(INPUTS.URL); const script_url = createScriptURL_policy(window, '5').createScriptURL(INPUTS.ScriptURL); const html = createHTML_policy(window, '6').createHTML(INPUTS.HTML); const script = createScript_policy(window, '7').createScript(INPUTS.Script); - // SVG elements that use xlink:href (SVGURIReference) and that expect - // TrustedURL. - // There a number of affected elements, and there are several ways to set - // a namespaced attribute. Let's iterate over all combinations. const xlink = "http://www.w3.org/1999/xlink"; const svg = "http://www.w3.org/2000/svg"; - const elems = [ "a", "animate", "animateMotion", "animateTransform", - "discard", "feImage", "filter", "image", "linearGradient", - "mpath", "pattern", "radialGradient", "set", "textPath", - "use" ]; - - // There are multiple ways to set a namespaced attribute. Let's encapsulate - // each in a function. - const variants = { - "setAttributeNS with prefix": (element_name, value) => { - let elem = document.createElementNS(svg, element_name); - elem.setAttributeNS(xlink, "xlink:href", value); - return elem; - }, - "setAttributeNS without prefix": (element_name, value) => { - let elem = document.createElementNS(svg, element_name); - elem.setAttributeNS(xlink, "href", value); - return elem; - }, - "setAttribute with prefix": (element_name, value) => { - let elem = document.createElementNS(svg, element_name); - // Create the namespaced attribute with setAttributeNS. Then refer - // to it with the prefix in setAttribute. This test will break - // if either setAttributeNS or setAttribtue functionality it broken. - elem.setAttributeNS(xlink, "xlink:href", url); - elem.setAttribute("xlink:href", value); - return elem; - } - }; - for (const e of elems) { - for (const variant in variants) { - // Assigning a TrustedURL works. - test(t => { - let elem = variants[variant](e, url); - assert_equals("" + RESULTS.URL, - elem.getAttributeNodeNS(xlink, "href").value); - }, "Assigning TrustedURL to <svg:" + e + "> works via " + variant); - - // Assigning things that ought to not work. - const values = ["abc", null, script_url, html, script]; - values.forEach((value, index) => { - test(t => { - assert_throws(new TypeError(), _ => { variants[variant](e, value); }); - }, "Blocking non-TrustedURL assignment to <svg:" + e + "> via " + - variant + " value no " + index); - }); - } - } - - // Test 'synchronization' of 'xlink:href'. - test(t => { - // ..setAttribute("xlink:href") will behave differently, depending on - // whether the element already has an attribute by that name. Make sure - // that Trusted Type handling respects that difference. - - // Case 1: "xlink:href" on an empty element: This is an unknown attribute - // not processed by SVG, and string assignment should work. - let elem1 = document.createElementNS(svg, "a"); - elem1.setAttribute("xlink:href", "abc"); - - // Case 2: "xlink:href", after a namespaced attribute has been set: Now - // this mirrors the SVG attribute, and string assignment should fail. - let elem2 = document.createElementNS(svg, "a"); - elem2.setAttributeNS(xlink, "xlink:href", url); - assert_throws(new TypeError(), _ => { - elem2.setAttribute("xlink:href", "abc"); - }); - }, "Test synchronized, namespaced attributes."); // svg:script xlink:href=... expects a TrustedScriptURL. // Assigning a TrustedScriptURL works. @@ -126,7 +50,7 @@ // Assigning things that ought to not work. test(t => { let elem = document.createElementNS(svg, "script"); - const values = [ "abc", null, url, html, script ]; + const values = [ "abc", null, html, script ]; for (const v of values) { assert_throws(new TypeError(), _ => { elem.setAttributeNS(xlink, "href", v); diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html index 89d1216d27e..84ff83bc083 100644 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html @@ -10,32 +10,6 @@ <body> <script> var testnb = 0; - // TrustedURL Assignments - const URLTestCases = [ - [ 'a', 'href' ], - [ 'area', 'href' ], - [ 'base', 'href' ], - [ 'button', 'formAction' ], - [ 'form', 'action' ], - [ 'frame', 'src' ], - [ 'iframe', 'src' ], - [ 'img', 'src' ], - [ 'input', 'formAction' ], - [ 'input', 'src' ], - [ 'link', 'href' ], - [ 'video', 'src' ], - [ 'source', 'src' ], - [ 'track', 'src' ] - ]; - - URLTestCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_url(window, ++testnb, t, c[0], c[1], RESULTS.URL); - assert_throws_no_trusted_type(c[0], c[1], 'A string'); - assert_throws_no_trusted_type(c[0], c[1], null); - }, c[0] + "." + c[1] + " accepts only TrustedURL"); - }); - // TrustedScriptURL Assignments const scriptURLTestCases = [ [ 'embed', 'src' ], @@ -69,14 +43,7 @@ }); // After default policy creation string and null assignments implicitly call createHTML - let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS, createScriptURL: createScriptURLJS, createHTML: createHTMLJS }, true); - - URLTestCases.forEach(c => { - test(t => { - assert_element_accepts_trusted_type(c[0], c[1], INPUTS.URL, RESULTS.URL); - assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null")); - }, c[0] + "." + c[1] + " accepts string and null after default policy was created"); - }); + let p = window.trustedTypes.createPolicy("default", { createScriptURL: createScriptURLJS, createHTML: createHTMLJS }, true); scriptURLTestCases.forEach(c => { test(t => { diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-assign.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-assign.tentative.html deleted file mode 100644 index 8e89d0d1a60..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-assign.tentative.html +++ /dev/null @@ -1,53 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/helper.sub.js"></script> - - <meta http-equiv="Content-Security-Policy" content="trusted-types *"> -</head> -<body> -<script> - // TrustedURL assignments do not throw. - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.assign(url); - assert_equals("" + url, location.href, "location href"); - }, "location.assign via policy (successful URL transformation)."); - - // String assignments throw. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.assign("A string"); - }); - assert_equals(location.href, href); - }, "`location.assign = string` throws"); - - // Null assignment throws. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.assign(null); - }); - assert_equals(location.href, href); - }, "`location.assign = null` throws"); - - // Create default policy. Applies to all subsequent tests. - let p = window.trustedTypes.createPolicy("default", - { createURL: createLocationURLJS }, true); - - // After default policy creation string assignment implicitly calls createURL. - test(t => { - location.assign("abcdefg"); - assert_true(location.href.endsWith("#abcdefg")); - }, "`location.assign = string` via default policy (successful URL transformation)."); - - // After default policy creation null assignment implicitly calls createURL. - test(t => { - location.assign(null); - assert_true(location.href.endsWith("#null")); - }, "`location.assign = null` via default policy does not throw."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-href.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-href.tentative.html deleted file mode 100644 index 998ee21f345..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-href.tentative.html +++ /dev/null @@ -1,53 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/helper.sub.js"></script> - - <meta http-equiv="Content-Security-Policy" content="trusted-types *"> -</head> -<body> -<script> - // TrustedURL assignments do not throw. - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.href = url; - assert_equals("" + url, location.href, "location href"); - }, "location.href assigned via policy (successful URL transformation)."); - - // String assignments throw. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.href = 'A string'; - }); - assert_equals(location.href, href); - }, "`location.href = string` throws"); - - // Null assignment throws. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.href = null; - }); - assert_equals(location.href, href); - }, "`location.href = null` throws"); - - // Create default policy. Applies to all subsequent tests. - let p = window.trustedTypes.createPolicy("default", - { createURL: createLocationURLJS }, true); - - // After default policy creation string assignment implicitly calls createURL. - test(t => { - location.href = "xxxx"; - assert_true(location.href.endsWith("#xxxx")); - }, "`location.href = string` via default policy (successful URL transformation)."); - - // After default policy creation null assignment implicitly calls createURL. - test(t => { - location.href = null; - assert_true(location.href.endsWith("#null")); - }, "`location.href = null` assigned via default policy does not throw."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-replace.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-replace.tentative.html deleted file mode 100644 index e85bb646fc9..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Location-replace.tentative.html +++ /dev/null @@ -1,53 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/helper.sub.js"></script> - - <meta http-equiv="Content-Security-Policy" content="trusted-types *"> -</head> -<body> -<script> - // TrustedURL replacements do not throw. - test(t => { - let p = createURL_policy(window, 1); - let url = p.createURL(location.href + "#xxx"); - location.replace(url); - assert_equals("" + url, location.href, "location href"); - }, "location.replace via policy (successful URL transformation)."); - - // String replacements throw. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.replace("A string"); - }); - assert_equals(location.href, href); - }, "`location.replace = string` throws"); - - // Null replacement throws. - test(t => { - let href = location.href; - assert_throws(new TypeError(), _ => { - location.replace(null); - }); - assert_equals(location.href, href); - }, "`location.replace = null` throws"); - - // Create default policy. Applies to all subsequent tests. - let p = window.trustedTypes.createPolicy("default", - { createURL: createLocationURLJS }, true); - - // After default policy creation string assignment implicitly calls createURL. - test(t => { - location.replace("potato"); - assert_true(location.href.endsWith("#potato")); - }, "`location.replace = string` via default policy (successful URL transformation)."); - - // After default policy creation null assignment implicitly calls createURL. - test(t => { - location.replace(null); - assert_true(location.href.endsWith("#null")); - }, "`location.replace = null` via default policy (successful URL transformation)."); -</script> diff --git a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Window-open.tentative.html b/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Window-open.tentative.html deleted file mode 100644 index e9c1c79050b..00000000000 --- a/tests/wpt/web-platform-tests/trusted-types/block-string-assignment-to-Window-open.tentative.html +++ /dev/null @@ -1,85 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/helper.sub.js"></script> - - <meta http-equiv="Content-Security-Policy" content="trusted-types *"> -</head> -<body> -<script> - var testnb = 0; - // helper functions for the tests - function testWindowOpen(t, win, nb) { - let p = createURL_policy(window, nb); - let url = p.createURL(INPUTS.URL); - let child_window = win.open(url, "", ""); - t.add_cleanup(_ => child_window.close()); - child_window.onload = t.step_func_done(_ => { - assert_equals(child_window.location.href, "" + url); - }); - } - - function testWindowThrows(t, url, win, nb) { - let p = createURL_policy(window, nb); - assert_throws(new TypeError(), _ => { - let child_window = win.open(url, "", ""); - }); - } - - function testWindowDoesntThrow(t, url, expected, win) { - let child_window = win.open(url, "", ""); - t.add_cleanup(_ => child_window.close()); - child_window.onload = t.step_func_done(_ => { - assert_equals(child_window.location.href, expected); - }); - } - - // TrustedURL assignments do not throw. - test(t => { - testWindowOpen(t, window, ++testnb); - }, "window.open via policy (successful URL transformation)."); - - test(t => { - testWindowOpen(t, document, ++testnb); - }, "document.open via policy (successful URL transformation)."); - - // String assignments throw. - test(t => { - testWindowThrows(t, 'A string', window, ++testnb); - }, "`window.open(string)` throws."); - - test(t => { - testWindowThrows(t, 'A string', document, ++testnb); - }, "`document.open(string)` throws."); - - // Null assignment throws. - test(t => { - testWindowThrows(t, null, window, ++testnb); - }, "`window.open(null)` throws."); - - test(t => { - testWindowThrows(t, null, document, ++testnb); - }, "`document.open(null)` throws."); - - // After default policy creation string assignment implicitly calls createURL. - let p = window.trustedTypes.createPolicy("default", { createURL: createURLJS }, true); - test(t => { - testWindowDoesntThrow(t, INPUTS.URL, RESULTS.URL, window); - }, "'window.open(string)' assigned via default policy (successful URL transformation)."); - - test(t => { - testWindowDoesntThrow(t, INPUTS.URL, RESULTS.URL, document); - }, "'document.open(string)' assigned via default policy (successful URL transformation)."); - - test(t => { - testWindowDoesntThrow(t, null, "null", window); - }, "'window.open(null)' assigned via default policy does not throw."); - - test(t => { - testWindowDoesntThrow(t, null, "null", document); - }, "'document.open(null)' assigned via default policy does not throw."); -</script> -</body> -</html> diff --git a/tests/wpt/web-platform-tests/trusted-types/default-policy-report-only.tentative.html b/tests/wpt/web-platform-tests/trusted-types/default-policy-report-only.tentative.html index 1a54fd62329..ba23d7a3678 100644 --- a/tests/wpt/web-platform-tests/trusted-types/default-policy-report-only.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/default-policy-report-only.tentative.html @@ -39,7 +39,6 @@ promise_test(t => { }, "Count SecurityPolicyViolation events."); const testCases = [ - [ "a", "href"], [ "script", "src" ], [ "div", "innerHTML" ], [ "script", "text" ], @@ -71,7 +70,6 @@ function policy(str) { } trustedTypes.createPolicy("default", { - createURL: policy, createScriptURL: policy, createHTML: policy, createScript: policy @@ -105,6 +103,6 @@ testCases.forEach(c => { }); // Trigger the exit condition in the "Count" promise test above. -try { document.createElement("a").href = "done"; } catch (e) {} +try { document.createElement("script").text = "done"; } catch (e) {} </script> </body> diff --git a/tests/wpt/web-platform-tests/trusted-types/default-policy.tentative.html b/tests/wpt/web-platform-tests/trusted-types/default-policy.tentative.html index 672eccfb430..955cdfaa404 100644 --- a/tests/wpt/web-platform-tests/trusted-types/default-policy.tentative.html +++ b/tests/wpt/web-platform-tests/trusted-types/default-policy.tentative.html @@ -39,7 +39,6 @@ promise_test(t => { }, "Count SecurityPolicyViolation events."); const testCases = [ - [ "a", "href"], [ "script", "src" ], [ "div", "innerHTML" ], [ "script", "text" ], @@ -71,7 +70,6 @@ function policy(str) { } trustedTypes.createPolicy("default", { - createURL: policy, createScriptURL: policy, createHTML: policy, createScript: policy @@ -105,6 +103,6 @@ testCases.forEach(c => { }); // Trigger the exit condition in the "Count" promise test above. -try { document.createElement("a").href = "done"; } catch (e) {} +try { document.createElement("script").text = "done"; } catch (e) {} </script> </body> diff --git a/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js b/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js index 4c1ee6e04a3..7be9615ce67 100644 --- a/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js +++ b/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js @@ -11,7 +11,6 @@ idl_test( TrustedHTML: ['window.trustedTypes.createPolicy("SomeName1", { createHTML: s => s }).createHTML("A string")'], TrustedScript: ['window.trustedTypes.createPolicy("SomeName2", { createScript: s => s }).createScript("A string")'], TrustedScriptURL: ['window.trustedTypes.createPolicy("SomeName3", { createScriptURL: s => s }).createScriptURL("A string")'], - TrustedURL: ['window.trustedTypes.createPolicy("SomeName4", { createURL: s => s }).createURL("A string")'] }); }, 'Trusted Types' diff --git a/tests/wpt/web-platform-tests/trusted-types/support/helper.sub.js b/tests/wpt/web-platform-tests/trusted-types/support/helper.sub.js index d63ff54ad60..d13ad567a72 100644 --- a/tests/wpt/web-platform-tests/trusted-types/support/helper.sub.js +++ b/tests/wpt/web-platform-tests/trusted-types/support/helper.sub.js @@ -2,14 +2,12 @@ const INPUTS = { HTML: "Hi, I want to be transformed!", SCRIPT: "Hi, I want to be transformed!", SCRIPTURL: "http://this.is.a.scripturl.test/", - URL: "http://hello.i.am.an.url/" }; const RESULTS = { HTML: "Quack, I want to be a duck!", SCRIPT: "Meow, I want to be a cat!", SCRIPTURL: "http://this.is.a.successful.test/", - URL: "http://hooray.i.am.successfully.transformed/" }; function createHTMLJS(html) { @@ -26,19 +24,6 @@ function createScriptURLJS(scripturl) { return scripturl.replace("scripturl", "successful"); } -function createURLJS(url) { - return url.replace("hello", "hooray") - .replace("an.url", "successfully.transformed"); -} - -// When testing location.href (& friends), we have the problem that assigning -// to the new location will navigate away from the test. To fix this, we'll -// have a policy that will just stick the argument into the fragment identifier -// of the current location.href. -function createLocationURLJS(value) { - return location.href.replace(/#.*/g, "") + "#" + value; -} - function createHTML_policy(win, c) { return win.trustedTypes.createPolicy('SomeHTMLPolicyName' + c, { createHTML: createHTMLJS }); } @@ -51,10 +36,6 @@ function createScriptURL_policy(win, c) { return win.trustedTypes.createPolicy('SomeScriptURLPolicyName' + c, { createScriptURL: createScriptURLJS }); } -function createURL_policy(win, c) { - return win.trustedTypes.createPolicy('SomeURLPolicyName' + c, { createURL: createURLJS }); -} - function assert_element_accepts_trusted_html(win, c, t, tag, attribute, expected) { let p = createHTML_policy(win, c); let html = p.createHTML(INPUTS.HTML); @@ -73,12 +54,6 @@ function assert_element_accepts_trusted_script_url(win, c, t, tag, attribute, ex assert_element_accepts_trusted_type(tag, attribute, scripturl, expected); } -function assert_element_accepts_trusted_url(win, c, t, tag, attribute, expected) { - let p = createURL_policy(win, c); - let url = p.createURL(INPUTS.URL); - assert_element_accepts_trusted_type(tag, attribute, url, expected); -} - function assert_element_accepts_trusted_type(tag, attribute, value, expected) { let elem = document.createElement(tag); elem[attribute] = value; @@ -112,12 +87,6 @@ function assert_element_accepts_trusted_script_url_explicit_set(win, c, t, tag, assert_element_accepts_trusted_type_explicit_set(tag, attribute, scripturl, expected); } -function assert_element_accepts_trusted_url_explicit_set(win, c, t, tag, attribute, expected) { - let p = createURL_policy(win, c); - let url = p.createURL(INPUTS.URL); - assert_element_accepts_trusted_type_explicit_set(tag, attribute, url, expected); -} - function assert_element_accepts_trusted_type_explicit_set(tag, attribute, value, expected) { let elem = document.createElement(tag); elem.setAttribute(attribute, value); @@ -163,12 +132,6 @@ function assert_element_accepts_trusted_script_url_set_ns(win, c, t, tag, attrib assert_element_accepts_trusted_type_set_ns(tag, attribute, scripturl, expected); } -function assert_element_accepts_trusted_url_set_ns(win, c, t, tag, attribute, expected) { - let p = createURL_policy(win, c); - let url = p.createURL(INPUTS.URL); - assert_element_accepts_trusted_type_set_ns(tag, attribute, url, expected); -} - function assert_element_accepts_trusted_type_set_ns(tag, attribute, value, expected) { let elem = document.createElement(tag); elem.setAttributeNS(namespace, attribute, value); diff --git a/tests/wpt/web-platform-tests/trusted-types/trusted-types-report-only.tentative.https.html b/tests/wpt/web-platform-tests/trusted-types/trusted-types-report-only.tentative.https.html index 1a17d529fd1..bf0a1eb9c19 100644 --- a/tests/wpt/web-platform-tests/trusted-types/trusted-types-report-only.tentative.https.html +++ b/tests/wpt/web-platform-tests/trusted-types/trusted-types-report-only.tentative.https.html @@ -7,14 +7,14 @@ <body> <!-- Some elements for the tests to act on. --> - <a id="anchor" href="#">anchor</a> <div id="div"></div> <script id="script-src" src=""></script> <script id="script"></script> + <script id="script2"></script> <script> // CSP insists the "trusted-types: ..." directives are deliverd as headers - // (rather than as "<meta http-equiv" tags). This test assumes the following + // (rather than as "meta http-equiv" tags). This test assumes the following // headers are set in the .headers file: // // Content-Security-Policy-Report-Only: trusted-types ...; report-uri ... @@ -39,17 +39,16 @@ const policy = trustedTypes.createPolicy("two", { createHTML: id, createScriptURL: id, - createURL: id, createScript: id, }); - - +/* promise_test(t => { let p = expect_violation("trusted-types two"); - document.getElementById("anchor").href = "#abc"; - assert_true(document.getElementById("anchor").href.endsWith("#abc")); + document.getElementById("script").src = "#abc"; + assert_true(document.getElementById("script").src.endsWith("#abc")); return p; - }, "Trusted Type violation report-only: assign string to url"); + }, "Trusted Type violation report-only: assign string to script url"); +*/ promise_test(t => { let p = expect_violation("trusted-types two"); @@ -74,7 +73,7 @@ promise_test(t => { let p = expect_violation("trusted-types two"); - document.getElementById("anchor").href = "#def"; + document.getElementById("script").src = "#def"; return p.then(report => { assert_equals(report.documentURI, "" + window.location); assert_equals(report.disposition, "report"); @@ -83,7 +82,5 @@ assert_true(report.originalPolicy.startsWith("trusted-types two;")); }); }, "Trusted Type violation report: check report contents"); - </script> - </body> diff --git a/tests/wpt/web-platform-tests/trusted-types/trusted-types-reporting.tentative.https.html b/tests/wpt/web-platform-tests/trusted-types/trusted-types-reporting.tentative.https.html index 6a79fec07b6..10a951fa12c 100644 --- a/tests/wpt/web-platform-tests/trusted-types/trusted-types-reporting.tentative.https.html +++ b/tests/wpt/web-platform-tests/trusted-types/trusted-types-reporting.tentative.https.html @@ -77,7 +77,6 @@ const a_policy = { createHTML: id, createScriptURL: id, - createURL: id, createScript: id, }; @@ -127,9 +126,9 @@ promise_test(t => { let p = promise_violation("trusted-types two")(); - expect_throws(_ => document.getElementById("anchor").href = url); + expect_throws(_ => document.getElementById("script").src = url); return p; - }, "Trusted Type violation report: assign string to url"); + }, "Trusted Type violation report: assign string to script url"); promise_test(t => { let p = promise_violation("trusted-types two")(); @@ -139,10 +138,10 @@ promise_test(t => { let p = promise_flush()(); - document.getElementById("anchor").href = policy_one.createURL("#"); + document.getElementById("script").text = policy_one.createScript("2+2;"); flush(); return p; - }, "Trusted Type violation report: assign trusted URL to url; no report"); + }, "Trusted Type violation report: assign trusted script to script; no report"); promise_test(t => { let p = promise_flush()(); @@ -165,10 +164,10 @@ let p = Promise.resolve() .then(promise_violation("trusted-types two")) .then(expect_blocked_uri("trusted-types-sink")) - .then(expect_sample("HTMLAnchorElement.href")); - expect_throws(_ => { document.getElementById("anchor").href = "" }); + .then(expect_sample("HTMLScriptElement.src")); + expect_throws(_ => { document.getElementById("script").src = "" }); return p; - }, "Trusted Type violation report: sample for .href assignment"); + }, "Trusted Type violation report: sample for script.src assignment"); promise_test(t => { let p = Promise.resolve() @@ -210,24 +209,24 @@ // refer to the DOM elements being modified, so that Custom Elements cannot // "mask" the underlying DOM mechanism (for reporting). if (customElements) { - class CustomLink extends HTMLAnchorElement {}; - customElements.define("custom-link", CustomLink, { extends: "a" }); + class CustomScript extends HTMLScriptElement {}; + customElements.define("custom-script", CustomScript, { extends: "script" }); promise_test(t => { let p = Promise.resolve() .then(promise_violation("trusted-types one")) .then(expect_blocked_uri("trusted-types-sink")) - .then(expect_sample("HTMLAnchorElement.href")) + .then(expect_sample("HTMLScriptElement.src")) .then(expect_sample("abc")); - expect_throws(_ => document.getElementById("customlink").href = "abc"); + expect_throws(_ => document.getElementById("customscript").src = "abc"); return p; }, "Trusted Type violation report: sample for custom element assignment"); } + </script> <!-- Some elements for the tests to act on. --> - <a id="anchor" href="">anchor</a> <div id="div"></div> <script id="script"></script> - <a id="customlink" is="custom-link" href="a"></a> + <script id="customscript" is="custom-script" src="a"></script> </body> diff --git a/tests/wpt/web-platform-tests/wake-lock/wakelockpermissiondescriptor.https.html b/tests/wpt/web-platform-tests/wake-lock/wakelockpermissiondescriptor.https.html new file mode 100644 index 00000000000..673990f36f6 --- /dev/null +++ b/tests/wpt/web-platform-tests/wake-lock/wakelockpermissiondescriptor.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<link rel="help" href="https://w3c.github.io/wake-lock/#the-wakelockpermissiondescriptor-dictionary"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// Checking for the permission status requires testdriver.js support for permissions. +// See https://github.com/web-platform-tests/wpt/issues/5671. + +promise_test(t => { + return promise_rejects(t, new TypeError(), navigator.permissions.query({ name:'wake-lock' })); +}, "WakeLockPermissionDescriptor's type attribute is required"); + +promise_test(t => { + return promise_rejects(t, new TypeError(), navigator.permissions.query({ name: 'wake-lock', type: 'foo' })); +}, "WakeLockPermissionDescriptor's type attribute must be a WakeLockType"); +</script>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/web-nfc/NDEFMessage_constructor.https.html b/tests/wpt/web-platform-tests/web-nfc/NDEFMessage_constructor.https.html index 19122112f59..88c9ec4006e 100644 --- a/tests/wpt/web-platform-tests/web-nfc/NDEFMessage_constructor.https.html +++ b/tests/wpt/web-platform-tests/web-nfc/NDEFMessage_constructor.https.html @@ -26,8 +26,8 @@ assert_true(typeof message.records[0].text() === 'string'); assert_equals(message.records[0].text(), test_text_data, 'text() contains the same text content'); - assert_equals(message.records[0].arrayBuffer(), null, - 'arrayBuffer() returns null'); + assert_true(message.records[0].arrayBuffer() instanceof ArrayBuffer, + 'arrayBuffer() returns an ArrayBuffer'); assert_equals(message.records[0].json(), null, 'json() returns null'); }, 'NDEFMessage constructor with a text record'); diff --git a/tests/wpt/web-platform-tests/web-nfc/NFCReader_scan_iframe.https.html b/tests/wpt/web-platform-tests/web-nfc/NFCReader_scan_iframe.https.html new file mode 100644 index 00000000000..1f29fe4b41d --- /dev/null +++ b/tests/wpt/web-platform-tests/web-nfc/NFCReader_scan_iframe.https.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>NFCWriter.scan with an focused iframe</title> +<link rel="help" href="https://w3c.github.io/web-nfc/"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/nfc-helpers.js"></script> +<body> +<script> + +nfc_test(async (t, mockNFC) => { + const reader = new NFCReader(); + const controller = new AbortController(); + const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]); + + const promise = readerWatcher.wait_for("reading").then(event => { + assert_true(event instanceof NFCReadingEvent); + controller.abort(); + }); + reader.scan({ signal: controller.signal }); + + const iframe = document.createElement('iframe'); + iframe.src = 'resources/support-iframe.html'; + + const iframeLoadWatcher = new EventWatcher(t, iframe, 'load'); + document.body.appendChild(iframe); + await iframeLoadWatcher.wait_for('load'); + // Focus on iframe + iframe.contentWindow.document.getElementById('foo').focus(); + assert_true(iframe.contentDocument.hasFocus(), 'iframe gains the focus'); + + mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)])); + await promise; + + // Remove iframe from main document. + iframe.parentNode.removeChild(iframe); +}, 'Test that NFCWriter.scan is not suspended if iframe gains focus.'); + +</script> +</body>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/web-nfc/NFCWriter_push.https.html b/tests/wpt/web-platform-tests/web-nfc/NFCWriter_push.https.html index dda160f159a..6b4034fccc2 100644 --- a/tests/wpt/web-platform-tests/web-nfc/NFCWriter_push.https.html +++ b/tests/wpt/web-platform-tests/web-nfc/NFCWriter_push.https.html @@ -377,4 +377,69 @@ nfc_test(async (t, mockNFC) => { }); }); }, "NFCWriter.push should replace all previously configured push operations."); -</script>
\ No newline at end of file + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ data: test_text_data}] }); + assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage()); +}, "Test that recordType should be set to 'text' if NDEFRecordInit.record's \ +recordType is undefined and NDEFRecordInit.record's data is DOMString."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ data: test_buffer_data}] }); + assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage()); +}, "Test that recordType should be set to 'opaque' if NDEFRecordInit.record's \ +recordType is undefined and NDEFRecordInit.record's data is ArrayBuffer."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ data: test_json_data }] }); + const message = createMessage([createJsonRecord(test_json_data)]); + assertNDEFMessagesEqual(message, mockNFC.pushedMessage()); +}, "Test that recordType should be set to 'json' if NDEFRecordInit.record's \ +recordType is undefined and NDEFRecordInit.record's data is not DOMString or \ +ArrayBuffer."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ recordType: "text", data: test_text_data }] }); + assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage()); +}, "Test that mediaType should be set to 'text/plain' if NDEFRecordInit.record's \ +recordType is 'text' and NDEFRecordInit.record's mediaType is undefined."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ recordType: "opaque", data: test_buffer_data }] }); + assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage()); +}, "Test that mediaType should be set to 'application/octet-stream' if \ +NDEFRecordInit.record's recordType is 'opaque' and NDEFRecordInit.record's \ +mediaType is undefined."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ recordType: "json", data: test_json_data }] }); + const message = createMessage([createJsonRecord(test_json_data)]); + assertNDEFMessagesEqual(message, mockNFC.pushedMessage()); +}, "Test that mediaType should be set to 'application/json' if \ +NDEFRecordInit.record's recordType is 'json' and NDEFRecordInit.record's \ +mediaType is undefined."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ recordType: "url", data: test_url_data }] }); + const message = createMessage([createUrlRecord(test_url_data)]); + assertNDEFMessagesEqual(message, mockNFC.pushedMessage()); +}, "Test that mediaType should be set to 'text/plain' if NDEFRecordInit.record's \ +recordType is 'url' and NDEFRecordInit.record's mediaType is undefined."); + +nfc_test(async (t, mockNFC) => { + const writer = new NFCWriter(); + await writer.push({ records: [{ recordType: "w3.org:xyz", data: test_buffer_data }] }); + const message = createMessage([createRecord('w3.org:xyz', 'application/octet-stream', + test_buffer_data)]); + assertNDEFMessagesEqual(message, mockNFC.pushedMessage()); +}, "Test that mediaType should be set to 'application/octet-stream' if \ +NDEFRecordInit.record's recordType is external type and NDEFRecordInit.record's \ +mediaType is undefined."); +</script> diff --git a/tests/wpt/web-platform-tests/web-nfc/resources/support-iframe.html b/tests/wpt/web-platform-tests/web-nfc/resources/support-iframe.html new file mode 100644 index 00000000000..540eab108b1 --- /dev/null +++ b/tests/wpt/web-platform-tests/web-nfc/resources/support-iframe.html @@ -0,0 +1,3 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<input type="text" id="foo" value="click me!"></input>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py b/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py index 2b08be1f983..a069a5a5df3 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/element_click/bubbling.py @@ -72,7 +72,7 @@ def test_spin_event_loop(session): for (var level = 0; level < elements.length; level++) { elements[level].addEventListener("click", function(clickEvent) { var target = clickEvent.currentTarget; - setTimeout(function() { window.delayedClicks.push(target); }, 100); + setTimeout(function() { window.delayedClicks.push(target); }, 0); }); } </script> diff --git a/tests/wpt/web-platform-tests/webgpu/cts.html b/tests/wpt/web-platform-tests/webgpu/cts.html index 661060fcd7b..b60faec9623 100644 --- a/tests/wpt/web-platform-tests/webgpu/cts.html +++ b/tests/wpt/web-platform-tests/webgpu/cts.html @@ -1,11 +1,30 @@ +<!-- AUTO-GENERATED - DO NOT EDIT. See gen_wpt_cts_html.ts. --> <!-- This test suite is built from the TypeScript sources at: https://github.com/gpuweb/cts + + NOTE: + The WPT version of this file is generated with *one test spec per variant*. + If your harness needs more fine-grained suppressions, you'll need to + generate your own variants list from your suppression list. For example, if + test file cts:a/b: has 3 tests and you need to suppress a single case, you + might break it out into the following variants: + + - cts:a/b:test1~ + - cts:a/b:test2={"x":1} + - cts:a/b:test2={"x":2} // <- suppress this one + - cts:a/b:test2={"x":3} + - cts:a/b:test3~ + + When run under browser CI, the original cts.html should be skipped, and + this alternate version should be run instead, under a non-exported WPT test + directory (e.g. Chromium's wpt_internal). --> + <!doctype html> <title>WebGPU CTS</title> <meta charset=utf-8> -<link rel="help" href="https://gpuweb.github.io/gpuweb/"> +<link rel=help href='https://gpuweb.github.io/gpuweb/'> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> @@ -18,17 +37,36 @@ </style> <textarea id=results></textarea> -<script type=module src="runtime/wpt.js"></script> +<script type=module src=/webgpu/runtime/wpt.js></script> -<meta name="variant" content="?q=cts:buffers/create_mapped:"> -<meta name="variant" content="?q=cts:buffers/map:"> -<meta name="variant" content="?q=cts:buffers/map_detach:"> -<meta name="variant" content="?q=cts:buffers/map_oom:"> -<meta name="variant" content="?q=cts:canvas/context_creation:"> -<meta name="variant" content="?q=cts:command_buffer/basic:"> -<meta name="variant" content="?q=cts:command_buffer/compute/basic:"> -<meta name="variant" content="?q=cts:command_buffer/copies:"> -<meta name="variant" content="?q=cts:command_buffer/render/basic:"> -<meta name="variant" content="?q=cts:command_buffer/render/rendering:"> -<meta name="variant" content="?q=cts:examples:"> -<meta name="variant" content="?q=cts:fences:"> +<meta name=variant content='?q=cts:buffers/create_mapped:'> +<meta name=variant content='?q=cts:buffers/map:'> +<meta name=variant content='?q=cts:buffers/map_detach:'> +<meta name=variant content='?q=cts:buffers/map_oom:'> +<meta name=variant content='?q=cts:canvas/context_creation:'> +<meta name=variant content='?q=cts:command_buffer/basic:'> +<meta name=variant content='?q=cts:command_buffer/compute/basic:'> +<meta name=variant content='?q=cts:command_buffer/copies:'> +<meta name=variant content='?q=cts:command_buffer/render/basic:'> +<meta name=variant content='?q=cts:command_buffer/render/rendering:'> +<meta name=variant content='?q=cts:command_buffer/render/storeop:'> +<meta name=variant content='?q=cts:examples:'> +<meta name=variant content='?q=cts:fences:'> +<meta name=variant content='?q=cts:validation/createBindGroup:'> +<meta name=variant content='?q=cts:validation/createBindGroupLayout:'> +<meta name=variant content='?q=cts:validation/createPipelineLayout:'> +<meta name=variant content='?q=cts:validation/createRenderPipeline:'> +<meta name=variant content='?q=cts:validation/createTexture:'> +<meta name=variant content='?q=cts:validation/createView:'> +<meta name=variant content='?q=cts:validation/error_scope:'> +<meta name=variant content='?q=cts:validation/fences:'> +<meta name=variant content='?q=cts:validation/queue_submit:'> +<meta name=variant content='?q=cts:validation/render_pass:'> +<meta name=variant content='?q=cts:validation/render_pass_descriptor:'> +<meta name=variant content='?q=cts:validation/setBindGroup:'> +<meta name=variant content='?q=cts:validation/setBlendColor:'> +<meta name=variant content='?q=cts:validation/setScissorRect:'> +<meta name=variant content='?q=cts:validation/setStencilReference:'> +<meta name=variant content='?q=cts:validation/setVertexBuffer:'> +<meta name=variant content='?q=cts:validation/setViewport:'> +<meta name=variant content='?q=cts:validation/vertex_input:'> diff --git a/tests/wpt/web-platform-tests/webgpu/framework/fixture.js b/tests/wpt/web-platform-tests/webgpu/framework/fixture.js index d77ede708f0..6e13385eef4 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/fixture.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/fixture.js @@ -23,11 +23,15 @@ export class Fixture { async init() {} + debug(msg) { + this.rec.debug(msg); + } + log(msg) { this.rec.log(msg); } - finalize() { + async finalize() { if (this.numOutstandingAsyncExpectations !== 0) { throw new Error('there were outstanding asynchronous expectations (e.g. shouldReject) at the end of the test'); } @@ -48,8 +52,9 @@ export class Fixture { async asyncExpectation(fn) { this.numOutstandingAsyncExpectations++; - await fn(); + const ret = await fn(); this.numOutstandingAsyncExpectations--; + return ret; } expectErrorValue(expectedName, ex, m) { diff --git a/tests/wpt/web-platform-tests/webgpu/framework/logger.js b/tests/wpt/web-platform-tests/webgpu/framework/logger.js index 8aa332c571a..d97be59091a 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/logger.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/logger.js @@ -60,14 +60,17 @@ export class TestCaseRecorder { _defineProperty(this, "logs", []); + _defineProperty(this, "debugging", false); + this.result = result; } - start() { + start(debug = false) { this.startTime = now(); this.logs = []; this.failed = false; this.warned = false; + this.debugging = debug; } finish() { @@ -80,6 +83,15 @@ export class TestCaseRecorder { this.result.timems = Math.ceil((endTime - this.startTime) * 1000) / 1000; this.result.status = this.failed ? 'fail' : this.warned ? 'warn' : 'pass'; this.result.logs = this.logs; + this.debugging = false; + } + + debug(msg) { + if (!this.debugging) { + return; + } + + this.log('DEBUG: ' + msg); } log(msg) { @@ -112,9 +124,7 @@ export class TestCaseRecorder { threw(e) { this.failed = true; - let m = 'EXCEPTION'; - m += ' ' + getStackTrace(e); - this.log(m); + this.log('EXCEPTION: ' + e.name + ': ' + e.message + '\n' + getStackTrace(e)); } } diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js b/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js index 3036e21bd63..e7cc5f78ba5 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_by_group.js @@ -14,10 +14,6 @@ export class FilterByGroup { this.groupPrefix = groupPrefix; } - matches(spec, testcase) { - throw new Error('unimplemented'); - } - async iterate(loader) { const specs = await loader.listing(this.suite); const entries = []; diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js b/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js index 6a998db0de9..7616bee6afe 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/test_filter/filter_one_file.js @@ -52,10 +52,6 @@ export class FilterByTestMatch extends FilterOneFile { return filterTestGroup(spec.g, testcase => testcase.test.startsWith(this.testPrefix)); } - matches(spec, testcase) { - throw new Error('unimplemented'); - } - } export class FilterByParamsMatch extends FilterOneFile { constructor(specId, test, params) { @@ -73,10 +69,6 @@ export class FilterByParamsMatch extends FilterOneFile { return filterTestGroup(spec.g, testcase => testcase.test === this.test && paramsSupersets(testcase.params, this.params)); } - matches(spec, testcase) { - throw new Error('unimplemented'); - } - } export class FilterByParamsExact extends FilterOneFile { constructor(specId, test, params) { @@ -94,9 +86,5 @@ export class FilterByParamsExact extends FilterOneFile { return filterTestGroup(spec.g, testcase => testcase.test === this.test && paramsEquals(testcase.params, this.params)); } - matches(spec, testcase) { - throw new Error('unimplemented'); - } - } //# sourceMappingURL=filter_one_file.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/test_group.js b/tests/wpt/web-platform-tests/webgpu/framework/test_group.js index c9cafb37b67..09697765b8c 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/test_group.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/test_group.js @@ -36,7 +36,7 @@ export class TestGroup { } if (this.seen.has(name)) { - throw new Error('Duplicate test name'); + throw new Error(`Duplicate test name: ${name}`); } this.seen.add(name); @@ -113,15 +113,15 @@ class RunCaseSpecific { this.fn = fn; } - async run() { + async run(debug) { const [rec, res] = this.recorder.record(this.id.test, this.id.params); - rec.start(); + rec.start(debug); try { const inst = new this.fixture(rec, this.id.params || {}); await inst.init(); await this.fn(inst); - inst.finalize(); + await inst.finalize(); } catch (e) { rec.threw(e); } diff --git a/tests/wpt/web-platform-tests/webgpu/framework/url_query.js b/tests/wpt/web-platform-tests/webgpu/framework/url_query.js index b2651390439..f7c7cbc17fe 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/url_query.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/url_query.js @@ -11,6 +11,8 @@ export function encodeSelectively(s) { ret = ret.replace(/%2F/g, '/'); ret = ret.replace(/%3A/g, ':'); ret = ret.replace(/%3D/g, '='); + ret = ret.replace(/%5B/g, '['); + ret = ret.replace(/%5D/g, ']'); ret = ret.replace(/%7B/g, '{'); ret = ret.replace(/%7D/g, '}'); return ret; diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/async_mutex.js b/tests/wpt/web-platform-tests/webgpu/framework/util/async_mutex.js new file mode 100644 index 00000000000..cb900605bcf --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/framework/util/async_mutex.js @@ -0,0 +1,32 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +export class AsyncMutex { + constructor() { + _defineProperty(this, "newestQueueItem", void 0); + } + + // Run an async function with a lock on this mutex. + // Waits until the mutex is available, locks it, runs the function, then releases it. + async with(fn) { + const p = (async () => { + // If the mutex is locked, wait for the last thing in the queue before running. + // (Everything in the queue runs in order, so this is after everything currently enqueued.) + if (this.newestQueueItem) { + await this.newestQueueItem; + } + + return fn(); + })(); // Push the newly-created Promise onto the queue by replacing the old "newest" item. + + + this.newestQueueItem = p; // And return so the caller can wait on the result. + + return p; + } + +} +//# sourceMappingURL=async_mutex.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/index.js b/tests/wpt/web-platform-tests/webgpu/framework/util/index.js index 8d0fe0e5b48..32aea98dea7 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/util/index.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/util/index.js @@ -2,12 +2,20 @@ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts **/ +import { timeout } from './timeout.js'; export * from './stack.js'; // performance.now() is available in all browsers, but not in scope by default in Node. const perf = typeof performance !== 'undefined' ? performance : require('perf_hooks').performance; export function now() { return perf.now(); } +export function rejectOnTimeout(ms, msg) { + return new Promise((resolve, reject) => { + timeout(() => { + reject(new Error(msg)); + }, ms); + }); +} export function objectEquals(x, y) { if (typeof x !== 'object' || typeof y !== 'object') return x === y; if (x === null || y === null) return x === y; @@ -24,4 +32,7 @@ export function objectEquals(x, y) { const p = Object.keys(x); return Object.keys(y).every(i => p.indexOf(i) !== -1) && p.every(i => objectEquals(x1[i], y1[i])); } +export function range(n, fn) { + return [...new Array(n)].map((_, i) => fn(i)); +} //# sourceMappingURL=index.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/util/timeout.js b/tests/wpt/web-platform-tests/webgpu/framework/util/timeout.js new file mode 100644 index 00000000000..e565a518efc --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/framework/util/timeout.js @@ -0,0 +1,6 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const timeout = typeof step_timeout !== 'undefined' ? step_timeout : setTimeout; +//# sourceMappingURL=timeout.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/framework/version.js b/tests/wpt/web-platform-tests/webgpu/framework/version.js index 9be025609f3..0bfbfad4f39 100644 --- a/tests/wpt/web-platform-tests/webgpu/framework/version.js +++ b/tests/wpt/web-platform-tests/webgpu/framework/version.js @@ -1,3 +1,3 @@ // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. -export const version = 'f690ac56a3291801e817433f43877132bb531d5f'; +export const version = 'afbbce5a6a4e9093d01ed454fdc7f257f29d2977'; diff --git a/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js b/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js index d11499f1e8c..ec4ab012392 100644 --- a/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js +++ b/tests/wpt/web-platform-tests/webgpu/runtime/wpt.js @@ -5,11 +5,13 @@ import { TestLoader } from '../framework/loader.js'; import { Logger } from '../framework/logger.js'; import { makeQueryString } from '../framework/url_query.js'; +import { AsyncMutex } from '../framework/util/async_mutex.js'; (async () => { const loader = new TestLoader(); const files = await loader.loadTestsFromQuery(window.location.search); const log = new Logger(); + const mutex = new AsyncMutex(); const running = []; for (const f of files) { @@ -17,20 +19,22 @@ import { makeQueryString } from '../framework/url_query.js'; continue; } - const [rec] = log.record(f.id); // TODO: don't run all tests all at once + const [rec] = log.record(f.id); for (const t of f.spec.g.iterate(rec)) { - const run = t.run(); - running.push(run); // Note: apparently, async_tests must ALL be added within the same task. - - async_test(async function () { - const r = await run; - this.step(() => { - if (r.status === 'fail') { - throw (r.logs || []).join('\n'); - } + // Note: apparently, async_tests must ALL be added within the same task. + async_test(function () { + const p = mutex.with(async () => { + const r = await t.run(); + this.step(() => { + if (r.status === 'fail') { + throw (r.logs || []).join('\n'); + } + }); + this.done(); }); - this.done(); + running.push(p); + return p; }, makeQueryString(f.id, t.id)); } } diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js index 137e428bd9d..c4333c794d2 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/basic.spec.js @@ -9,7 +9,7 @@ import { TestGroup } from '../../../framework/index.js'; import { GPUTest } from '../gpu_test.js'; export const g = new TestGroup(GPUTest); g.test('empty', async t => { - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); const cmd = encoder.finish(); t.device.getQueue().submit([cmd]); // TODO: test that submit() succeeded. }); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js index 56754d5f39e..a001cbc0d82 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/compute/basic.spec.js @@ -78,7 +78,7 @@ g.test('memcpy', async t => { }, layout: pl }); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); const pass = encoder.beginComputePass(); pass.setPipeline(pipeline); pass.setBindGroup(0, bg); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js index 9bf78db8454..0055a58d115 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/copies.spec.js @@ -20,7 +20,7 @@ g.test('b2b', async t => { size: 4, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST }); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); encoder.copyBufferToBuffer(src, 0, dst, 0, 4); t.device.getQueue().submit([encoder.finish()]); await t.expectContents(dst, data); @@ -46,7 +46,7 @@ g.test('b2t2b', async t => { format: 'rgba8uint', usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST }); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); encoder.copyBufferToTexture({ buffer: src, rowPitch: 256, @@ -107,7 +107,7 @@ g.test('b2t2t2b', async t => { }; const mid1 = t.device.createTexture(midDesc); const mid2 = t.device.createTexture(midDesc); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); encoder.copyBufferToTexture({ buffer: src, rowPitch: 256, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js index 83bb026d963..8f4d8c879da 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/basic.spec.js @@ -23,7 +23,7 @@ g.test('clear', async t => { usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT }); const colorAttachmentView = colorAttachment.createView(); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); const pass = encoder.beginRenderPass({ colorAttachments: [{ attachment: colorAttachmentView, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js index c8a7d7f5738..c065ed23be4 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/rendering.spec.js @@ -78,7 +78,7 @@ g.test('fullscreen quad', async t => { vertexBuffers: [] } }); - const encoder = t.device.createCommandEncoder({}); + const encoder = t.device.createCommandEncoder(); const pass = encoder.beginRenderPass({ colorAttachments: [{ attachment: colorAttachmentView, diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js new file mode 100644 index 00000000000..da58ad2d8a5 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/command_buffer/render/storeop.spec.js @@ -0,0 +1,113 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +renderPass store op test that drawn quad is either stored or cleared based on storeop`; +import { TestGroup } from '../../../../framework/index.js'; +import { GPUTest } from '../../gpu_test.js'; +export const g = new TestGroup(GPUTest); +g.test('storeOp controls whether 1x1 drawn quad is stored', async t => { + const renderTexture = t.device.createTexture({ + size: { + width: 1, + height: 1, + depth: 1 + }, + format: 'r8unorm', + usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT + }); // create render pipeline + + const vertexModule = t.device.createShaderModule({ + code: + /* GLSL( + * 'vertex', + * `#version 450 + * const vec2 pos[3] = vec2[3]( + * vec2( 1.0f, -1.0f), + * vec2( 1.0f, 1.0f), + * vec2(-1.0f, 1.0f) + * ); + * + * void main() { + * gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0); + * }` + * ) + */ + new Uint32Array([119734787, 66304, 524295, 39, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 458767, 0, 4, 1852399981, 0, 13, 26, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 393221, 26, 1449094247, 1702130277, 1684949368, 30821, 327685, 29, 1701080681, 1818386808, 101, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 262215, 26, 11, 42, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262167, 16, 6, 2, 262187, 8, 17, 3, 262172, 18, 16, 17, 262187, 6, 19, 1065353216, 262187, 6, 20, 3212836864, 327724, 16, 21, 19, 20, 327724, 16, 22, 19, 19, 327724, 16, 23, 20, 19, 393260, 18, 24, 21, 22, 23, 262176, 25, 1, 14, 262203, 25, 26, 1, 262176, 28, 7, 18, 262176, 30, 7, 16, 262187, 6, 33, 0, 262176, 37, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 262203, 28, 29, 7, 262205, 14, 27, 26, 196670, 29, 24, 327745, 30, 31, 29, 27, 262205, 16, 32, 31, 327761, 6, 34, 32, 0, 327761, 6, 35, 32, 1, 458832, 7, 36, 34, 35, 33, 19, 327745, 37, 38, 13, 15, 196670, 38, 36, 65789, 65592]) + }); + const fragmentModule = t.device.createShaderModule({ + code: + /* GLSL( + * 'fragment', + * `#version 450 + * layout(location = 0) out vec4 fragColor; + * void main() { + * fragColor = vec4(1.0, 0.0, 0.0, 1.0); + * }` + * ) + */ + new Uint32Array([119734787, 66304, 524295, 13, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 4, 4, 1852399981, 0, 9, 196624, 4, 7, 196611, 2, 450, 262149, 4, 1852399981, 0, 327685, 9, 1734439526, 1869377347, 114, 262215, 9, 30, 0, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262176, 8, 3, 7, 262203, 8, 9, 3, 262187, 6, 10, 1065353216, 262187, 6, 11, 0, 458796, 7, 12, 10, 11, 11, 10, 327734, 2, 4, 0, 3, 131320, 5, 196670, 9, 12, 65789, 65592]) + }); + const renderPipeline = t.device.createRenderPipeline({ + vertexStage: { + module: vertexModule, + entryPoint: 'main' + }, + fragmentStage: { + module: fragmentModule, + entryPoint: 'main' + }, + layout: t.device.createPipelineLayout({ + bindGroupLayouts: [] + }), + primitiveTopology: 'triangle-list', + colorStates: [{ + format: 'r8unorm' + }] + }); // encode pass and submit + + const encoder = t.device.createCommandEncoder(); + const pass = encoder.beginRenderPass({ + colorAttachments: [{ + attachment: renderTexture.createView(), + storeOp: t.params.storeOp, + loadValue: { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0 + } + }] + }); + pass.setPipeline(renderPipeline); + pass.draw(3, 1, 0, 0); + pass.endPass(); + const dstBuffer = t.device.createBuffer({ + size: 4, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC + }); + encoder.copyTextureToBuffer({ + texture: renderTexture + }, { + buffer: dstBuffer, + rowPitch: 256, + imageHeight: 1 + }, { + width: 1, + height: 1, + depth: 1 + }); + t.device.getQueue().submit([encoder.finish()]); // expect the buffer to be clear + + const expectedContent = new Uint32Array([t.params.expected]); + await t.expectContents(dstBuffer, expectedContent); +}).params([{ + storeOp: 'store', + expected: 255 +}, // +{ + storeOp: 'clear', + expected: 0 +}]); +//# sourceMappingURL=storeop.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js index ad86e73b191..8a992a6239d 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/examples.spec.js @@ -44,12 +44,13 @@ g.test('basic/params', t => { x: 2, y: 4, result: 6 -}, // (blank comment to enforce newlines on autoformat) +}, // { x: -10, y: 18, result: 8 -}]); +}]); // (note blank comment above to enforce newlines on autoformat) + g.test('gpu/async', async t => { const fence = t.queue.createFence(); t.queue.signal(fence, 2); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js index d9f8ce57678..ccf513633da 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/fences.spec.js @@ -34,13 +34,20 @@ g.test('wait/equal to signaled', async t => { t.queue.signal(fence, 2); await fence.onCompletion(2); t.expect(fence.getCompletedValue() === 2); -}); // Test it is illegal to wait on a value greater than the signaled value. +}); // All promises resolve when signal is called once. -g.test('wait/greater than signaled', async t => { +g.test('wait/signaled once', async t => { const fence = t.queue.createFence(); - t.queue.signal(fence, 2); - const promise = fence.onCompletion(3); - await t.shouldReject('OperationError', promise); + t.queue.signal(fence, 20); + const promises = []; + + for (let i = 0; i <= 20; ++i) { + promises.push(fence.onCompletion(i).then(() => { + t.expect(fence.getCompletedValue() >= i); + })); + } + + await Promise.all(promises); }); // Promise resolves when signal is called multiple times. g.test('wait/signaled multiple times', async t => { @@ -64,19 +71,6 @@ g.test('wait/already completed', async t => { t.expect(fence.getCompletedValue() === 2); await fence.onCompletion(2); t.expect(fence.getCompletedValue() === 2); -}); // Test it is illegal to wait on a fence without signaling the value. - -g.test('wait/without signal', async t => { - const fence = t.queue.createFence(); - const promise = fence.onCompletion(2); - await t.shouldReject('OperationError', promise); -}); // Test it is illegal to wait on a fence before it is signaled. - -g.test('wait/before signaled', async t => { - const fence = t.queue.createFence(); - const promise = fence.onCompletion(2); - t.queue.signal(fence, 2); - await t.shouldReject('OperationError', promise); }); // Test many calls to signal and wait on fence values one at a time. g.test('wait/many/serially', async t => { diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js index a67ce4ab0ba..e437ee09449 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/gpu_test.js @@ -5,7 +5,8 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { getGPU } from '../../framework/gpu/implementation.js'; -import { Fixture } from '../../framework/index.js'; // TODO: Should this gain some functionality currently only in UnitTest? +import { Fixture } from '../../framework/index.js'; +let glslangInstance; // TODO: Should this gain some functionality currently only in UnitTest? export class GPUTest extends Fixture { constructor(...args) { @@ -20,8 +21,51 @@ export class GPUTest extends Fixture { super.init(); const gpu = getGPU(); const adapter = await gpu.requestAdapter(); - this.device = await adapter.requestDevice({}); + this.device = await adapter.requestDevice(); this.queue = this.device.getQueue(); + this.device.pushErrorScope('out-of-memory'); + this.device.pushErrorScope('validation'); + } + + async finalize() { + super.finalize(); + const gpuValidationError = await this.device.popErrorScope(); + + if (gpuValidationError !== null) { + if (!(gpuValidationError instanceof GPUValidationError)) throw new Error(); + this.fail(`Unexpected validation error occurred: ${gpuValidationError.message}`); + } + + const gpuOutOfMemoryError = await this.device.popErrorScope(); + + if (gpuOutOfMemoryError !== null) { + if (!(gpuOutOfMemoryError instanceof GPUOutOfMemoryError)) throw new Error(); + this.fail('Unexpected out-of-memory error occurred'); + } + } + + async initGLSL() { + if (!glslangInstance) { + const glslangPath = '../../glslang.js'; + const glslangModule = (await import(glslangPath)).default; + await new Promise(resolve => { + glslangModule().then(glslang => { + glslangInstance = glslang; + resolve(); + }); + }); + } + } + + makeShaderModule(stage, source) { + if (!glslangInstance) { + throw new Error('GLSL is not instantiated. Run `await t.initGLSL()` first'); + } + + const code = glslangInstance.compileGLSL(source, stage, false); + return this.device.createShaderModule({ + code + }); } // TODO: add an expectContents for textures, which logs data: uris on failure @@ -33,7 +77,7 @@ export class GPUTest extends Fixture { size: expected.buffer.byteLength, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST }); - const c = this.device.createCommandEncoder({}); + const c = this.device.createCommandEncoder(); c.copyBufferToBuffer(src, 0, dst, 0, size); this.queue.submit([c.finish()]); const actual = new Uint8Array((await dst.mapReadAsync())); diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js index cb2a592697f..b38ea11df28 100644 --- a/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/index.js @@ -1,4 +1,4 @@ -// AUTO-GENERATED - DO NOT EDIT. See src/tools/gen.ts. +// AUTO-GENERATED - DO NOT EDIT. See src/tools/gen_listings.ts. export const listing = [ { @@ -42,11 +42,87 @@ export const listing = [ "description": "" }, { + "path": "command_buffer/render/storeop", + "description": "renderPass store op test that drawn quad is either stored or cleared based on storeop" + }, + { "path": "examples", "description": "Examples of writing CTS tests with various features." }, { "path": "fences", "description": "" + }, + { + "path": "validation/createBindGroup", + "description": "createBindGroup validation tests." + }, + { + "path": "validation/createBindGroupLayout", + "description": "createBindGroupLayout validation tests." + }, + { + "path": "validation/createPipelineLayout", + "description": "createPipelineLayout validation tests." + }, + { + "path": "validation/createRenderPipeline", + "description": "createRenderPipeline validation tests." + }, + { + "path": "validation/createTexture", + "description": "createTexture validation tests." + }, + { + "path": "validation/createView", + "description": "createView validation tests." + }, + { + "path": "validation/error_scope", + "description": "error scope validation tests." + }, + { + "path": "validation/fences", + "description": "fences validation tests." + }, + { + "path": "validation/queue_submit", + "description": "queue submit validation tests." + }, + { + "path": "validation/render_pass", + "description": "render pass validation tests." + }, + { + "path": "validation/render_pass_descriptor", + "description": "render pass descriptor validation tests." + }, + { + "path": "validation/setBindGroup", + "description": "setBindGroup validation tests." + }, + { + "path": "validation/setBlendColor", + "description": "setBlendColor validation tests." + }, + { + "path": "validation/setScissorRect", + "description": "setScissorRect validation tests." + }, + { + "path": "validation/setStencilReference", + "description": "setStencilReference validation tests." + }, + { + "path": "validation/setVertexBuffer", + "description": "setVertexBuffer validation tests." + }, + { + "path": "validation/setViewport", + "description": "setViewport validation tests." + }, + { + "path": "validation/vertex_input", + "description": "vertexInput validation tests." } ]; diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroup.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroup.spec.js new file mode 100644 index 00000000000..24d29d0e61e --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroup.spec.js @@ -0,0 +1,477 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createBindGroup validation tests. +`; +import { TestGroup, pcombine, poptions } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +function clone(descriptor) { + return JSON.parse(JSON.stringify(descriptor)); +} + +class F extends ValidationTest { + getStorageBuffer() { + return this.device.createBuffer({ + size: 1024, + usage: GPUBufferUsage.STORAGE + }); + } + + getUniformBuffer() { + return this.device.createBuffer({ + size: 1024, + usage: GPUBufferUsage.UNIFORM + }); + } + + getSampler() { + return this.device.createSampler(); + } + + getSampledTexture() { + return this.device.createTexture({ + size: { + width: 16, + height: 16, + depth: 1 + }, + format: 'rgba8unorm', + usage: GPUTextureUsage.SAMPLED + }); + } + + getStorageTexture() { + return this.device.createTexture({ + size: { + width: 16, + height: 16, + depth: 1 + }, + format: 'rgba8unorm', + usage: GPUTextureUsage.STORAGE + }); + } + +} + +export const g = new TestGroup(F); +g.test('binding count mismatch', async t => { + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }] + }); + const goodDescriptor = { + bindings: [{ + binding: 0, + resource: { + buffer: t.getStorageBuffer() + } + }], + layout: bindGroupLayout + }; // Control case + + t.device.createBindGroup(goodDescriptor); // Another binding is not expected. + + const badDescriptor = { + bindings: [{ + binding: 0, + resource: { + buffer: t.getStorageBuffer() + } + }, // Another binding is added. + { + binding: 1, + resource: { + buffer: t.getStorageBuffer() + } + }], + layout: bindGroupLayout + }; + await t.expectValidationError(() => { + t.device.createBindGroup(badDescriptor); + }); +}); +g.test('binding must be present in layout', async t => { + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }] + }); + const goodDescriptor = { + bindings: [{ + binding: 0, + resource: { + buffer: t.getStorageBuffer() + } + }], + layout: bindGroupLayout + }; // Control case + + t.device.createBindGroup(goodDescriptor); // Binding index 0 must be present. + + const badDescriptor = { + bindings: [{ + binding: 1, + // binding index becomes 1. + resource: { + buffer: t.getStorageBuffer() + } + }], + layout: bindGroupLayout + }; + await t.expectValidationError(() => { + t.device.createBindGroup(badDescriptor); + }); +}); +g.test('buffer binding must contain exactly one buffer of its type', async t => { + const { + bindingType, + resourceType + } = t.params; + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: bindingType + }] + }); + let resource; + + if (resourceType === 'error') { + resource = { + buffer: await t.getErrorBuffer() + }; + } else if (resourceType === 'uniform-buffer') { + resource = { + buffer: t.getUniformBuffer() + }; + } else if (resourceType === 'storage-buffer') { + resource = { + buffer: t.getStorageBuffer() + }; + } else if (resourceType === 'sampler') { + resource = t.getSampler(); + } else if (resourceType === 'sampled-texture') { + resource = t.getSampledTexture().createView(); + } else if (resourceType === 'storage-texture') { + resource = t.getStorageTexture().createView(); + } else throw new Error(); + + let shouldError = bindingType !== resourceType; + + if (bindingType === 'readonly-storage-buffer' && resourceType === 'storage-buffer') { + shouldError = false; + } + + await t.expectValidationError(() => { + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource + }], + layout: bindGroupLayout + }); + }, shouldError); +}).params(pcombine([poptions('bindingType', ['uniform-buffer', 'storage-buffer', 'readonly-storage-buffer', 'sampler', 'sampled-texture', 'storage-texture']), poptions('resourceType', ['error', 'uniform-buffer', 'storage-buffer', 'sampler', 'sampled-texture', 'storage-texture'])])); +g.test('texture binding must have correct usage', async t => { + const { + type + } = t.params; + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type + }] + }); + let usage; + + if (type === 'sampled-texture') { + usage = GPUTextureUsage.SAMPLED; + } else if (type === 'storage-texture') { + usage = GPUTextureUsage.STORAGE; + } else { + throw new Error('Unexpected binding type'); + } + + const goodDescriptor = { + size: { + width: 16, + height: 16, + depth: 1 + }, + format: 'r8unorm', + usage + }; // Control case + + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(goodDescriptor).createView() + }], + layout: bindGroupLayout + }); + + function* mismatchedTextureUsages() { + yield GPUTextureUsage.COPY_SRC; + yield GPUTextureUsage.COPY_DST; + + if (type !== 'sampled-texture') { + yield GPUTextureUsage.SAMPLED; + } + + if (type !== 'storage-texture') { + yield GPUTextureUsage.STORAGE; + } + + yield GPUTextureUsage.OUTPUT_ATTACHMENT; + } // Mismatched texture binding usages are not valid. + + + for (const mismatchedTextureUsage of mismatchedTextureUsages()) { + const badDescriptor = clone(goodDescriptor); + badDescriptor.usage = mismatchedTextureUsage; + await t.expectValidationError(() => { + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(badDescriptor).createView() + }], + layout: bindGroupLayout + }); + }); + } +}).params(poptions('type', ['sampled-texture', 'storage-texture'])); +g.test('texture must have correct component type', async t => { + const { + textureComponentType + } = t.params; + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type: 'sampled-texture', + textureComponentType + }] + }); // TODO: Test more texture component types. + + let format; + + if (textureComponentType === 'float') { + format = 'r8unorm'; + } else if (textureComponentType === 'sint') { + format = 'r8sint'; + } else if (textureComponentType === 'uint') { + format = 'r8uint'; + } else { + throw new Error('Unexpected texture component type'); + } + + const goodDescriptor = { + size: { + width: 16, + height: 16, + depth: 1 + }, + format, + usage: GPUTextureUsage.SAMPLED + }; // Control case + + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(goodDescriptor).createView() + }], + layout: bindGroupLayout + }); + + function* mismatchedTextureFormats() { + if (textureComponentType !== 'float') { + yield 'r8unorm'; + } + + if (textureComponentType !== 'sint') { + yield 'r8sint'; + } + + if (textureComponentType !== 'uint') { + yield 'r8uint'; + } + } // Mismatched texture binding formats are not valid. + + + for (const mismatchedTextureFormat of mismatchedTextureFormats()) { + const badDescriptor = clone(goodDescriptor); + badDescriptor.format = mismatchedTextureFormat; + await t.expectValidationError(() => { + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(badDescriptor).createView() + }], + layout: bindGroupLayout + }); + }); + } +}).params(poptions('textureComponentType', ['float', 'sint', 'uint'])); // TODO: Write test for all dimensions. + +g.test('texture must have correct dimension', async t => { + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type: 'sampled-texture', + textureDimension: '2d' + }] + }); + const goodDescriptor = { + size: { + width: 16, + height: 16, + depth: 1 + }, + arrayLayerCount: 1, + format: 'rgba8unorm', + usage: GPUTextureUsage.SAMPLED + }; // Control case + + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(goodDescriptor).createView() + }], + layout: bindGroupLayout + }); // Mismatched texture binding formats are not valid. + + const badDescriptor = clone(goodDescriptor); + badDescriptor.arrayLayerCount = 2; + await t.expectValidationError(() => { + t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: t.device.createTexture(badDescriptor).createView() + }], + layout: bindGroupLayout + }); + }); +}); +g.test('buffer offset and size for bind groups match', async t => { + const { + offset, + size, + success + } = t.params; + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }] + }); + const buffer = t.device.createBuffer({ + size: 1024, + usage: GPUBufferUsage.STORAGE + }); + const descriptor = { + bindings: [{ + binding: 0, + resource: { + buffer, + offset, + size + } + }], + layout: bindGroupLayout + }; + + if (success) { + // Control case + t.device.createBindGroup(descriptor); + } else { + // Buffer offset and/or size don't match in bind groups. + await t.expectValidationError(() => { + t.device.createBindGroup(descriptor); + }); + } +}).params([{ + offset: 0, + size: 512, + success: true +}, // offset 0 is valid +{ + offset: 256, + size: 256, + success: true +}, // offset 256 (aligned) is valid +// unaligned buffer offset is invalid +{ + offset: 1, + size: 256, + success: false +}, { + offset: 1, + size: undefined, + success: false +}, { + offset: 128, + size: 256, + success: false +}, { + offset: 255, + size: 256, + success: false +}, { + offset: 0, + size: 256, + success: true +}, // touching the start of the buffer works +{ + offset: 256 * 3, + size: 256, + success: true +}, // touching the end of the buffer works +{ + offset: 1024, + size: 0, + success: true +}, // touching the end of the buffer works +{ + offset: 0, + size: 1024, + success: true +}, // touching the full buffer works +{ + offset: 0, + size: undefined, + success: true +}, // touching the full buffer works +{ + offset: 256 * 5, + size: 0, + success: false +}, // offset is OOB +{ + offset: 0, + size: 256 * 5, + success: false +}, // size is OOB +{ + offset: 1024, + size: 1, + success: false +}, // offset+size is OOB +{ + offset: 256, + size: -256, + success: false +} // offset+size overflows to be 0 +]); +//# sourceMappingURL=createBindGroup.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroupLayout.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroupLayout.spec.js new file mode 100644 index 00000000000..8e3bfc22572 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createBindGroupLayout.spec.js @@ -0,0 +1,145 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createBindGroupLayout validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +function clone(descriptor) { + return JSON.parse(JSON.stringify(descriptor)); +} + +export const g = new TestGroup(ValidationTest); +g.test('some binding index was specified more than once', async t => { + const goodDescriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }, { + binding: 1, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }] + }; // Control case + + t.device.createBindGroupLayout(goodDescriptor); + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[1].binding = 0; // Binding index 0 can't be specified twice. + + await t.expectValidationError(() => { + t.device.createBindGroupLayout(badDescriptor); + }); +}); +g.test('negative binding index', async t => { + const goodDescriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type: 'storage-buffer' + }] + }; // Control case + + t.device.createBindGroupLayout(goodDescriptor); // Negative binding index can't be specified. + + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[0].binding = -1; + await t.expectValidationError(() => { + t.device.createBindGroupLayout(badDescriptor); + }); +}); +g.test('Visibility of bindings can be 0', async t => { + const descriptor = { + bindings: [{ + binding: 0, + visibility: 0, + type: 'storage-buffer' + }] + }; + t.device.createBindGroupLayout(descriptor); +}); +g.test('number of dynamic buffers exceeds the maximum value', async t => { + const { + type, + maxDynamicBufferCount + } = t.params; + const maxDynamicBufferBindings = []; + + for (let i = 0; i < maxDynamicBufferCount; i++) { + maxDynamicBufferBindings.push({ + binding: i, + visibility: GPUShaderStage.COMPUTE, + type, + hasDynamicOffset: true + }); + } + + const goodDescriptor = { + bindings: [...maxDynamicBufferBindings, { + binding: maxDynamicBufferBindings.length, + visibility: GPUShaderStage.COMPUTE, + type, + hasDynamicOffset: false + }] + }; // Control case + + t.device.createBindGroupLayout(goodDescriptor); // Dynamic buffers exceed maximum in a bind group layout. + + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[maxDynamicBufferCount].hasDynamicOffset = true; + await t.expectValidationError(() => { + t.device.createBindGroupLayout(badDescriptor); + }); +}).params([{ + type: 'storage-buffer', + maxDynamicBufferCount: 4 +}, { + type: 'uniform-buffer', + maxDynamicBufferCount: 8 +}]); +g.test('dynamic set to true is allowed only for buffers', async t => { + const { + type, + success + } = t.params; + const descriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type, + hasDynamicOffset: true + }] + }; + + if (success) { + // Control case + t.device.createBindGroupLayout(descriptor); + } else { + // Dynamic set to true is not allowed in some cases. + await t.expectValidationError(() => { + t.device.createBindGroupLayout(descriptor); + }); + } +}).params([{ + type: 'uniform-buffer', + success: true +}, { + type: 'storage-buffer', + success: true +}, { + type: 'readonly-storage-buffer', + success: true +}, { + type: 'sampler', + success: false +}, { + type: 'sampled-texture', + success: false +}, { + type: 'storage-texture', + success: false +}]); +//# sourceMappingURL=createBindGroupLayout.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createPipelineLayout.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createPipelineLayout.spec.js new file mode 100644 index 00000000000..dc759750a98 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createPipelineLayout.spec.js @@ -0,0 +1,90 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createPipelineLayout validation tests. +`; +import { TestGroup, poptions } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +function clone(descriptor) { + return JSON.parse(JSON.stringify(descriptor)); +} + +export const g = new TestGroup(ValidationTest); +g.test('number of dynamic buffers exceeds the maximum value', async t => { + const { + type, + maxDynamicBufferCount + } = t.params; + const maxDynamicBufferBindings = []; + + for (let i = 0; i < maxDynamicBufferCount; i++) { + maxDynamicBufferBindings.push({ + binding: i, + visibility: GPUShaderStage.COMPUTE, + type, + hasDynamicOffset: true + }); + } + + const maxDynamicBufferBindGroupLayout = t.device.createBindGroupLayout({ + bindings: maxDynamicBufferBindings + }); + const goodDescriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type, + hasDynamicOffset: false + }] + }; + const goodPipelineLayoutDescriptor = { + bindGroupLayouts: [maxDynamicBufferBindGroupLayout, t.device.createBindGroupLayout(goodDescriptor)] + }; // Control case + + t.device.createPipelineLayout(goodPipelineLayoutDescriptor); // Check dynamic buffers exceed maximum in pipeline layout. + + const badDescriptor = clone(goodDescriptor); + badDescriptor.bindings[0].hasDynamicOffset = true; + const badPipelineLayoutDescriptor = { + bindGroupLayouts: [maxDynamicBufferBindGroupLayout, t.device.createBindGroupLayout(badDescriptor)] + }; + await t.expectValidationError(() => { + t.device.createPipelineLayout(badPipelineLayoutDescriptor); + }); +}).params([{ + type: 'storage-buffer', + maxDynamicBufferCount: 4 +}, { + type: 'uniform-buffer', + maxDynamicBufferCount: 8 +}]); +g.test('number of bind group layouts exceeds the maximum value', async t => { + const { + type + } = t.params; + const bindGroupLayoutDescriptor = { + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE, + type + }] + }; // 4 is the maximum number of bind group layouts. + + const maxBindGroupLayouts = [1, 2, 3, 4].map(() => t.device.createBindGroupLayout(bindGroupLayoutDescriptor)); + const goodPipelineLayoutDescriptor = { + bindGroupLayouts: maxBindGroupLayouts + }; // Control case + + t.device.createPipelineLayout(goodPipelineLayoutDescriptor); // Check bind group layouts exceed maximum in pipeline layout. + + const badPipelineLayoutDescriptor = { + bindGroupLayouts: [...maxBindGroupLayouts, t.device.createBindGroupLayout(bindGroupLayoutDescriptor)] + }; + await t.expectValidationError(() => { + t.device.createPipelineLayout(badPipelineLayoutDescriptor); + }); +}).params(poptions('type', ['storage-buffer', 'uniform-buffer'])); +//# sourceMappingURL=createPipelineLayout.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js new file mode 100644 index 00000000000..7cbe93dd9c9 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createRenderPipeline.spec.js @@ -0,0 +1,379 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createRenderPipeline validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + async init() { + await Promise.all([super.init(), this.initGLSL()]); + } + + getDescriptor(options = {}) { + const defaultColorStates = [{ + format: 'rgba8unorm' + }]; + const { + primitiveTopology = 'triangle-list', + colorStates = defaultColorStates, + sampleCount = 1, + depthStencilState + } = options; + const format = colorStates.length ? colorStates[0].format : 'rgba8unorm'; + return { + vertexStage: this.getVertexStage(), + fragmentStage: this.getFragmentStage(format), + layout: this.getPipelineLayout(), + primitiveTopology, + colorStates, + sampleCount, + depthStencilState + }; + } + + getVertexStage() { + return { + module: this.device.createShaderModule({ + code: + /* GLSL( + * 'vertex', + * `#version 450 + * void main() { + * gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + * } + * ` + * ) + */ + new Uint32Array([119734787, 66304, 524295, 21, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 0, 4, 1852399981, 0, 13, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262187, 6, 16, 0, 262187, 6, 17, 1065353216, 458796, 7, 18, 16, 16, 16, 17, 262176, 19, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 327745, 19, 20, 13, 15, 196670, 20, 18, 65789, 65592]) + }), + entryPoint: 'main' + }; + } + + getFragmentStage(format) { + let fragColorType; + + if (format.endsWith('sint')) { + fragColorType = 'ivec4'; + } else if (format.endsWith('uint')) { + fragColorType = 'uvec4'; + } else { + fragColorType = 'vec4'; + } + + const code = ` + #version 450 + layout(location = 0) out ${fragColorType} fragColor; + void main() { + fragColor = ${fragColorType}(0.0, 1.0, 0.0, 1.0); + } + `; + return { + module: this.makeShaderModule('fragment', code), + entryPoint: 'main' + }; + } + + getPipelineLayout() { + return this.device.createPipelineLayout({ + bindGroupLayouts: [] + }); + } + + createTexture(params) { + const { + format, + sampleCount + } = params; + return this.device.createTexture({ + size: { + width: 4, + height: 4, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT, + format, + sampleCount + }); + } + +} + +export const g = new TestGroup(F); +g.test('basic use of createRenderPipeline', t => { + const descriptor = t.getDescriptor(); + t.device.createRenderPipeline(descriptor); +}); +g.test('at least one color state is required', async t => { + const goodDescriptor = t.getDescriptor({ + colorStates: [{ + format: 'rgba8unorm' + }] + }); // Control case + + t.device.createRenderPipeline(goodDescriptor); // Fail because lack of color states + + const badDescriptor = t.getDescriptor({ + colorStates: [] + }); + await t.expectValidationError(() => { + t.device.createRenderPipeline(badDescriptor); + }); +}); +g.test('color formats must be renderable', async t => { + const { + format, + success + } = t.params; + const descriptor = t.getDescriptor({ + colorStates: [{ + format + }] + }); + + if (success) { + // Succeeds when format is renderable + t.device.createRenderPipeline(descriptor); + } else { + // Fails because when format is non-renderable + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}).params([// 8-bit formats +{ + format: 'r8unorm', + success: true +}, { + format: 'r8snorm', + success: false +}, { + format: 'r8uint', + success: true +}, { + format: 'r8sint', + success: true +}, // 16-bit formats +{ + format: 'r16uint', + success: true +}, { + format: 'r16sint', + success: true +}, { + format: 'r16float', + success: true +}, { + format: 'rg8unorm', + success: true +}, { + format: 'rg8snorm', + success: false +}, { + format: 'rg8uint', + success: true +}, { + format: 'rg8sint', + success: true +}, // 32-bit formats +{ + format: 'r32uint', + success: true +}, { + format: 'r32sint', + success: true +}, { + format: 'r32float', + success: true +}, { + format: 'rg16uint', + success: true +}, { + format: 'rg16sint', + success: true +}, { + format: 'rg16float', + success: true +}, { + format: 'rgba8unorm', + success: true +}, { + format: 'rgba8unorm-srgb', + success: true +}, { + format: 'rgba8snorm', + success: false +}, { + format: 'rgba8uint', + success: true +}, { + format: 'rgba8sint', + success: true +}, { + format: 'bgra8unorm', + success: true +}, { + format: 'bgra8unorm-srgb', + success: true +}, // Packed 32-bit formats +{ + format: 'rgb10a2unorm', + success: true +}, { + format: 'rg11b10float', + success: false +}, // 64-bit formats +{ + format: 'rg32uint', + success: true +}, { + format: 'rg32sint', + success: true +}, { + format: 'rg32float', + success: true +}, { + format: 'rgba16uint', + success: true +}, { + format: 'rgba16sint', + success: true +}, { + format: 'rgba16float', + success: true +}, // 128-bit formats +{ + format: 'rgba32uint', + success: true +}, { + format: 'rgba32sint', + success: true +}, { + format: 'rgba32float', + success: true +}]); +g.test('sample count must be valid', async t => { + const { + sampleCount, + success + } = t.params; + const descriptor = t.getDescriptor({ + sampleCount + }); + + if (success) { + // Succeeds when sample count is valid + t.device.createRenderPipeline(descriptor); + } else { + // Fails when sample count is not 4 or 1 + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}).params([{ + sampleCount: 0, + success: false +}, { + sampleCount: 1, + success: true +}, { + sampleCount: 2, + success: false +}, { + sampleCount: 3, + success: false +}, { + sampleCount: 4, + success: true +}, { + sampleCount: 8, + success: false +}, { + sampleCount: 16, + success: false +}]); +g.test('sample count must be equal to the one of every attachment in the render pass', async t => { + const { + attachmentSamples, + pipelineSamples, + success + } = t.params; + const colorTexture = t.createTexture({ + format: 'rgba8unorm', + sampleCount: attachmentSamples + }); + const depthStencilTexture = t.createTexture({ + format: 'depth24plus-stencil8', + sampleCount: attachmentSamples + }); + const renderPassDescriptorWithoutDepthStencil = { + colorAttachments: [{ + attachment: colorTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }; + const renderPassDescriptorWithDepthStencilOnly = { + colorAttachments: [], + depthStencilAttachment: { + attachment: depthStencilTexture.createView(), + depthLoadValue: 1.0, + depthStoreOp: 'store', + stencilLoadValue: 0, + stencilStoreOp: 'store' + } + }; + const pipelineWithoutDepthStencil = t.device.createRenderPipeline(t.getDescriptor({ + sampleCount: pipelineSamples + })); + const pipelineWithDepthStencilOnly = t.device.createRenderPipeline(t.getDescriptor({ + colorStates: [], + depthStencilState: { + format: 'depth24plus-stencil8' + }, + sampleCount: pipelineSamples + })); + + for (const { + renderPassDescriptor, + pipeline + } of [{ + renderPassDescriptor: renderPassDescriptorWithoutDepthStencil, + pipeline: pipelineWithoutDepthStencil + }, { + renderPassDescriptor: renderPassDescriptorWithDepthStencilOnly, + pipeline: pipelineWithDepthStencilOnly + }]) { + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor); + renderPass.setPipeline(pipeline); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }, !success); + } +}).params([{ + attachmentSamples: 4, + pipelineSamples: 4, + success: true +}, // It is allowed to use multisampled render pass and multisampled render pipeline. +{ + attachmentSamples: 4, + pipelineSamples: 1, + success: false +}, // It is not allowed to use multisampled render pass and non-multisampled render pipeline. +{ + attachmentSamples: 1, + pipelineSamples: 4, + success: false +} // It is not allowed to use non-multisampled render pass and multisampled render pipeline. +]); +//# sourceMappingURL=createRenderPipeline.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createTexture.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createTexture.spec.js new file mode 100644 index 00000000000..c99204b9667 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createTexture.spec.js @@ -0,0 +1,336 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createTexture validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + getDescriptor(options = {}) { + const { + width = 32, + height = 32, + arrayLayerCount = 1, + mipLevelCount = 1, + sampleCount = 1, + format = 'rgba8unorm' + } = options; + return { + size: { + width, + height, + depth: 1 + }, + arrayLayerCount, + mipLevelCount, + sampleCount, + dimension: '2d', + format, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.SAMPLED + }; + } + +} + +export const g = new TestGroup(F); +g.test('validation of sampleCount', async t => { + const { + sampleCount, + mipLevelCount, + arrayLayerCount, + success + } = t.params; + const descriptor = t.getDescriptor({ + sampleCount, + mipLevelCount, + arrayLayerCount + }); + await t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !success); +}).params([{ + sampleCount: 0, + success: false +}, // sampleCount of 0 is not allowed +{ + sampleCount: 1, + success: true +}, // sampleCount of 1 is allowed +{ + sampleCount: 2, + success: false +}, // sampleCount of 2 is not allowed +{ + sampleCount: 3, + success: false +}, // sampleCount of 3 is not allowed +{ + sampleCount: 4, + success: true +}, // sampleCount of 4 is allowed +{ + sampleCount: 8, + success: false +}, // sampleCount of 8 is not allowed +{ + sampleCount: 16, + success: false +}, // sampleCount of 16 is not allowed +{ + sampleCount: 4, + mipLevelCount: 2, + success: false +}, // it is an error to create a multisampled texture with mipLevelCount > 1 +{ + sampleCount: 4, + arrayLayerCount: 2, + success: true +} // multisampled 2D array texture is supported +]); +g.test('validation of mipLevelCount', async t => { + const { + width, + height, + mipLevelCount, + success + } = t.params; + const descriptor = t.getDescriptor({ + width, + height, + mipLevelCount + }); + await t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !success); +}).params([{ + width: 32, + height: 32, + mipLevelCount: 1, + success: true +}, // mipLevelCount of 1 is allowed +{ + width: 32, + height: 32, + mipLevelCount: 0, + success: false +}, // mipLevelCount of 0 is not allowed +{ + width: 32, + height: 32, + mipLevelCount: 6, + success: true +}, // full mip chains are allowed (Mip level sizes: 32, 16, 8, 4, 2, 1) +{ + width: 31, + height: 32, + mipLevelCount: 7, + success: false +}, // too big mip chains on width are disallowed (Mip level width: 31, 15, 7, 3, 1, 1) +{ + width: 32, + height: 31, + mipLevelCount: 7, + success: false +}, // too big mip chains on height are disallowed (Mip level width: 31, 15, 7, 3, 1, 1) +{ + width: 32, + height: 32, + mipLevelCount: 100, + success: false +}, // undefined shift check if miplevel is bigger than the integer bit width +{ + width: 32, + height: 8, + mipLevelCount: 6, + success: true +} // non square mip map halves the resolution until a 1x1 dimension. (Mip maps: 32 * 8, 16 * 4, 8 * 2, 4 * 1, 2 * 1, 1 * 1) +]); +g.test('it is valid to destroy a texture', t => { + const descriptor = t.getDescriptor(); + const texture = t.device.createTexture(descriptor); + texture.destroy(); +}); +g.test('it is valid to destroy a destroyed texture', t => { + const descriptor = t.getDescriptor(); + const texture = t.device.createTexture(descriptor); + texture.destroy(); + texture.destroy(); +}); +g.test('it is invalid to submit a destroyed texture before and after encode', async t => { + const { + destroyBeforeEncode, + destroyAfterEncode, + success + } = t.params; + const descriptor = t.getDescriptor(); + const texture = t.device.createTexture(descriptor); + const textureView = texture.createView(); + + if (destroyBeforeEncode) { + texture.destroy(); + } + + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: textureView, + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + renderPass.endPass(); + const commandBuffer = commandEncoder.finish(); + + if (destroyAfterEncode) { + texture.destroy(); + } + + await t.expectValidationError(() => { + t.queue.submit([commandBuffer]); + }, !success); +}).params([{ + destroyBeforeEncode: false, + destroyAfterEncode: false, + success: true +}, { + destroyBeforeEncode: true, + destroyAfterEncode: false, + success: false +}, { + destroyBeforeEncode: false, + destroyAfterEncode: true, + success: false +}]); +g.test('it is invalid to have an output attachment texture with non renderable format', async t => { + const { + format, + success + } = t.params; + const descriptor = t.getDescriptor({ + width: 1, + height: 1, + format + }); + await t.expectValidationError(() => { + t.device.createTexture(descriptor); + }, !success); +}).params([// 8-bit formats +{ + format: 'r8unorm', + success: true +}, { + format: 'r8snorm', + success: false +}, { + format: 'r8uint', + success: true +}, { + format: 'r8sint', + success: true +}, // 16-bit formats +{ + format: 'r16uint', + success: true +}, { + format: 'r16sint', + success: true +}, { + format: 'r16float', + success: true +}, { + format: 'rg8unorm', + success: true +}, { + format: 'rg8snorm', + success: false +}, { + format: 'rg8uint', + success: true +}, { + format: 'rg8sint', + success: true +}, // 32-bit formats +{ + format: 'r32uint', + success: true +}, { + format: 'r32sint', + success: true +}, { + format: 'r32float', + success: true +}, { + format: 'rg16uint', + success: true +}, { + format: 'rg16sint', + success: true +}, { + format: 'rg16float', + success: true +}, { + format: 'rgba8unorm', + success: true +}, { + format: 'rgba8unorm-srgb', + success: true +}, { + format: 'rgba8snorm', + success: false +}, { + format: 'rgba8uint', + success: true +}, { + format: 'rgba8sint', + success: true +}, { + format: 'bgra8unorm', + success: true +}, { + format: 'bgra8unorm-srgb', + success: true +}, // Packed 32-bit formats +{ + format: 'rgb10a2unorm', + success: true +}, { + format: 'rg11b10float', + success: false +}, // 64-bit formats +{ + format: 'rg32uint', + success: true +}, { + format: 'rg32sint', + success: true +}, { + format: 'rg32float', + success: true +}, { + format: 'rgba16uint', + success: true +}, { + format: 'rgba16sint', + success: true +}, { + format: 'rgba16float', + success: true +}, // 128-bit formats +{ + format: 'rgba32uint', + success: true +}, { + format: 'rgba32sint', + success: true +}, { + format: 'rgba32float', + success: true +}]); // TODO: Add tests for compressed texture formats +//# sourceMappingURL=createTexture.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createView.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createView.spec.js new file mode 100644 index 00000000000..2330c6ecdd9 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/createView.spec.js @@ -0,0 +1,417 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +createView validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +const ARRAY_LAYER_COUNT_2D = 6; +const MIP_LEVEL_COUNT = 6; +const FORMAT = 'rgba8unorm'; + +class F extends ValidationTest { + createTexture(options = {}) { + const { + width = 32, + height = 32, + arrayLayerCount = 1, + mipLevelCount = MIP_LEVEL_COUNT, + sampleCount = 1 + } = options; + return this.device.createTexture({ + size: { + width, + height, + depth: 1 + }, + arrayLayerCount, + mipLevelCount, + sampleCount, + dimension: '2d', + format: FORMAT, + usage: GPUTextureUsage.SAMPLED + }); + } + + getDescriptor(options = {}) { + const { + format = FORMAT, + dimension = '2d', + baseMipLevel = 0, + mipLevelCount = MIP_LEVEL_COUNT, + baseArrayLayer = 0, + arrayLayerCount = 1 + } = options; + return { + format, + dimension, + baseMipLevel, + mipLevelCount, + baseArrayLayer, + arrayLayerCount + }; + } + +} + +export const g = new TestGroup(F); +g.test('creating texture view on a 2D non array texture', async t => { + const { + dimension = '2d', + arrayLayerCount, + mipLevelCount, + baseMipLevel, + success + } = t.params; + const texture = t.createTexture({ + arrayLayerCount: 1 + }); + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + mipLevelCount, + baseMipLevel + }); + await t.expectValidationError(() => { + texture.createView(descriptor); + }, !success); +}).params([{ + success: true +}, // default view works +{ + arrayLayerCount: 1, + success: true +}, // it is OK to create a 2D texture view on a 2D texture +{ + arrayLayerCount: 2, + success: false +}, // it is an error to view a layer past the end of the texture +{ + dimension: '2d-array', + arrayLayerCount: 1, + success: true +}, // it is OK to create a 1-layer 2D array texture view on a 2D texture +// mip level is in range +{ + mipLevelCount: 1, + baseMipLevel: MIP_LEVEL_COUNT - 1, + success: true +}, { + mipLevelCount: 2, + baseMipLevel: MIP_LEVEL_COUNT - 2, + success: true +}, // baseMipLevel == k && mipLevelCount == 0 means to use levels k..end +{ + mipLevelCount: 0, + baseMipLevel: 0, + success: true +}, { + mipLevelCount: 0, + baseMipLevel: 1, + success: true +}, { + mipLevelCount: 0, + baseMipLevel: MIP_LEVEL_COUNT - 1, + success: true +}, { + mipLevelCount: 0, + baseMipLevel: MIP_LEVEL_COUNT, + success: false +}, // it is an error to make the mip level out of range +{ + mipLevelCount: MIP_LEVEL_COUNT + 1, + baseMipLevel: 0, + success: false +}, { + mipLevelCount: MIP_LEVEL_COUNT, + baseMipLevel: 1, + success: false +}, { + mipLevelCount: 2, + baseMipLevel: MIP_LEVEL_COUNT - 1, + success: false +}, { + mipLevelCount: 1, + baseMipLevel: MIP_LEVEL_COUNT, + success: false +}]); +g.test('creating texture view on a 2D array texture', async t => { + const { + dimension = '2d-array', + arrayLayerCount, + baseArrayLayer, + success + } = t.params; + const texture = t.createTexture({ + arrayLayerCount: ARRAY_LAYER_COUNT_2D + }); + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount, + baseArrayLayer + }); + await t.expectValidationError(() => { + texture.createView(descriptor); + }, !success); +}).params([{ + success: true +}, // default view works +{ + dimension: '2d', + arrayLayerCount: 1, + success: true +}, // it is OK to create a 2D texture view on a 2D array texture +{ + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + success: true +}, // it is OK to create a 2D array texture view on a 2D array texture +// baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end. +{ + arrayLayerCount: 0, + baseArrayLayer: 0, + success: true +}, { + arrayLayerCount: 0, + baseArrayLayer: 1, + success: true +}, { + arrayLayerCount: 0, + baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, + success: true +}, { + arrayLayerCount: 0, + baseArrayLayer: ARRAY_LAYER_COUNT_2D, + success: false +}, // It is an error for the array layer range of the view to exceed that of the texture +{ + arrayLayerCount: ARRAY_LAYER_COUNT_2D + 1, + baseArrayLayer: 0, + success: false +}, { + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + baseArrayLayer: 1, + success: false +}, { + arrayLayerCount: 2, + baseArrayLayer: ARRAY_LAYER_COUNT_2D - 1, + success: false +}, { + arrayLayerCount: 1, + baseArrayLayer: ARRAY_LAYER_COUNT_2D, + success: false +}]); +g.test('Using defaults validates the same as setting values for more than 1 array layer', async t => { + const { + format, + dimension, + arrayLayerCount, + mipLevelCount, + success + } = t.params; + const texture = t.createTexture({ + arrayLayerCount: ARRAY_LAYER_COUNT_2D + }); + const descriptor = { + format, + dimension, + arrayLayerCount, + mipLevelCount + }; + await t.expectValidationError(() => { + texture.createView(descriptor); + }, !success); +}).params([{ + success: true +}, { + format: 'rgba8unorm', + success: true +}, { + format: 'r8unorm', + success: false +}, { + dimension: '2d-array', + success: true +}, { + dimension: '2d', + success: false +}, { + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + success: false +}, // setting array layers to non-0 means the dimensionality will default to 2D so by itself it causes an error. +{ + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + dimension: '2d-array', + success: true +}, { + arrayLayerCount: ARRAY_LAYER_COUNT_2D, + dimension: '2d-array', + mipLevelCount: MIP_LEVEL_COUNT, + success: true +}]); +g.test('Using defaults validates the same as setting values for only 1 array layer', async t => { + const { + format, + dimension, + arrayLayerCount, + mipLevelCount, + success + } = t.params; + const texture = t.createTexture({ + arrayLayerCount: 1 + }); + const descriptor = { + format, + dimension, + arrayLayerCount, + mipLevelCount + }; + await t.expectValidationError(() => { + texture.createView(descriptor); + }, !success); +}).params([{ + success: true +}, { + format: 'rgba8unorm', + success: true +}, { + format: 'r8unorm', + success: false +}, { + dimension: '2d-array', + success: true +}, { + dimension: '2d', + success: true +}, { + arrayLayerCount: 0, + success: true +}, { + arrayLayerCount: 1, + success: true +}, { + arrayLayerCount: 2, + success: false +}, { + mipLevelCount: MIP_LEVEL_COUNT, + success: true +}, { + mipLevelCount: 1, + success: true +}]); +g.test('creating cube map texture view', async t => { + const { + dimension = '2d-array', + arrayLayerCount, + success + } = t.params; + const texture = t.createTexture({ + arrayLayerCount: 16 + }); + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount + }); + await t.expectValidationError(() => { + texture.createView(descriptor); + }, !success); +}).params([{ + dimension: 'cube', + arrayLayerCount: 6, + success: true +}, // it is OK to create a cube map texture view with arrayLayerCount == 6 +// it is an error to create a cube map texture view with arrayLayerCount != 6 +{ + dimension: 'cube', + arrayLayerCount: 3, + success: false +}, { + dimension: 'cube', + arrayLayerCount: 7, + success: false +}, { + dimension: 'cube', + arrayLayerCount: 12, + success: false +}, { + dimension: 'cube', + success: false +}, { + dimension: 'cube-array', + arrayLayerCount: 12, + success: true +}, // it is OK to create a cube map array texture view with arrayLayerCount % 6 == 0 +// it is an error to create a cube map array texture view with arrayLayerCount % 6 != 0 +{ + dimension: 'cube-array', + arrayLayerCount: 11, + success: false +}, { + dimension: 'cube-array', + arrayLayerCount: 13, + success: false +}]); +g.test('creating cube map texture view with a non square texture', async t => { + const { + dimension, + arrayLayerCount + } = t.params; + const nonSquareTexture = t.createTexture({ + arrayLayerCount: 18, + width: 32, + height: 16, + mipLevelCount: 5 + }); + const descriptor = t.getDescriptor({ + dimension, + arrayLayerCount + }); + await t.expectValidationError(() => { + nonSquareTexture.createView(descriptor); + }); +}).params([{ + dimension: 'cube', + arrayLayerCount: 6 +}, // it is an error to create a cube map texture view with width != height. +{ + dimension: 'cube-array', + arrayLayerCount: 12 +} // it is an error to create a cube map array texture view with width != height. +]); // TODO: add more tests when rules are fully implemented. + +g.test('test the format compatibility rules when creating a texture view', async t => { + const texture = t.createTexture({ + arrayLayerCount: 1 + }); + const descriptor = t.getDescriptor({ + format: 'depth24plus-stencil8' + }); // it is invalid to create a view in depth-stencil format on a RGBA texture + + await t.expectValidationError(() => { + texture.createView(descriptor); + }); +}); +g.test('it is invalid to use a texture view created from a destroyed texture', async t => { + const texture = t.createTexture({ + arrayLayerCount: 1 + }); + texture.destroy(); + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: texture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }); +}); // TODO: Add tests for TextureAspect +//# sourceMappingURL=createView.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/error_scope.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/error_scope.spec.js new file mode 100644 index 00000000000..2232db9b54e --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/error_scope.spec.js @@ -0,0 +1,141 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +export const description = ` +error scope validation tests. +`; +import { getGPU } from '../../../framework/gpu/implementation.js'; +import { Fixture, TestGroup, rejectOnTimeout } from '../../../framework/index.js'; + +class F extends Fixture { + constructor(...args) { + super(...args); + + _defineProperty(this, "device", undefined); + } + + async init() { + super.init(); + const gpu = getGPU(); + const adapter = await gpu.requestAdapter(); + this.device = await adapter.requestDevice(); + } + + createErrorBuffer() { + this.device.createBuffer({ + size: 1024, + usage: 0xffff // Invalid GPUBufferUsage + + }); // TODO: Remove when chrome does it automatically. + + this.device.getQueue().submit([]); + } + + async expectUncapturedError(fn) { + return this.asyncExpectation(() => { + // TODO: Make arbitrary timeout value a test runner variable + const TIMEOUT_IN_MS = 1000; + const promise = new Promise(resolve => { + const eventListener = event => { + this.debug(`Got uncaptured error event with ${event.error}`); + resolve(event); + }; + + this.device.addEventListener('uncapturederror', eventListener, { + once: true + }); + }); + fn(); + return Promise.race([promise, rejectOnTimeout(TIMEOUT_IN_MS, 'Timeout occurred waiting for uncaptured error')]); + }); + } + +} + +export const g = new TestGroup(F); +g.test('simple case where the error scope catches an error', async t => { + t.device.pushErrorScope('validation'); + t.createErrorBuffer(); + const error = await t.device.popErrorScope(); + t.expect(error instanceof GPUValidationError); +}); +g.test('errors bubble to the parent scope if not handled by the current scope', async t => { + t.device.pushErrorScope('validation'); + t.device.pushErrorScope('out-of-memory'); + t.createErrorBuffer(); + { + const error = await t.device.popErrorScope(); + t.expect(error === null); + } + { + const error = await t.device.popErrorScope(); + t.expect(error instanceof GPUValidationError); + } +}); +g.test('if an error scope matches an error it does not bubble to the parent scope', async t => { + t.device.pushErrorScope('validation'); + t.device.pushErrorScope('validation'); + t.createErrorBuffer(); + { + const error = await t.device.popErrorScope(); + t.expect(error instanceof GPUValidationError); + } + { + const error = await t.device.popErrorScope(); + t.expect(error === null); + } +}); +g.test('if no error scope handles an error it fires an uncapturederror event', async t => { + t.device.pushErrorScope('out-of-memory'); + const uncapturedErrorEvent = await t.expectUncapturedError(() => { + t.createErrorBuffer(); + }); + t.expect(uncapturedErrorEvent.error instanceof GPUValidationError); + const error = await t.device.popErrorScope(); + t.expect(error === null); +}); +g.test('push/popping sibling error scopes must be balanced', async t => { + { + const promise = t.device.popErrorScope(); + await t.shouldReject('OperationError', promise); + } + const promises = []; + + for (let i = 0; i < 1000; i++) { + t.device.pushErrorScope('validation'); + promises.push(t.device.popErrorScope()); + } + + const errors = await Promise.all(promises); + t.expect(errors.every(e => e === null)); + { + const promise = t.device.popErrorScope(); + await t.shouldReject('OperationError', promise); + } +}); +g.test('push/popping nested error scopes must be balanced', async t => { + { + const promise = t.device.popErrorScope(); + await t.shouldReject('OperationError', promise); + } + const promises = []; + + for (let i = 0; i < 1000; i++) { + t.device.pushErrorScope('validation'); + } + + for (let i = 0; i < 1000; i++) { + promises.push(t.device.popErrorScope()); + } + + const errors = await Promise.all(promises); + t.expect(errors.every(e => e === null)); + { + const promise = t.device.popErrorScope(); + await t.shouldReject('OperationError', promise); + } +}); +//# sourceMappingURL=error_scope.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/fences.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/fences.spec.js new file mode 100644 index 00000000000..4aca3d7773a --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/fences.spec.js @@ -0,0 +1,70 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +fences validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +export const g = new TestGroup(ValidationTest); // TODO: Remove if https://github.com/gpuweb/gpuweb/issues/377 is decided + +g.test('wait on a fence without signaling the value is invalid', async t => { + const fence = t.queue.createFence(); + await t.expectValidationError(() => { + t.shouldReject('OperationError', fence.onCompletion(2)); + }); +}); // TODO: Remove if https://github.com/gpuweb/gpuweb/issues/377 is decided + +g.test('wait on a fence with a value greater than signaled value is invalid', async t => { + const fence = t.queue.createFence(); + t.queue.signal(fence, 2); + await t.expectValidationError(() => { + t.shouldReject('OperationError', fence.onCompletion(3)); + }); +}); +g.test('signal a value lower than signaled value is invalid', async t => { + const fence = t.queue.createFence({ + initialValue: 1 + }); + await t.expectValidationError(() => { + t.queue.signal(fence, 0); + }); +}); +g.test('signal a value equal to signaled value is invalid', async t => { + const fence = t.queue.createFence({ + initialValue: 1 + }); + await t.expectValidationError(() => { + t.queue.signal(fence, 1); + }); +}); +g.test('increasing fence value by more than 1 succeeds', async t => { + const fence = t.queue.createFence(); + t.queue.signal(fence, 2); + await fence.onCompletion(2); + t.queue.signal(fence, 6); + await fence.onCompletion(6); +}); +g.test('signal a fence on a different device than it was created on is invalid', async t => { + const fence = t.queue.createFence(); + const anotherDevice = await t.device.adapter.requestDevice(); + const anotherQueue = anotherDevice.getQueue(); + await t.expectValidationError(() => { + anotherQueue.signal(fence, 2); + }); +}); +g.test('signal a fence on a different device does not update fence signaled value', async t => { + const fence = t.queue.createFence({ + initialValue: 1 + }); + const anotherDevice = await t.device.adapter.requestDevice(); + const anotherQueue = anotherDevice.getQueue(); + await t.expectValidationError(() => { + anotherQueue.signal(fence, 2); + }); + t.expect(fence.getCompletedValue() === 1); + t.queue.signal(fence, 2); + await fence.onCompletion(2); +}); +//# sourceMappingURL=fences.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/queue_submit.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/queue_submit.spec.js new file mode 100644 index 00000000000..50d912f4d6f --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/queue_submit.spec.js @@ -0,0 +1,39 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +queue submit validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +export const g = new TestGroup(ValidationTest); +g.test('submitting with a mapped buffer is disallowed', async t => { + const buffer = t.device.createBuffer({ + size: 4, + usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC + }); + const targetBuffer = t.device.createBuffer({ + size: 4, + usage: GPUBufferUsage.COPY_DST + }); + + const getCommandBuffer = () => { + const commandEncoder = t.device.createCommandEncoder(); + commandEncoder.copyBufferToBuffer(buffer, 0, targetBuffer, 0, 4); + return commandEncoder.finish(); + }; // Submitting when the buffer has never been mapped should succeed + + + t.queue.submit([getCommandBuffer()]); // Map the buffer, submitting when the buffer is mapped should fail + + await buffer.mapWriteAsync(); + t.queue.submit([]); + await t.expectValidationError(() => { + t.queue.submit([getCommandBuffer()]); + }); // Unmap the buffer, queue submit should succeed + + buffer.unmap(); + t.queue.submit([getCommandBuffer()]); +}); +//# sourceMappingURL=queue_submit.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js new file mode 100644 index 00000000000..f71a4a2b974 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass.spec.js @@ -0,0 +1,174 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +render pass validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + getUniformBuffer() { + return this.device.createBuffer({ + size: 4 * Float32Array.BYTES_PER_ELEMENT, + usage: GPUBufferUsage.UNIFORM + }); + } + + createRenderPipeline(pipelineLayout) { + const vertexModule = this.device.createShaderModule({ + code: + /* GLSL( + * 'vertex', + * `#version 450 + * layout (set = 0, binding = 0) uniform vertexUniformBuffer { + * mat2 transform; + * }; + * void main() { + * const vec2 pos[3] = vec2[3](vec2(-1.f, -1.f), vec2(1.f, -1.f), vec2(-1.f, 1.f)); + * gl_Position = vec4(transform * pos[gl_VertexIndex], 0.f, 1.f); + * } + * ` + * ) + */ + new Uint32Array([119734787, 66304, 524295, 47, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 458767, 0, 4, 1852399981, 0, 13, 33, 196611, 2, 450, 262149, 4, 1852399981, 0, 393221, 11, 1348430951, 1700164197, 2019914866, 0, 393222, 11, 0, 1348430951, 1953067887, 7237481, 458758, 11, 1, 1348430951, 1953393007, 1702521171, 0, 458758, 11, 2, 1130327143, 1148217708, 1635021673, 6644590, 458758, 11, 3, 1130327143, 1147956341, 1635021673, 6644590, 196613, 13, 0, 458757, 18, 1953654134, 1851095141, 1919903337, 1718960749, 7497062, 393222, 18, 0, 1851880052, 1919903347, 109, 196613, 20, 0, 393221, 33, 1449094247, 1702130277, 1684949368, 30821, 327685, 36, 1701080681, 1818386808, 101, 327752, 11, 0, 11, 0, 327752, 11, 1, 11, 1, 327752, 11, 2, 11, 3, 327752, 11, 3, 11, 4, 196679, 11, 2, 262216, 18, 0, 5, 327752, 18, 0, 35, 0, 327752, 18, 0, 7, 16, 196679, 18, 2, 262215, 20, 34, 0, 262215, 20, 33, 0, 262215, 33, 11, 42, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 262165, 8, 32, 0, 262187, 8, 9, 1, 262172, 10, 6, 9, 393246, 11, 7, 6, 10, 10, 262176, 12, 3, 11, 262203, 12, 13, 3, 262165, 14, 32, 1, 262187, 14, 15, 0, 262167, 16, 6, 2, 262168, 17, 16, 2, 196638, 18, 17, 262176, 19, 2, 18, 262203, 19, 20, 2, 262176, 21, 2, 17, 262187, 8, 24, 3, 262172, 25, 16, 24, 262187, 6, 26, 3212836864, 327724, 16, 27, 26, 26, 262187, 6, 28, 1065353216, 327724, 16, 29, 28, 26, 327724, 16, 30, 26, 28, 393260, 25, 31, 27, 29, 30, 262176, 32, 1, 14, 262203, 32, 33, 1, 262176, 35, 7, 25, 262176, 37, 7, 16, 262187, 6, 41, 0, 262176, 45, 3, 7, 327734, 2, 4, 0, 3, 131320, 5, 262203, 35, 36, 7, 327745, 21, 22, 20, 15, 262205, 17, 23, 22, 262205, 14, 34, 33, 196670, 36, 31, 327745, 37, 38, 36, 34, 262205, 16, 39, 38, 327825, 16, 40, 23, 39, 327761, 6, 42, 40, 0, 327761, 6, 43, 40, 1, 458832, 7, 44, 42, 43, 41, 28, 327745, 45, 46, 13, 15, 196670, 46, 44, 65789, 65592]) + }); + const fragmentModule = this.device.createShaderModule({ + code: + /* GLSL( + * 'fragment', + * `#version 450 + * layout (set = 1, binding = 0) uniform fragmentUniformBuffer { + * vec4 color; + * }; + * layout(location = 0) out vec4 fragColor; + * void main() { + * } + * ` + * ) + */ + new Uint32Array([119734787, 66304, 524295, 13, 0, 131089, 1, 393227, 1, 1280527431, 1685353262, 808793134, 0, 196622, 0, 1, 393231, 4, 4, 1852399981, 0, 12, 196624, 4, 7, 196611, 2, 450, 262149, 4, 1852399981, 0, 524293, 8, 1734439526, 1953391981, 1718185557, 1114468975, 1701209717, 114, 327686, 8, 0, 1869377379, 114, 196613, 10, 0, 327685, 12, 1734439526, 1869377347, 114, 327752, 8, 0, 35, 0, 196679, 8, 2, 262215, 10, 34, 1, 262215, 10, 33, 0, 262215, 12, 30, 0, 131091, 2, 196641, 3, 2, 196630, 6, 32, 262167, 7, 6, 4, 196638, 8, 7, 262176, 9, 2, 8, 262203, 9, 10, 2, 262176, 11, 3, 7, 262203, 11, 12, 3, 327734, 2, 4, 0, 3, 131320, 5, 65789, 65592]) + }); + const pipeline = this.device.createRenderPipeline({ + vertexStage: { + module: vertexModule, + entryPoint: 'main' + }, + fragmentStage: { + module: fragmentModule, + entryPoint: 'main' + }, + layout: pipelineLayout, + primitiveTopology: 'triangle-list', + colorStates: [{ + format: 'rgba8unorm' + }] + }); + return pipeline; + } + + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: 16, + height: 16, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('it is invalid to draw in a render pass with missing bind groups', async t => { + const { + setBindGroup1, + setBindGroup2, + success + } = t.params; + const uniformBuffer = t.getUniformBuffer(); + const bindGroupLayout1 = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.VERTEX, + type: 'uniform-buffer' + }] + }); + const bindGroup1 = t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: { + buffer: uniformBuffer + } + }], + layout: bindGroupLayout1 + }); + const bindGroupLayout2 = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.FRAGMENT, + type: 'uniform-buffer' + }] + }); + const bindGroup2 = t.device.createBindGroup({ + bindings: [{ + binding: 0, + resource: { + buffer: uniformBuffer + } + }], + layout: bindGroupLayout2 + }); + const pipelineLayout = t.device.createPipelineLayout({ + bindGroupLayouts: [bindGroupLayout1, bindGroupLayout2] + }); + const pipeline = t.createRenderPipeline(pipelineLayout); + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline); + + if (setBindGroup1) { + renderPass.setBindGroup(0, bindGroup1); + } + + if (setBindGroup2) { + renderPass.setBindGroup(1, bindGroup2); + } + + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }, !success); +}).params([{ + setBindGroup1: true, + setBindGroup2: true, + success: true +}, { + setBindGroup1: true, + setBindGroup2: false, + success: false +}, { + setBindGroup1: false, + setBindGroup2: true, + success: false +}, { + setBindGroup1: false, + setBindGroup2: false, + success: false +}]); +//# sourceMappingURL=render_pass.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass_descriptor.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass_descriptor.spec.js new file mode 100644 index 00000000000..5a171879082 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/render_pass_descriptor.spec.js @@ -0,0 +1,560 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +render pass descriptor validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + createTexture(options = {}) { + const { + format = 'rgba8unorm', + width = 16, + height = 16, + arrayLayerCount = 1, + mipLevelCount = 1, + sampleCount = 1, + usage = GPUTextureUsage.OUTPUT_ATTACHMENT + } = options; + return this.device.createTexture({ + size: { + width, + height, + depth: 1 + }, + format, + arrayLayerCount, + mipLevelCount, + sampleCount, + usage + }); + } + + getColorAttachment(texture, textureViewDescriptor) { + const attachment = texture.createView(textureViewDescriptor); + return { + attachment, + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }; + } + + getDepthStencilAttachment(texture, textureViewDescriptor) { + const attachment = texture.createView(textureViewDescriptor); + return { + attachment, + depthLoadValue: 1.0, + depthStoreOp: 'store', + stencilLoadValue: 0, + stencilStoreOp: 'store' + }; + } + + async tryRenderPass(success, descriptor) { + const commandEncoder = this.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass(descriptor); + renderPass.endPass(); + await this.expectValidationError(() => { + commandEncoder.finish(); + }, !success); + } + +} + +export const g = new TestGroup(F); +g.test('a render pass with only one color is ok', t => { + const colorTexture = t.createTexture({ + format: 'rgba8unorm' + }); + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture)] + }; + t.tryRenderPass(true, descriptor); +}); +g.test('a render pass with only one depth attachment is ok', t => { + const depthStencilTexture = t.createTexture({ + format: 'depth24plus-stencil8' + }); + const descriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture) + }; + t.tryRenderPass(true, descriptor); +}); +g.test('OOB color attachment indices are handled', async t => { + const { + colorAttachmentsCount, + success + } = t.params; + const colorAttachments = []; + + for (let i = 0; i < colorAttachmentsCount; i++) { + const colorTexture = t.createTexture(); + colorAttachments.push(t.getColorAttachment(colorTexture)); + } + + await t.tryRenderPass(success, { + colorAttachments + }); +}).params([{ + colorAttachmentsCount: 4, + success: true +}, // Control case +{ + colorAttachmentsCount: 5, + success: false +} // Out of bounds +]); +g.test('attachments must have the same size', async t => { + const colorTexture1x1A = t.createTexture({ + width: 1, + height: 1, + format: 'rgba8unorm' + }); + const colorTexture1x1B = t.createTexture({ + width: 1, + height: 1, + format: 'rgba8unorm' + }); + const colorTexture2x2 = t.createTexture({ + width: 2, + height: 2, + format: 'rgba8unorm' + }); + const depthStencilTexture1x1 = t.createTexture({ + width: 1, + height: 1, + format: 'depth24plus-stencil8' + }); + const depthStencilTexture2x2 = t.createTexture({ + width: 2, + height: 2, + format: 'depth24plus-stencil8' + }); + { + // Control case: all the same size (1x1) + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture1x1A), t.getColorAttachment(colorTexture1x1B)], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture1x1) + }; + t.tryRenderPass(true, descriptor); + } + { + // One of the color attachments has a different size + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture1x1A), t.getColorAttachment(colorTexture2x2)] + }; + await t.tryRenderPass(false, descriptor); + } + { + // The depth stencil attachment has a different size + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture1x1A), t.getColorAttachment(colorTexture1x1B)], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture2x2) + }; + await t.tryRenderPass(false, descriptor); + } +}); +g.test('attachments must match whether they are used for color or depth stencil', async t => { + const colorTexture = t.createTexture({ + format: 'rgba8unorm' + }); + const depthStencilTexture = t.createTexture({ + format: 'depth24plus-stencil8' + }); + { + // Using depth-stencil for color + const descriptor = { + colorAttachments: [t.getColorAttachment(depthStencilTexture)] + }; + await t.tryRenderPass(false, descriptor); + } + { + // Using color for depth-stencil + const descriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment(colorTexture) + }; + await t.tryRenderPass(false, descriptor); + } +}); +g.test('check layer count for color or depth stencil', async t => { + const { + arrayLayerCount, + baseArrayLayer, + success + } = t.params; + const ARRAY_LAYER_COUNT = 10; + const MIP_LEVEL_COUNT = 1; + const COLOR_FORMAT = 'rgba8unorm'; + const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; + const colorTexture = t.createTexture({ + format: COLOR_FORMAT, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT + }); + const depthStencilTexture = t.createTexture({ + format: DEPTH_STENCIL_FORMAT, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT + }); + const baseTextureViewDescriptor = { + dimension: '2d-array', + baseArrayLayer, + arrayLayerCount, + baseMipLevel: 0, + mipLevelCount: MIP_LEVEL_COUNT + }; + { + // Check 2D array texture view for color + const textureViewDescriptor = { ...baseTextureViewDescriptor, + format: COLOR_FORMAT + }; + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)] + }; + await t.tryRenderPass(success, descriptor); + } + { + // Check 2D array texture view for depth stencil + const textureViewDescriptor = { ...baseTextureViewDescriptor, + format: DEPTH_STENCIL_FORMAT + }; + const descriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture, textureViewDescriptor) + }; + await t.tryRenderPass(success, descriptor); + } +}).params([{ + arrayLayerCount: 5, + baseArrayLayer: 0, + success: false +}, // using 2D array texture view with arrayLayerCount > 1 is not allowed +{ + arrayLayerCount: 1, + baseArrayLayer: 0, + success: true +}, // using 2D array texture view that covers the first layer of the texture is OK +{ + arrayLayerCount: 1, + baseArrayLayer: 9, + success: true +} // using 2D array texture view that covers the last layer is OK for depth stencil +]); +g.test('check mip level count for color or depth stencil', async t => { + const { + mipLevelCount, + baseMipLevel, + success + } = t.params; + const ARRAY_LAYER_COUNT = 1; + const MIP_LEVEL_COUNT = 4; + const COLOR_FORMAT = 'rgba8unorm'; + const DEPTH_STENCIL_FORMAT = 'depth24plus-stencil8'; + const colorTexture = t.createTexture({ + format: COLOR_FORMAT, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT + }); + const depthStencilTexture = t.createTexture({ + format: DEPTH_STENCIL_FORMAT, + width: 32, + height: 32, + mipLevelCount: MIP_LEVEL_COUNT, + arrayLayerCount: ARRAY_LAYER_COUNT + }); + const baseTextureViewDescriptor = { + dimension: '2d', + baseArrayLayer: 0, + arrayLayerCount: ARRAY_LAYER_COUNT, + baseMipLevel, + mipLevelCount + }; + { + // Check 2D texture view for color + const textureViewDescriptor = { ...baseTextureViewDescriptor, + format: COLOR_FORMAT + }; + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture, textureViewDescriptor)] + }; + await t.tryRenderPass(success, descriptor); + } + { + // Check 2D texture view for depth stencil + const textureViewDescriptor = { ...baseTextureViewDescriptor, + format: DEPTH_STENCIL_FORMAT + }; + const descriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture, textureViewDescriptor) + }; + await t.tryRenderPass(success, descriptor); + } +}).params([{ + mipLevelCount: 2, + baseMipLevel: 0, + success: false +}, // using 2D texture view with mipLevelCount > 1 is not allowed +{ + mipLevelCount: 1, + baseMipLevel: 0, + success: true +}, // using 2D texture view that covers the first level of the texture is OK +{ + mipLevelCount: 1, + baseMipLevel: 3, + success: true +} // using 2D texture view that covers the last level of the texture is OK +]); +g.test('it is invalid to set resolve target if color attachment is non multisampled', async t => { + const colorTexture = t.createTexture({ + sampleCount: 1 + }); + const resolveTargetTexture = t.createTexture({ + sampleCount: 1 + }); + const descriptor = { + colorAttachments: [{ + attachment: colorTexture.createView(), + resolveTarget: resolveTargetTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('check the use of multisampled textures as color attachments', async t => { + const colorTexture = t.createTexture({ + sampleCount: 1 + }); + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + { + // It is allowed to use a multisampled color attachment without setting resolve target + const descriptor = { + colorAttachments: [t.getColorAttachment(multisampledColorTexture)] + }; + t.tryRenderPass(true, descriptor); + } + { + // It is not allowed to use multiple color attachments with different sample counts + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture), t.getColorAttachment(multisampledColorTexture)] + }; + await t.tryRenderPass(false, descriptor); + } +}); +g.test('it is invalid to use a multisampled resolve target', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const multisampledResolveTargetTexture = t.createTexture({ + sampleCount: 4 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = multisampledResolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('it is invalid to use a resolve target with array layer count greater than 1', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + arrayLayerCount: 2 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('it is invalid to use a resolve target with mipmap level count greater than 1', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + mipLevelCount: 2 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('it is invalid to use a resolve target whose usage is not output attachment', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('it is invalid to use a resolve target in error state', async t => { + const ARRAY_LAYER_COUNT = 1; + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + arrayLayerCount: ARRAY_LAYER_COUNT + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + await t.expectValidationError(() => { + colorAttachment.resolveTarget = resolveTargetTexture.createView({ + dimension: '2d', + format: 'rgba8unorm', + baseArrayLayer: ARRAY_LAYER_COUNT + 1 + }); + }); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('use of multisampled attachment and non multisampled resolve target is allowed', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + sampleCount: 1 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + t.tryRenderPass(true, descriptor); +}); +g.test('use a resolve target in a format different than the attachment is not allowed', async t => { + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + format: 'bgra8unorm' + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTexture.createView(); + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); +}); +g.test('size of the resolve target must be the same as the color attachment', async t => { + const size = 16; + const multisampledColorTexture = t.createTexture({ + width: size, + height: size, + sampleCount: 4 + }); + const resolveTargetTexture = t.createTexture({ + width: size * 2, + height: size * 2, + mipLevelCount: 2 + }); + { + const resolveTargetTextureView = resolveTargetTexture.createView({ + baseMipLevel: 0, + mipLevelCount: 1 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTextureView; + const descriptor = { + colorAttachments: [colorAttachment] + }; + await t.tryRenderPass(false, descriptor); + } + { + const resolveTargetTextureView = resolveTargetTexture.createView({ + baseMipLevel: 1 + }); + const colorAttachment = t.getColorAttachment(multisampledColorTexture); + colorAttachment.resolveTarget = resolveTargetTextureView; + const descriptor = { + colorAttachments: [colorAttachment] + }; + t.tryRenderPass(true, descriptor); + } +}); +g.test('check depth stencil attachment sample counts mismatch', async t => { + const multisampledDepthStencilTexture = t.createTexture({ + sampleCount: 4, + format: 'depth24plus-stencil8' + }); + { + // It is not allowed to use a depth stencil attachment whose sample count is different from the + // one of the color attachment + const depthStencilTexture = t.createTexture({ + sampleCount: 1, + format: 'depth24plus-stencil8' + }); + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const descriptor = { + colorAttachments: [t.getColorAttachment(multisampledColorTexture)], + depthStencilAttachment: t.getDepthStencilAttachment(depthStencilTexture) + }; + await t.tryRenderPass(false, descriptor); + } + { + const colorTexture = t.createTexture({ + sampleCount: 1 + }); + const descriptor = { + colorAttachments: [t.getColorAttachment(colorTexture)], + depthStencilAttachment: t.getDepthStencilAttachment(multisampledDepthStencilTexture) + }; + await t.tryRenderPass(false, descriptor); + } + { + // It is allowed to use a multisampled depth stencil attachment whose sample count is equal to + // the one of the color attachment. + const multisampledColorTexture = t.createTexture({ + sampleCount: 4 + }); + const descriptor = { + colorAttachments: [t.getColorAttachment(multisampledColorTexture)], + depthStencilAttachment: t.getDepthStencilAttachment(multisampledDepthStencilTexture) + }; + t.tryRenderPass(true, descriptor); + } + { + // It is allowed to use a multisampled depth stencil attachment with no color attachment + const descriptor = { + colorAttachments: [], + depthStencilAttachment: t.getDepthStencilAttachment(multisampledDepthStencilTexture) + }; + t.tryRenderPass(true, descriptor); + } +}); +//# sourceMappingURL=render_pass_descriptor.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBindGroup.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBindGroup.spec.js new file mode 100644 index 00000000000..c669ea08d58 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBindGroup.spec.js @@ -0,0 +1,205 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setBindGroup validation tests. +`; +import { TestGroup, pcombine, poptions } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + makeAttachmentTexture() { + return this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: 16, + height: 16, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + } + + testComputePass(bindGroup, dynamicOffsets) { + const encoder = this.device.createCommandEncoder(); + const computePass = encoder.beginComputePass(); + computePass.setBindGroup(0, bindGroup, dynamicOffsets); + computePass.endPass(); + encoder.finish(); + } + + testRenderPass(bindGroup, dynamicOffsets) { + const encoder = this.device.createCommandEncoder(); + const renderPass = encoder.beginRenderPass({ + colorAttachments: [{ + attachment: this.makeAttachmentTexture().createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + renderPass.setBindGroup(0, bindGroup, dynamicOffsets); + renderPass.endPass(); + encoder.finish(); + } + + testRenderBundle(bindGroup, dynamicOffsets) { + const encoder = this.device.createRenderBundleEncoder({ + colorFormats: ['rgba8unorm'] + }); + encoder.setBindGroup(0, bindGroup, dynamicOffsets); + encoder.finish(); + } + +} + +export const g = new TestGroup(F); +g.test('dynamic offsets passed but not expected/compute pass', async t => { + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [] + }); + const bindGroup = t.device.createBindGroup({ + layout: bindGroupLayout, + bindings: [] + }); + const { + type + } = t.params; + const dynamicOffsets = [0]; + await t.expectValidationError(() => { + if (type === 'compute') { + const encoder = t.device.createCommandEncoder(); + const computePass = encoder.beginComputePass(); + computePass.setBindGroup(0, bindGroup, dynamicOffsets); + computePass.endPass(); + encoder.finish(); + } else if (type === 'renderpass') { + const encoder = t.device.createCommandEncoder(); + const renderPass = encoder.beginRenderPass({ + colorAttachments: [{ + attachment: t.makeAttachmentTexture().createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + renderPass.setBindGroup(0, bindGroup, dynamicOffsets); + renderPass.endPass(); + encoder.finish(); + } else if (type === 'renderbundle') { + const encoder = t.device.createRenderBundleEncoder({ + colorFormats: ['rgba8unorm'] + }); + encoder.setBindGroup(0, bindGroup, dynamicOffsets); + encoder.finish(); + } else { + t.fail(); + } + }); +}).params(poptions('type', ['compute', 'renderpass', 'renderbundle'])); +g.test('dynamic offsets match expectations in pass encoder', async t => { + // Dynamic buffer offsets require offset to be divisible by 256 + const MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT = 256; + const BINDING_SIZE = 9; + const bindGroupLayout = t.device.createBindGroupLayout({ + bindings: [{ + binding: 0, + visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + type: 'uniform-buffer', + hasDynamicOffset: true + }, { + binding: 1, + visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + type: 'storage-buffer', + hasDynamicOffset: true + }] + }); + const uniformBuffer = t.device.createBuffer({ + size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, + usage: GPUBufferUsage.UNIFORM + }); + const storageBuffer = t.device.createBuffer({ + size: 2 * MIN_DYNAMIC_BUFFER_OFFSET_ALIGNMENT + 8, + usage: GPUBufferUsage.STORAGE + }); + const bindGroup = t.device.createBindGroup({ + layout: bindGroupLayout, + bindings: [{ + binding: 0, + resource: { + buffer: uniformBuffer, + size: BINDING_SIZE + } + }, { + binding: 1, + resource: { + buffer: storageBuffer, + size: BINDING_SIZE + } + }] + }); + const { + type, + dynamicOffsets, + success + } = t.params; + await t.expectValidationError(() => { + if (type === 'compute') { + t.testComputePass(bindGroup, dynamicOffsets); + } else if (type === 'renderpass') { + t.testRenderPass(bindGroup, dynamicOffsets); + } else if (type === 'renderbundle') { + t.testRenderBundle(bindGroup, dynamicOffsets); + } else { + t.fail(); + } + + t.testComputePass(bindGroup, dynamicOffsets); + }, !success); +}).params(pcombine([poptions('type', ['compute', 'renderpass', 'renderbundle']), [{ + dynamicOffsets: [256, 0], + success: true +}, // Dynamic offsets aligned +{ + dynamicOffsets: [1, 2], + success: false +}, // Dynamic offsets not aligned +// Wrong number of dynamic offsets +{ + dynamicOffsets: [256, 0, 0], + success: false +}, { + dynamicOffsets: [256], + success: false +}, { + dynamicOffsets: [], + success: false +}, // Dynamic uniform buffer out of bounds because of binding size +{ + dynamicOffsets: [512, 0], + success: false +}, { + dynamicOffsets: [1024, 0], + success: false +}, { + dynamicOffsets: [Number.MAX_SAFE_INTEGER, 0], + success: false +}, // Dynamic storage buffer out of bounds because of binding size +{ + dynamicOffsets: [0, 512], + success: false +}, { + dynamicOffsets: [0, 1024], + success: false +}, { + dynamicOffsets: [0, Number.MAX_SAFE_INTEGER], + success: false +}]])); // TODO: test error bind group +//# sourceMappingURL=setBindGroup.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBlendColor.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBlendColor.spec.js new file mode 100644 index 00000000000..a04bcd038ee --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setBlendColor.spec.js @@ -0,0 +1,66 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setBlendColor validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; // TODO: Move beginRenderPass to a Fixture class. + +class F extends ValidationTest { + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: 16, + height: 16, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('basic use of setBlendColor', t => { + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setBlendColor({ + r: 0, + g: 0, + b: 0, + a: 0 + }); + renderPass.endPass(); + commandEncoder.finish(); +}); +g.test('setBlendColor allows any number value', t => { + const values = [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]; + + for (const value of values) { + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setBlendColor({ + r: value, + g: value, + b: value, + a: value + }); + renderPass.endPass(); + commandEncoder.finish(); + } +}); +//# sourceMappingURL=setBlendColor.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setScissorRect.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setScissorRect.spec.js new file mode 100644 index 00000000000..ee1588d2a88 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setScissorRect.spec.js @@ -0,0 +1,91 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setScissorRect validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +const TEXTURE_WIDTH = 16; +const TEXTURE_HEIGHT = 16; // TODO: Move this fixture class to a common file. + +class F extends ValidationTest { + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: TEXTURE_WIDTH, + height: TEXTURE_HEIGHT, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('use of setScissorRect', async t => { + const { + x, + y, + width, + height, + success + } = t.params; + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setScissorRect(x, y, width, height); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }, !success); +}).params([{ + x: 0, + y: 0, + width: 1, + height: 1, + success: true +}, // Basic use +{ + x: 0, + y: 0, + width: 0, + height: 1, + success: false +}, // Width of zero is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 0, + success: false +}, // Height of zero is not allowed +{ + x: 0, + y: 0, + width: 0, + height: 0, + success: false +}, // Both width and height of zero are not allowed +{ + x: 0, + y: 0, + width: TEXTURE_WIDTH + 1, + height: TEXTURE_HEIGHT + 1, + success: true +} // Scissor larger than the framebuffer is allowed +]); +//# sourceMappingURL=setScissorRect.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setStencilReference.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setStencilReference.spec.js new file mode 100644 index 00000000000..3db37a4908e --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setStencilReference.spec.js @@ -0,0 +1,48 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setStencilReference validation tests. +`; +import { TestGroup, poptions } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; // TODO: Move this fixture class to a common file. + +class F extends ValidationTest { + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: 16, + height: 16, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('use of setStencilReference', t => { + const { + reference + } = t.params; + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setStencilReference(reference); + renderPass.endPass(); + commandEncoder.finish(); +}).params(poptions('reference', [0, 0xffffffff])); +//# sourceMappingURL=setStencilReference.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js new file mode 100644 index 00000000000..949dd91932d --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setVertexBuffer.spec.js @@ -0,0 +1,182 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setVertexBuffer validation tests. +`; +import { TestGroup, range } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; + +class F extends ValidationTest { + async init() { + await Promise.all([super.init(), this.initGLSL()]); + } + + getVertexBuffer() { + return this.device.createBuffer({ + size: 256, + usage: GPUBufferUsage.VERTEX + }); + } + + createRenderPipeline(bufferCount) { + const descriptor = { + vertexStage: this.getVertexStage(bufferCount), + fragmentStage: this.getFragmentStage(), + layout: this.getPipelineLayout(), + primitiveTopology: 'triangle-list', + colorStates: [{ + format: 'rgba8unorm' + }], + vertexInput: { + vertexBuffers: [{ + stride: 3 * 4, + attributeSet: range(bufferCount, i => ({ + format: 'float3', + shaderLocation: i + })) + }] + } + }; + return this.device.createRenderPipeline(descriptor); + } + + getVertexStage(bufferCount) { + const code = ` + #version 450 + ${range(bufferCount, i => `\nlayout(location = ${i}) in vec3 a_position${i};`).join('')} + void main() { + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + } + `; + return { + module: this.makeShaderModule('vertex', code), + entryPoint: 'main' + }; + } + + getFragmentStage() { + const code = ` + #version 450 + layout(location = 0) out vec4 fragColor; + void main() { + fragColor = vec4(0.0, 1.0, 0.0, 1.0); + } + `; + return { + module: this.makeShaderModule('fragment', code), + entryPoint: 'main' + }; + } + + getPipelineLayout() { + return this.device.createPipelineLayout({ + bindGroupLayouts: [] + }); + } + + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: 16, + height: 16, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('vertex buffers inherit from previous pipeline', async t => { + const pipeline1 = t.createRenderPipeline(1); + const pipeline2 = t.createRenderPipeline(2); + const vertexBuffer1 = t.getVertexBuffer(); + const vertexBuffer2 = t.getVertexBuffer(); + { + // Check failure when vertex buffer is not set + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline1); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }); + } + { + // Check success when vertex buffer is inherited from previous pipeline + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline2); + renderPass.setVertexBuffer(0, vertexBuffer1); + renderPass.setVertexBuffer(1, vertexBuffer2); + renderPass.draw(3, 1, 0, 0); + renderPass.setPipeline(pipeline1); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + commandEncoder.finish(); + } +}); +g.test('vertex buffers do not inherit between render passes', async t => { + const pipeline1 = t.createRenderPipeline(1); + const pipeline2 = t.createRenderPipeline(2); + const vertexBuffer1 = t.getVertexBuffer(); + const vertexBuffer2 = t.getVertexBuffer(); + { + // Check success when vertex buffer is set for each render pass + const commandEncoder = t.device.createCommandEncoder(); + { + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline2); + renderPass.setVertexBuffer(0, vertexBuffer1); + renderPass.setVertexBuffer(1, vertexBuffer2); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + } + { + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline1); + renderPass.setVertexBuffer(0, vertexBuffer1); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + } + commandEncoder.finish(); + } + { + // Check failure because vertex buffer is not inherited in second subpass + const commandEncoder = t.device.createCommandEncoder(); + { + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline2); + renderPass.setVertexBuffer(0, vertexBuffer1); + renderPass.setVertexBuffer(1, vertexBuffer2); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + } + { + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setPipeline(pipeline1); + renderPass.draw(3, 1, 0, 0); + renderPass.endPass(); + } + await t.expectValidationError(() => { + commandEncoder.finish(); + }); + } +}); +//# sourceMappingURL=setVertexBuffer.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setViewport.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setViewport.spec.js new file mode 100644 index 00000000000..5610930829e --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/setViewport.spec.js @@ -0,0 +1,193 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +setViewport validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +const TEXTURE_WIDTH = 16; +const TEXTURE_HEIGHT = 16; // TODO: Move this fixture class to a common file. + +class F extends ValidationTest { + beginRenderPass(commandEncoder) { + const attachmentTexture = this.device.createTexture({ + format: 'rgba8unorm', + size: { + width: TEXTURE_WIDTH, + height: TEXTURE_HEIGHT, + depth: 1 + }, + usage: GPUTextureUsage.OUTPUT_ATTACHMENT + }); + return commandEncoder.beginRenderPass({ + colorAttachments: [{ + attachment: attachmentTexture.createView(), + loadValue: { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0 + } + }] + }); + } + +} + +export const g = new TestGroup(F); +g.test('use of setViewport', async t => { + const { + x, + y, + width, + height, + minDepth, + maxDepth, + success + } = t.params; + const commandEncoder = t.device.createCommandEncoder(); + const renderPass = t.beginRenderPass(commandEncoder); + renderPass.setViewport(x, y, width, height, minDepth, maxDepth); + renderPass.endPass(); + await t.expectValidationError(() => { + commandEncoder.finish(); + }, !success); +}).params([{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 0, + maxDepth: 1, + success: true +}, // Basic use +{ + x: 0, + y: 0, + width: 0, + height: 1, + minDepth: 0, + maxDepth: 1, + success: false +}, // Width of zero is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 0, + minDepth: 0, + maxDepth: 1, + success: false +}, // Height of zero is not allowed +{ + x: 0, + y: 0, + width: 0, + height: 0, + minDepth: 0, + maxDepth: 1, + success: false +}, // Both width and height of zero are not allowed +{ + x: -1, + y: 0, + width: 1, + height: 1, + minDepth: 0, + maxDepth: 1, + success: true +}, // Negative x is allowed +{ + x: 0, + y: -1, + width: 1, + height: 1, + minDepth: 0, + maxDepth: 1, + success: true +}, // Negative y is allowed +{ + x: 0, + y: 0, + width: -1, + height: 1, + minDepth: 0, + maxDepth: 1, + success: false +}, // Negative width is not allowed +{ + x: 0, + y: 0, + width: 1, + height: -1, + minDepth: 0, + maxDepth: 1, + success: false +}, // Negative height is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: -1, + maxDepth: 1, + success: false +}, // Negative minDepth is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 0, + maxDepth: -1, + success: false +}, // Negative maxDepth is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 10, + maxDepth: 1, + success: false +}, // minDepth greater than 1 is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 0, + maxDepth: 10, + success: false +}, // maxDepth greater than 1 is not allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 0.5, + maxDepth: 0.5, + success: true +}, // minDepth equal to maxDepth is allowed +{ + x: 0, + y: 0, + width: 1, + height: 1, + minDepth: 0.8, + maxDepth: 0.5, + success: true +}, // minDepth greater than maxDepth is allowed +{ + x: 0, + y: 0, + width: TEXTURE_WIDTH + 1, + height: TEXTURE_HEIGHT + 1, + minDepth: 0, + maxDepth: 1, + success: true +} // Viewport larger than the framebuffer is allowed +]); +//# sourceMappingURL=setViewport.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/validation_test.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/validation_test.js new file mode 100644 index 00000000000..35ad5d89552 --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/validation_test.js @@ -0,0 +1,39 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +import { GPUTest } from '../gpu_test.js'; +export class ValidationTest extends GPUTest { + async getErrorBuffer() { + this.device.pushErrorScope('validation'); + const errorBuffer = this.device.createBuffer({ + size: 1024, + usage: 0xffff // Invalid GPUBufferUsage + + }); + await this.device.popErrorScope(); + return errorBuffer; + } + + async expectValidationError(fn, shouldError = true) { + // If no error is expected, we let the scope surrounding the test catch it. + if (shouldError === false) { + fn(); + return; + } + + return this.asyncExpectation(async () => { + this.device.pushErrorScope('validation'); + fn(); + const gpuValidationError = await this.device.popErrorScope(); + + if (!gpuValidationError) { + this.fail('Validation error was expected.'); + } else if (gpuValidationError instanceof GPUValidationError) { + this.debug(`Captured validation error - ${gpuValidationError.message}`); + } + }); + } + +} +//# sourceMappingURL=validation_test.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_input.spec.js b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_input.spec.js new file mode 100644 index 00000000000..432a04a4cee --- /dev/null +++ b/tests/wpt/web-platform-tests/webgpu/suites/cts/validation/vertex_input.spec.js @@ -0,0 +1,623 @@ +/** +* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts +**/ + +export const description = ` +vertexInput validation tests. +`; +import { TestGroup } from '../../../framework/index.js'; +import { ValidationTest } from './validation_test.js'; +const MAX_VERTEX_ATTRIBUTES = 16; +const MAX_VERTEX_BUFFER_END = 2048; +const MAX_VERTEX_BUFFER_STRIDE = 2048; +const MAX_VERTEX_BUFFERS = 16; +const VERTEX_SHADER_CODE_WITH_NO_INPUT = ` + #version 450 + void main() { + gl_Position = vec4(0.0); + } +`; + +function clone(descriptor) { + return JSON.parse(JSON.stringify(descriptor)); +} + +class F extends ValidationTest { + async init() { + await Promise.all([super.init(), this.initGLSL()]); + } + + getDescriptor(vertexInput, vertexShaderCode) { + const descriptor = { + vertexStage: this.getVertexStage(vertexShaderCode), + fragmentStage: this.getFragmentStage(), + layout: this.getPipelineLayout(), + primitiveTopology: 'triangle-list', + colorStates: [{ + format: 'rgba8unorm' + }], + vertexInput + }; + return descriptor; + } + + getVertexStage(code) { + return { + module: this.makeShaderModule('vertex', code), + entryPoint: 'main' + }; + } + + getFragmentStage() { + const code = ` + #version 450 + layout(location = 0) out vec4 fragColor; + void main() { + fragColor = vec4(0.0, 1.0, 0.0, 1.0); + } + `; + return { + module: this.makeShaderModule('fragment', code), + entryPoint: 'main' + }; + } + + getPipelineLayout() { + return this.device.createPipelineLayout({ + bindGroupLayouts: [] + }); + } + +} + +export const g = new TestGroup(F); +g.test('an empty vertex input is valid', t => { + const vertexInput = {}; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); +}); +g.test('a null buffer is valid', t => { + { + // One null buffer is OK + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // One null buffer followed by a buffer is OK + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [] + }, { + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // One null buffer sitting between buffers is OK + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }, { + stride: 0, + attributeSet: [] + }, { + stride: 0, + attributeSet: [{ + shaderLocation: 1, + format: 'float' + }] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }, { + shaderLocation: 1, + format: 'float' + }] + }] + }; + { + // Control case: pipeline with one input per attribute + const code = ` + #version 450 + layout(location = 0) in vec4 a; + layout(location = 1) in vec4 b; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexInput, code); + t.device.createRenderPipeline(descriptor); + } + { + // Check it is valid for the pipeline to use a subset of the VertexInput + const code = ` + #version 450 + layout(location = 0) in vec4 a; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexInput, code); + t.device.createRenderPipeline(descriptor); + } + { + // Check for an error when the pipeline uses an attribute not in the vertex input + const code = ` + #version 450 + layout(location = 2) in vec4 a; + void main() { + gl_Position = vec4(0.0); + } + `; + const descriptor = t.getDescriptor(vertexInput, code); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('a stride of 0 is valid', t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }] + }; + { + // Works ok without attributes + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Works ok with attributes at a large-ish offset + vertexInput.vertexBuffers[0].attributeSet[0].offset = 128; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('offset should be within vertex buffer stride if stride is not zero', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }, { + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1, + format: 'float' + }] + }] + }; + { + // Control case, setting correct stride and offset + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute offset exceed vertex buffer stride range + const badVertexInput = clone(vertexInput); + badVertexInput.vertexBuffers[0].attributeSet[1].format = 'float2'; + const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // Test vertex attribute offset exceed vertex buffer stride range + const badVertexInput = clone(vertexInput); + badVertexInput.vertexBuffers[0].stride = Float32Array.BYTES_PER_ELEMENT; + const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // It's OK if stride is zero + const goodVertexInput = clone(vertexInput); + goodVertexInput.vertexBuffers[0].stride = 0; + const descriptor = t.getDescriptor(goodVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } +}); +g.test('check two attributes overlapping', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 2 * Float32Array.BYTES_PER_ELEMENT, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }, { + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1, + format: 'float' + }] + }] + }; + { + // Control case, setting correct stride and offset + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test two attributes overlapping + const badVertexInput = clone(vertexInput); + badVertexInput.vertexBuffers[0].attributeSet[0].format = 'int2'; + const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on total number of vertex buffers', async t => { + const vertexBuffers = []; + + for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) { + vertexBuffers.push({ + stride: 0, + attributeSet: [{ + shaderLocation: i, + format: 'float' + }] + }); + } + + { + // Control case, setting max vertex buffer number + const vertexInput = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex buffer number exceed the limit + const vertexInput = { + vertexBuffers: [...vertexBuffers, { + stride: 0, + attributeSet: [{ + shaderLocation: MAX_VERTEX_BUFFERS, + format: 'float' + }] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => { + const vertexAttributes = []; + + for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { + vertexAttributes.push({ + shaderLocation: i, + format: 'float' + }); + } + + { + // Control case, setting max vertex buffer number + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: vertexAttributes + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute number exceed the limit + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [...vertexAttributes, { + shaderLocation: MAX_VERTEX_ATTRIBUTES, + format: 'float' + }] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => { + const vertexBuffers = []; + + for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) { + vertexBuffers.push({ + stride: 0, + attributeSet: [{ + shaderLocation: i, + format: 'float' + }] + }); + } + + { + // Control case, setting max vertex buffer number + const vertexInput = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test vertex attribute number exceed the limit + vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributeSet.push({ + shaderLocation: MAX_VERTEX_ATTRIBUTES, + format: 'float' + }); + const vertexInput = { + vertexBuffers + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on input strides', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: MAX_VERTEX_BUFFER_STRIDE, + attributeSet: [] + }] + }; + { + // Control case, setting max input stride + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test input stride OOB + vertexInput.vertexBuffers[0].stride = MAX_VERTEX_BUFFER_STRIDE + 4; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check multiple of 4 bytes constraint on input stride', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 4, + attributeSet: [{ + shaderLocation: 0, + format: 'uchar2' + }] + }] + }; + { + // Control case, setting input stride 4 bytes + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test input stride not multiple of 4 bytes + vertexInput.vertexBuffers[0].stride = 2; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('identical duplicate attributes are invalid', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }] + }; + { + // Control case, setting attribute 0 + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Oh no, attribute 0 is set twice + vertexInput.vertexBuffers[0].attributeSet.push({ + shaderLocation: 0, + format: 'float' + }); + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('we cannot set same shader location', async t => { + { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }, { + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 1, + format: 'float' + }] + }] + }; + { + // Control case, setting different shader locations in two attributes + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test same shader location in two attributes in the same buffer + vertexInput.vertexBuffers[0].attributeSet[1].shaderLocation = 0; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + } + { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }, { + stride: 0, + attributeSet: [{ + shaderLocation: 0, + format: 'float' + }] + }] + }; // Test same shader location in two attributes in different buffers + + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check out of bounds condition on attribute shader location', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + shaderLocation: MAX_VERTEX_ATTRIBUTES - 1, + format: 'float' + }] + }] + }; + { + // Control case, setting last attribute shader location + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test attribute location OOB + vertexInput.vertexBuffers[0].attributeSet[0].shaderLocation = MAX_VERTEX_ATTRIBUTES; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check attribute offset out of bounds', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + offset: MAX_VERTEX_BUFFER_END - 2 * Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 0, + format: 'float2' + }] + }] + }; + { + // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8 + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Control case, setting attribute offset to 8 + vertexInput.vertexBuffers[0].attributeSet[0].offset = 8; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test attribute offset out of bounds + vertexInput.vertexBuffers[0].attributeSet[0].offset = MAX_VERTEX_BUFFER_END - 4; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check multiple of 4 bytes constraint on offset', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + offset: Float32Array.BYTES_PER_ELEMENT, + shaderLocation: 0, + format: 'float' + }] + }] + }; + { + // Control case, setting offset 4 bytes + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + t.device.createRenderPipeline(descriptor); + } + { + // Test offset of 2 bytes with uchar2 format + vertexInput.vertexBuffers[0].attributeSet[0].offset = 2; + vertexInput.vertexBuffers[0].attributeSet[0].format = 'uchar2'; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } + { + // Test offset of 2 bytes with float format + vertexInput.vertexBuffers[0].attributeSet[0].offset = 2; + vertexInput.vertexBuffers[0].attributeSet[0].format = 'float'; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); + } +}); +g.test('check attribute offset overflow', async t => { + const vertexInput = { + vertexBuffers: [{ + stride: 0, + attributeSet: [{ + offset: Number.MAX_SAFE_INTEGER, + shaderLocation: 0, + format: 'float' + }] + }] + }; + const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT); + await t.expectValidationError(() => { + t.device.createRenderPipeline(descriptor); + }); +}); +//# sourceMappingURL=vertex_input.spec.js.map
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset_immersive.https.html b/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset_immersive.https.html new file mode 100644 index 00000000000..2da3788a39a --- /dev/null +++ b/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset_immersive.https.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="resources/webxr_util.js"></script> +<script src="resources/webxr_test_constants.js"></script> +<canvas id="webgl-canvas"></canvas> + +<script> +let immersiveTestName = "XRSession resetpose from a device properly fires off " + + "the right events for immersive sessions"; + +let watcherDone = new Event("watcherdone"); + +let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE; + +let testFunction = function(session, fakeDeviceController, t) { + let resetPromise = session.requestReferenceSpace('local') + .then((refSpace) => { + let eventWatcher = new EventWatcher( + t, refSpace, ["reset", "watcherdone"]); + refSpace.addEventListener("reset", (event) => { + t.step(() => { + assert_equals(event.referenceSpace, refSpace); + + // Also make sure the same objects are returned each time these + // attributes are accessed. + let eventRefSpace = event.referenceSpace; + let transform = event.transform; + assert_equals(eventRefSpace, event.referenceSpace, + "XRReferenceSpaceEvent.referenceSpace returns the same object."); + assert_equals(transform, event.transform, + "XRReferenceSpaceEvent.transform returns the same object."); + }); + + refSpace.dispatchEvent(watcherDone); + }, false); + return eventWatcher.wait_for(["reset", "watcherdone"]); + }); + + fakeDeviceController.simulateResetPose(); + + // The triggered resetPose event should arrive after the next Animation Frame + session.requestAnimationFrame(() => {}); + + return resetPromise; +}; + +xr_session_promise_test( + immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr'); + +</script> diff --git a/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset.https.html b/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset_inline.https.html index 3a931168fd3..b3abcc817bd 100644 --- a/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset.https.html +++ b/tests/wpt/web-platform-tests/webxr/events_referenceSpace_reset_inline.https.html @@ -6,8 +6,6 @@ <canvas id="webgl-canvas"></canvas> <script> -let immersiveTestName = "XRSession resetpose from a device properly fires off " + - "the right events for immersive sessions"; let nonImmersiveTestName = "XRSession resetpose from a device properly fires off " + "the right events for non-immersive sessions"; @@ -48,8 +46,6 @@ let testFunction = function(session, fakeDeviceController, t) { }; xr_session_promise_test( - immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr'); -xr_session_promise_test( nonImmersiveTestName, testFunction, fakeDeviceInitParams, 'inline', { requiredFeatures: ['local'], }); diff --git a/tests/wpt/webgl/meta/conformance2/rendering/canvas-resizing-with-pbo-bound.html.ini b/tests/wpt/webgl/meta/conformance2/rendering/canvas-resizing-with-pbo-bound.html.ini index 436b6e96fe7..0e7c48f1481 100644 --- a/tests/wpt/webgl/meta/conformance2/rendering/canvas-resizing-with-pbo-bound.html.ini +++ b/tests/wpt/webgl/meta/conformance2/rendering/canvas-resizing-with-pbo-bound.html.ini @@ -1,5 +1,4 @@ [canvas-resizing-with-pbo-bound.html] - expected: TIMEOUT [WebGL test #0: Unable to fetch WebGL rendering context for Canvas] expected: FAIL |