aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/wpt/meta/FileAPI/url/url-with-fetch.any.js.ini3
-rw-r--r--tests/wpt/meta/MANIFEST.json2215
-rw-r--r--tests/wpt/meta/css/css-align/abspos/align-self-stretch-auto-margins.html.ini2
-rw-r--r--tests/wpt/meta/css/css-align/abspos/justify-self-stretch-auto-margins.html.ini2
-rw-r--r--tests/wpt/meta/css/css-align/blocks/justify-self-auto-margins-2.html.ini2
-rw-r--r--tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html.ini24
-rw-r--r--tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html.ini24
-rw-r--r--tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini3
-rw-r--r--tests/wpt/meta/css/css-content/parsing/content-counter-valid.html.ini9
-rw-r--r--tests/wpt/meta/css/css-fonts/font-family-name-000.xht.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-020.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-021.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-034.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-035.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-036.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-037.html.ini2
-rw-r--r--tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html.ini24
-rw-r--r--tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html.ini39
-rw-r--r--tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand.html.ini192
-rw-r--r--tests/wpt/meta/css/css-gaps/serialization/gap-decorations-properties.html.ini189
-rw-r--r--tests/wpt/meta/css/css-mixins/dashed-function-cycles.html.ini3
-rw-r--r--tests/wpt/meta/css/css-mixins/local-attr-substitution.html.ini3
-rw-r--r--tests/wpt/meta/css/css-overflow/overflow-video.html.ini2
-rw-r--r--tests/wpt/meta/css/css-text/bidi/empty-span-001.html.ini2
-rw-r--r--tests/wpt/meta/css/css-values/attr-cycle.html.ini10
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-function-descriptors.tentative.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini54
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html.ini6
-rw-r--r--tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html.ini6
-rw-r--r--tests/wpt/meta/css/css-variables/variable-cycles.html.ini3
-rw-r--r--tests/wpt/meta/css/css-variables/variable-substitution-variable-declaration.html.ini12
-rw-r--r--tests/wpt/meta/css/filter-effects/hidpi-invert-filter-background.html.ini2
-rw-r--r--tests/wpt/meta/css/selectors/invalidation/has-with-nth-child-sibling-remove.html.ini2
-rw-r--r--tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html.ini3
-rw-r--r--tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini2
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html.ini7
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm.ini40
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html.ini90
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-object-element/object-javascript-url.html.ini7
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm.ini3
-rw-r--r--tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/permission-element/display-css-property-reftest.tentative.html.ini2
-rw-r--r--tests/wpt/meta/html/semantics/permission-element/display-css-property.tentative.html.ini3
-rw-r--r--tests/wpt/meta/html/semantics/popovers/popover-toggle-source.tentative.html.ini21
-rw-r--r--tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini6
-rw-r--r--tests/wpt/meta/resize-observer/change-layout-in-error.html.ini3
-rw-r--r--tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.html.ini (renamed from tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.https.html.ini)7
-rw-r--r--tests/wpt/meta/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html.ini2
-rw-r--r--tests/wpt/meta/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html.ini4
-rw-r--r--tests/wpt/meta/wasm/webapi/esm-integration/source-phase-preload.tentative.html.ini7
-rw-r--r--tests/wpt/meta/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html.ini3
-rw-r--r--tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini9
-rw-r--r--tests/wpt/tests/.github/workflows/documentation.yml8
-rw-r--r--tests/wpt/tests/accelerometer/Accelerometer-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/accelerometer/Accelerometer.https.html2
-rw-r--r--tests/wpt/tests/accelerometer/GravitySensor.https.html2
-rw-r--r--tests/wpt/tests/accelerometer/LinearAccelerationSensor.https.html2
-rw-r--r--tests/wpt/tests/ai/resources/util.js50
-rw-r--r--tests/wpt/tests/ai/rewriter/resources/iframe-helper.html25
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter-abort.tentative.https.window.js35
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter-availability-available.tentative.https.window.js34
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter-availability.tentative.https.window.js31
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.js56
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter-iframe.tentative.https.html58
-rw-r--r--tests/wpt/tests/ai/rewriter/rewriter.tentative.https.window.js173
-rw-r--r--tests/wpt/tests/ai/summarizer/resources/iframe-helper.html35
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-abort.tentative.https.window.js14
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-availability-available.tentative.https.window.js1
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-availability.tentative.https.window.js1
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-create-available.tentative.https.window.js31
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-create.tentative.https.window.js15
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-iframe.tentative.https.html111
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js3
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js9
-rw-r--r--tests/wpt/tests/ai/summarizer/summarizer-summarize.tentative.https.window.js5
-rw-r--r--tests/wpt/tests/ai/translator/translator.optional.https.window.js50
-rw-r--r--tests/wpt/tests/ai/writer/resources/iframe-helper.html26
-rw-r--r--tests/wpt/tests/ai/writer/writer-abort.tentative.https.window.js37
-rw-r--r--tests/wpt/tests/ai/writer/writer-availability-available.tentative.https.window.js34
-rw-r--r--tests/wpt/tests/ai/writer/writer-availability.tentative.https.window.js31
-rw-r--r--tests/wpt/tests/ai/writer/writer-from-detached-iframe.tentative.https.window.js56
-rw-r--r--tests/wpt/tests/ai/writer/writer-iframe.tentative.https.html58
-rw-r--r--tests/wpt/tests/ai/writer/writer.tentative.https.window.js175
-rw-r--r--tests/wpt/tests/ambient-light/AmbientLightSensor-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/ambient-light/AmbientLightSensor.https.html2
-rw-r--r--tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html50
-rw-r--r--tests/wpt/tests/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html127
-rw-r--r--tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html112
-rw-r--r--tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html47
-rw-r--r--tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html54
-rw-r--r--tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html61
-rw-r--r--tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html21
-rw-r--r--tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js23
-rw-r--r--tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js6
-rw-r--r--tests/wpt/tests/compute-pressure/resources/worker-support.js4
-rw-r--r--tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js31
-rw-r--r--tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js66
-rw-r--r--tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html83
-rw-r--r--tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js117
-rw-r--r--tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html11
-rw-r--r--tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html4
-rw-r--r--tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html6
-rw-r--r--tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html4
-rw-r--r--tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html6
-rw-r--r--tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.html (renamed from tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.tentative.html)0
-rw-r--r--tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html10
-rw-r--r--tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change-ref.html35
-rw-r--r--tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html53
-rw-r--r--tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html113
-rw-r--r--tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html36
-rw-r--r--tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html72
-rw-r--r--tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html71
-rw-r--r--tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html71
-rw-r--r--tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html16
-rw-r--r--tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html29
-rw-r--r--tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html14
-rw-r--r--tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html68
-rw-r--r--tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html68
-rw-r--r--tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html68
-rw-r--r--tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html1
-rw-r--r--tests/wpt/tests/css/css-contain/contain-inline-size-grid-auto-fit.html32
-rw-r--r--tests/wpt/tests/css/css-content/parsing/content-counter-valid.html13
-rw-r--r--tests/wpt/tests/css/css-fonts/font-family-name-000.xht15
-rw-r--r--tests/wpt/tests/css/css-fonts/font-family-name-024.xht6
-rw-r--r--tests/wpt/tests/css/css-fonts/font-palette-relative-color-crash.html18
-rw-r--r--tests/wpt/tests/css/css-fonts/test-synthetic-bold-notref.html18
-rw-r--r--tests/wpt/tests/css/css-fonts/test-synthetic-bold.html (renamed from tests/wpt/tests/css/css-fonts/test-synthetic-bold.xht)9
-rw-r--r--tests/wpt/tests/css/css-fonts/test-synthetic-italic-notref.html19
-rw-r--r--tests/wpt/tests/css/css-fonts/test-synthetic-italic.html (renamed from tests/wpt/tests/css/css-fonts/test-synthetic-italic.xht)9
-rw-r--r--tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html14
-rw-r--r--tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003-ref.html32
-rw-r--r--tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003.html51
-rw-r--r--tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html55
-rw-r--r--tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html49
-rw-r--r--tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html55
-rw-r--r--tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html49
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html71
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html48
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html71
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html44
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html71
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html44
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html70
-rw-r--r--tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html48
-rw-r--r--tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html76
-rw-r--r--tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html62
-rw-r--r--tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html31
-rw-r--r--tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html127
-rw-r--r--tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html300
-rw-r--r--tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html4
-rw-r--r--tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-001.html82
-rw-r--r--tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html79
-rw-r--r--tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html68
-rw-r--r--tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html78
-rw-r--r--tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html1
-rw-r--r--tests/wpt/tests/css/css-images/multiple-position-color-stop-radial.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-linear-2.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-linear-degenerate.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-linear.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-radial-2.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-radial-3.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-radial-4.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-radial-degenerate.html1
-rw-r--r--tests/wpt/tests/css/css-images/normalization-radial.html1
-rw-r--r--tests/wpt/tests/css/css-images/tiled-gradients.html36
-rw-r--r--tests/wpt/tests/css/css-mixins/dashed-function-cycles.html6
-rw-r--r--tests/wpt/tests/css/css-mixins/local-attr-substitution.html8
-rw-r--r--tests/wpt/tests/css/css-multicol/crashtests/float-cannot-be-spanner.html11
-rw-r--r--tests/wpt/tests/css/css-multicol/multicol-fill-balance-030.html22
-rw-r--r--tests/wpt/tests/css/css-multicol/offsetProps-001.html41
-rw-r--r--tests/wpt/tests/css/css-properties-values-api/registered-property-computation-color-005.html17
-rw-r--r--tests/wpt/tests/css/css-properties-values-api/resolved-color-value.html23
-rw-r--r--tests/wpt/tests/css/css-scroll-snap/resnap-on-snap-alignment-change.html1
-rw-r--r--tests/wpt/tests/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html7
-rw-r--r--tests/wpt/tests/css/css-scroll-snap/smooth-anchor-scroll-in-snap-container.html1
-rw-r--r--tests/wpt/tests/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align-nested.tentative.html10
-rw-r--r--tests/wpt/tests/css/css-scroll-snap/snapevent-constructor.html42
-rw-r--r--tests/wpt/tests/css/css-text-decor/crashtests/text-decoration-first-line-layer-crash.html26
-rw-r--r--tests/wpt/tests/css/css-text/bidi/empty-span-001-ref.html22
-rw-r--r--tests/wpt/tests/css/css-text/bidi/empty-span-001.html23
-rw-r--r--tests/wpt/tests/css/css-ui/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/css/css-ui/parsing/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/css/css-values/attr-cycle.html13
-rw-r--r--tests/wpt/tests/css/css-values/if-cycle.html2
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-function-descriptors.tentative.html23
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html34
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html34
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html34
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html109
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html34
-rw-r--r--tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html34
-rw-r--r--tests/wpt/tests/css/css-variables/variable-cycles.html12
-rw-r--r--tests/wpt/tests/css/css-variables/variable-substitution-variable-declaration.html8
-rw-r--r--tests/wpt/tests/css/css-view-transitions/content-with-transform-ref.html2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/dynamic-stylesheet-animations-timing-function.html140
-rw-r--r--tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html2
-rw-r--r--tests/wpt/tests/css/css-view-transitions/pseudo-get-computed-style.html35
-rw-r--r--tests/wpt/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html11
-rw-r--r--tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background-ref.html19
-rw-r--r--tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background.html28
-rw-r--r--tests/wpt/tests/css/selectors/invalidation/has-with-nth-child-sibling-remove.html33
-rw-r--r--tests/wpt/tests/css/selectors/invalidation/negated-last-of-type-invalidation.html32
-rw-r--r--tests/wpt/tests/css/selectors/quirks-mode-import.html25
-rw-r--r--tests/wpt/tests/digital-credentials/allow-attribute-with-get.https.html3
-rw-r--r--tests/wpt/tests/digital-credentials/get.tentative.https.html35
-rw-r--r--tests/wpt/tests/digital-credentials/non-fully-active.https.html8
-rw-r--r--tests/wpt/tests/digital-credentials/support/iframe.html4
-rw-r--r--tests/wpt/tests/digital-credentials/user-activation.https.html11
-rw-r--r--tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-basic.tentative.https.html57
-rw-r--r--tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-caches-pictures.tentative.https.html69
-rw-r--r--tests/wpt/tests/fedcm/support/account_picture.py23
-rw-r--r--tests/wpt/tests/fedcm/support/account_picture_get_count.py13
-rw-r--r--tests/wpt/tests/fedcm/support/account_picture_uncached.py23
-rw-r--r--tests/wpt/tests/fedcm/support/account_picture_uncached_get_count.py13
-rw-r--r--tests/wpt/tests/fedcm/support/fedcm-helper.sub.js4
-rw-r--r--tests/wpt/tests/fedcm/support/keys.py2
-rw-r--r--tests/wpt/tests/fedcm/support/manifest_accounts_push.json4
-rw-r--r--tests/wpt/tests/fedcm/support/mark_signedout.sub.headers1
-rw-r--r--tests/wpt/tests/fedcm/support/push_accounts30
-rw-r--r--tests/wpt/tests/fedcm/support/push_accounts.sub.headers5
-rw-r--r--tests/wpt/tests/fedcm/support/request-params-check.py19
-rw-r--r--tests/wpt/tests/generic-sensor/generic-sensor-iframe-tests.sub.js12
-rw-r--r--tests/wpt/tests/generic-sensor/generic-sensor-tests.js51
-rw-r--r--tests/wpt/tests/generic-sensor/resources/iframe_sensor_handler.html5
-rw-r--r--tests/wpt/tests/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html17
-rw-r--r--tests/wpt/tests/geolocation/getCurrentPosition-error.https.html48
-rw-r--r--tests/wpt/tests/geolocation/getCurrentPosition-success.https.html43
-rw-r--r--tests/wpt/tests/gyroscope/Gyroscope-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/gyroscope/Gyroscope.https.html2
-rw-r--r--tests/wpt/tests/html/canvas/canvas-sibling-index-crash.html10
-rw-r--r--tests/wpt/tests/html/cross-origin-opener-policy/resources/noopener-helper.js8
-rw-r--r--tests/wpt/tests/html/dom/elements-embedded.js8
-rw-r--r--tests/wpt/tests/html/dom/new-harness.js2
-rw-r--r--tests/wpt/tests/html/dom/original-harness.js20
-rw-r--r--tests/wpt/tests/html/dom/reflection.js27
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html43
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html2
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html4
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm46
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html24
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm23
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html24
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html23
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_navigate_javascript_url.htm33
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html189
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-object-element/object-javascript-url.html44
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-meter-element/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-progress-element/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-optgroup-arrow-keys.tentative.html76
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html8
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html148
-rw-r--r--tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent.tentative.html4
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-details-element/details-toggle-source.tentative.html77
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-corner-cases.html103
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-show-stacked.html127
-rw-r--r--tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-toggle-source.tentative.html56
-rw-r--r--tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest-ref.html16
-rw-r--r--tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html22
-rw-r--r--tests/wpt/tests/html/semantics/permission-element/display-css-property.tentative.html34
-rw-r--r--tests/wpt/tests/html/semantics/popovers/popover-toggle-source.tentative.html90
-rw-r--r--tests/wpt/tests/html/semantics/popovers/resources/toggle-event-source-test.js76
-rw-r--r--tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-keyboard-behavior.tentative.html17
-rw-r--r--tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-pseudo-classes.tentative.html43
-rw-r--r--tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/initial-color.html.ini3
-rw-r--r--tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini3
-rw-r--r--tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini6
-rw-r--r--tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/click-multiple.html.ini4
-rw-r--r--tests/wpt/tests/interfaces/crash-reporting.idl2
-rw-r--r--tests/wpt/tests/interfaces/digital-credentials.idl19
-rw-r--r--tests/wpt/tests/interfaces/speech-api.idl16
-rw-r--r--tests/wpt/tests/interfaces/translation-api.idl85
-rw-r--r--tests/wpt/tests/interfaces/webnn.idl3
-rw-r--r--tests/wpt/tests/lifecycle/META.yml3
-rw-r--r--tests/wpt/tests/lint.ignore1
-rw-r--r--tests/wpt/tests/magnetometer/Magnetometer-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/magnetometer/Magnetometer.https.html2
-rw-r--r--tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor.https.html2
-rw-r--r--tests/wpt/tests/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html2
-rw-r--r--tests/wpt/tests/orientation-sensor/RelativeOrientationSensor.https.html2
-rw-r--r--tests/wpt/tests/page-lifecycle/META.yml2
-rw-r--r--tests/wpt/tests/page-lifecycle/child-display-none.tentative.html (renamed from tests/wpt/tests/lifecycle/child-display-none.tentative.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/child-out-of-viewport.tentative.html (renamed from tests/wpt/tests/lifecycle/child-out-of-viewport.tentative.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/freeze.html (renamed from tests/wpt/tests/lifecycle/freeze.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/beacon.py (renamed from tests/wpt/tests/lifecycle/resources/beacon.py)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/child.html (renamed from tests/wpt/tests/lifecycle/resources/child.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/subframe.html (renamed from tests/wpt/tests/lifecycle/resources/subframe.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/subframe_worker.html (renamed from tests/wpt/tests/lifecycle/resources/subframe_worker.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/subframe_worker1.js (renamed from tests/wpt/tests/lifecycle/resources/subframe_worker1.js)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/subframe_worker2.js (renamed from tests/wpt/tests/lifecycle/resources/subframe_worker2.js)0
-rw-r--r--tests/wpt/tests/page-lifecycle/resources/window.html (renamed from tests/wpt/tests/lifecycle/resources/window.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/set-composited-layer-position-ref.html (renamed from tests/wpt/tests/lifecycle/set-composited-layer-position-ref.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/set-composited-layer-position.html (renamed from tests/wpt/tests/lifecycle/set-composited-layer-position.html)0
-rw-r--r--tests/wpt/tests/page-lifecycle/worker-dispay-none.tentative.html (renamed from tests/wpt/tests/lifecycle/worker-dispay-none.tentative.html)0
-rw-r--r--tests/wpt/tests/pointerevents/pointerevent_click_during_parent_capture.html280
-rw-r--r--tests/wpt/tests/requestidlecallback/WEB_FEATURES.yml3
-rw-r--r--tests/wpt/tests/resources/idlharness.js9
-rw-r--r--tests/wpt/tests/sanitizer-api/sanitizer-basic-filtering.tentative.html73
-rw-r--r--tests/wpt/tests/scroll-animations/crashtests/scroll-timeline-completion-crash.html42
-rw-r--r--tests/wpt/tests/scroll-animations/css/timeline-scope-computed.html (renamed from tests/wpt/tests/scroll-animations/css/timeline-scope-computed.tentative.html)2
-rw-r--r--tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.html (renamed from tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.tentative.html)2
-rw-r--r--tests/wpt/tests/shadow-dom/crashtests/manual-assignment-beforeattrmodified.html15
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/replacestate.tentative.html30
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js407
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/almost-soft-navigation.html120
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html116
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/task-attribution.html155
-rw-r--r--tests/wpt/tests/soft-navigation-heuristics/soft-navigation-no-url.tentative.html31
-rw-r--r--tests/wpt/tests/speculation-rules/prefetch/resources/utils.sub.js22
-rw-r--r--tests/wpt/tests/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html12
-rw-r--r--tests/wpt/tests/speech-api/SpeechRecognition-availableOnDevice.https.html140
-rw-r--r--tests/wpt/tests/speech-api/SpeechRecognition-basics.https.html2
-rw-r--r--tests/wpt/tests/speech-api/SpeechRecognition-installOnDevice.https.html290
-rw-r--r--tests/wpt/tests/speech-api/SpeechRecognition-phrases-manual.https.html (renamed from tests/wpt/tests/speech-api/SpeechRecognition-recognitionContext-manual.https.html)33
-rw-r--r--tests/wpt/tests/storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.js1
-rw-r--r--tests/wpt/tests/storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.js1
-rw-r--r--tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.html (renamed from tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.https.html)0
-rw-r--r--tests/wpt/tests/tools/ci/requirements_build.txt1
-rw-r--r--tests/wpt/tests/tools/ci/requirements_tc.txt2
-rw-r--r--tests/wpt/tests/tools/docker/requirements.txt2
-rw-r--r--tests/wpt/tests/tools/manifest/download.py4
-rw-r--r--tests/wpt/tests/tools/manifest/sourcefile.py7
-rw-r--r--tests/wpt/tests/tools/metadata/yaml/requirements.txt1
-rw-r--r--tests/wpt/tests/tools/mypy.ini65
-rw-r--r--tests/wpt/tests/tools/requirements_mypy.txt37
-rw-r--r--tests/wpt/tests/tools/requirements_tests.txt1
-rw-r--r--tests/wpt/tests/tools/serve/serve.py5
-rw-r--r--tests/wpt/tests/tools/wave/requirements.txt1
-rw-r--r--tests/wpt/tests/tools/webdriver/webdriver/bidi/transport.py6
-rw-r--r--tests/wpt/tests/tools/webtransport/h3/capsule.py6
-rw-r--r--tests/wpt/tests/tools/webtransport/h3/webtransport_h3_server.py53
-rw-r--r--tests/wpt/tests/tools/wpt/browser.py177
-rw-r--r--tests/wpt/tests/tools/wpt/requirements.txt1
-rw-r--r--tests/wpt/tests/tools/wpt/requirements_metadata.txt1
-rw-r--r--tests/wpt/tests/tools/wptrunner/requirements.txt2
-rw-r--r--tests/wpt/tests/tools/wptrunner/requirements_firefox.txt1
-rw-r--r--tests/wpt/tests/tools/wptrunner/requirements_safari.txt1
-rw-r--r--tests/wpt/tests/tools/wptrunner/requirements_sauce.txt1
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/asyncactions.py3
-rw-r--r--tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py7
-rw-r--r--tests/wpt/tests/tools/wptserve/setup.py2
-rw-r--r--tests/wpt/tests/tools/wptserve/tests/functional/test_pipes.py16
-rw-r--r--tests/wpt/tests/tools/wptserve/wptserve/ws_h2_handshake.py2
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/resources/audio-worklet-source-phase.js43
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-dynamic-source-phase-import.sub.js2
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-static-source-phase-import.sub.js1
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-helper.js5
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-source-phase.js7
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html35
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html23
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/source-phase-preload.tentative.html64
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html4
-rw-r--r--tests/wpt/tests/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html22
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/__init__.py14
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/context_created.py34
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/original_opener.py11
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed.py14
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/reference_context.py7
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/type.py6
-rw-r--r--tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/user_context.py17
-rw-r--r--tests/wpt/tests/webdriver/tests/interop/beforeunload_prompt.py67
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/prelu.https.any.js168
-rw-r--r--tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js385
-rw-r--r--tests/wpt/tests/webnn/resources/utils.js34
-rw-r--r--tests/wpt/tests/webnn/resources/utils_validation.js2
-rw-r--r--tests/wpt/tests/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html25
-rw-r--r--tests/wpt/tests/webrtc-encoded-transform/idlharness.https.window.js3
377 files changed, 11523 insertions, 2397 deletions
diff --git a/tests/wpt/meta/FileAPI/url/url-with-fetch.any.js.ini b/tests/wpt/meta/FileAPI/url/url-with-fetch.any.js.ini
index 292dc852b9f..b275cb58343 100644
--- a/tests/wpt/meta/FileAPI/url/url-with-fetch.any.js.ini
+++ b/tests/wpt/meta/FileAPI/url/url-with-fetch.any.js.ini
@@ -12,3 +12,6 @@
[Revoke blob URL after creating Request, then clone Request, will fetch]
expected: FAIL
+
+ [Revoke blob URL after calling fetch, fetch should succeed]
+ expected: FAIL
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index 8f9578b1ac9..4399aedf8e8 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -2775,6 +2775,13 @@
{}
]
],
+ "font-palette-relative-color-crash.html": [
+ "1dc973a00b97610843346cc840c02169e07c3da9",
+ [
+ null,
+ {}
+ ]
+ ],
"font-size-adjust-generic-font-fallback-crash.html": [
"b2884e975a114a40c9986fac38a45527954c3691",
[
@@ -3374,6 +3381,13 @@
{}
]
],
+ "float-cannot-be-spanner.html": [
+ "f366e79ae8dd94c117e20753573dc84e93321c2a",
+ [
+ null,
+ {}
+ ]
+ ],
"float-multicol-crash.html": [
"a8f01db169e9dbcfc211ed2d7d97da3a72fc5425",
[
@@ -5410,6 +5424,13 @@
{}
]
],
+ "text-decoration-first-line-layer-crash.html": [
+ "5f5b7e7b9e4774d74224000271e2115ef9792540",
+ [
+ null,
+ {}
+ ]
+ ],
"text-decoration-first-line-multi-crash.html": [
"f6176334ad6e6ef2662a8f89785f601f48a762cf",
[
@@ -7602,6 +7623,13 @@
}
},
"canvas": {
+ "canvas-sibling-index-crash.html": [
+ "506a77ebad50c2dd0e292bc7c1d20bb13d16080a",
+ [
+ null,
+ {}
+ ]
+ ],
"element": {
"manual": {
"filters": {
@@ -9494,6 +9522,13 @@
{}
]
],
+ "scroll-timeline-completion-crash.html": [
+ "fb7ecd1ed1bff87cb45bfdbcbb9ad7504a9fda9c",
+ [
+ null,
+ {}
+ ]
+ ],
"viewport-100vh.html": [
"cc862bd29955ec0c6730614a4eb72e3565c46cd4",
[
@@ -9682,6 +9717,13 @@
{}
]
],
+ "manual-assignment-beforeattrmodified.html": [
+ "50ba9303a8a9b9dd53fe20ba204c4548108e497e",
+ [
+ null,
+ {}
+ ]
+ ],
"move-to-new-tree-1343016.html": [
"853884b99301e22383e0fd0936cf154beab5e93e",
[
@@ -26417,8 +26459,8 @@
{}
]
],
- "SpeechRecognition-recognitionContext-manual.https.html": [
- "1039baa2825baed883e1c95c80247ee96a2ee33d",
+ "SpeechRecognition-phrases-manual.https.html": [
+ "2d0b19ab46ce3c41610b298750cbb0ca85832513",
[
null,
{}
@@ -124536,7 +124578,7 @@
]
],
"align-self-stretch-auto-margins-aspect-ratio.html": [
- "4eaa9d2f3a6dbab63d3d931d4c58a427bc11976f",
+ "347005204e333eeb813bd531ec1aa12e734e37d4",
[
null,
[
@@ -124549,7 +124591,7 @@
]
],
"align-self-stretch-auto-margins.html": [
- "9d1b6454c848c02b7fef360fb447d4d6b46ee8c0",
+ "9d6eb2306534d5d2a30c5724abf11e994470b92c",
[
null,
[
@@ -124588,7 +124630,7 @@
]
],
"justify-self-stretch-auto-margins-aspect-ratio.html": [
- "c50b32f089b1b0043ac5d9dbd0f79906d82827f3",
+ "bc6120584c248659646cad0a3f6349a23f4b8744",
[
null,
[
@@ -124601,7 +124643,7 @@
]
],
"justify-self-stretch-auto-margins.html": [
- "7d7b4bfc8570d3dde59fc903de7cb173b0b5baf8",
+ "675321fc2b12b16816e5355d420e51e3b0195aac",
[
null,
[
@@ -124833,7 +124875,7 @@
{}
]
],
- "justify-items-anonymous.tentative.html": [
+ "justify-items-anonymous.html": [
"641dea1f54b2f0cea29bc4c4c82e023a479e3d3c",
[
null,
@@ -124860,7 +124902,7 @@
]
],
"justify-self-auto-margins-2.html": [
- "33c98d6c1dfb43ff29f5c63472f041add65faff1",
+ "e81c4bba6f4fb98f79a3abfced011d896bd734d3",
[
null,
[
@@ -125118,7 +125160,7 @@
]
],
"anchor-center-visibility-change.html": [
- "0f7d805844f010d9854301c094b5ce6fd03d13fa",
+ "e5559433206741222198471088ddd165cf6786bf",
[
null,
[
@@ -125796,6 +125838,19 @@
{}
]
],
+ "position-area-visibility-change.html": [
+ "61d8ab50284aed3f7e2c3abc13180af7967e1463",
+ [
+ null,
+ [
+ [
+ "/css/css-anchor-position/reference/position-area-visibility-change-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"position-try-fallbacks-001.html": [
"b41e326800cf26a85b762ae34213e20aa47905b2",
[
@@ -126108,6 +126163,19 @@
{}
]
],
+ "position-visibility-no-overflow-without-anchor.html": [
+ "01f4d97947bc68ca09d6691f1a43fb98a57ea98d",
+ [
+ null,
+ [
+ [
+ "/css/css-anchor-position/position-visibility-no-overflow-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"position-visibility-no-overflow.html": [
"0569a9d179c02501eb747d66c830da96da14ae3b",
[
@@ -136835,6 +136903,35 @@
}
]
],
+ "corner-shape-overflow-clip-margin.html": [
+ "97371aa6c3f3891004a6da02548101ae9adf29d3",
+ [
+ null,
+ [
+ [
+ "/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html",
+ "=="
+ ]
+ ],
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 64
+ ],
+ [
+ 0,
+ 180
+ ]
+ ]
+ ]
+ ]
+ }
+ ]
+ ],
"corner-shape-render-fuzzy.html": [
"590e960830f595c7bc6f730d12d69e19c2ba0453",
[
@@ -157607,6 +157704,19 @@
{}
]
],
+ "contain-inline-size-grid-auto-fit.html": [
+ "b6401ac6640cd8476f9a740ac2838f97d078b6e1",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square-only.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"contain-inline-size-grid-stretches-auto-rows.html": [
"c168950929d58c2c7b0b4c4228f2185f8a7b4e88",
[
@@ -182209,6 +182319,19 @@
{}
]
],
+ "font-family-name-000.xht": [
+ "4eee0d232337fd068e1dc1c8fedf895323bcc59c",
+ [
+ null,
+ [
+ [
+ "/css/css-fonts/font-family-name-ref.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"font-family-name-001.xht": [
"5bb7a66ebd54dbe9dc78219f77c441654cd27818",
[
@@ -182509,7 +182632,7 @@
]
],
"font-family-name-024.xht": [
- "20aec304fa45f0cb4f14e56a6cd83046f1c7b0ed",
+ "6630cfd6090f8acced5009002db859565379c5da",
[
null,
[
@@ -186130,6 +186253,19 @@
{}
]
],
+ "test-synthetic-bold.html": [
+ "c2337c0a3ce538a573eddec7e75ea191bc394ae0",
+ [
+ null,
+ [
+ [
+ "/css/css-fonts/test-synthetic-bold-notref.html",
+ "!="
+ ]
+ ],
+ {}
+ ]
+ ],
"test-synthetic-italic-2.html": [
"6e8910e22c86c309de1403060f9a5061dbbf571c",
[
@@ -186156,6 +186292,19 @@
{}
]
],
+ "test-synthetic-italic.html": [
+ "3f6764ecfa3696310b1395037afbd6aa9c38b853",
+ [
+ null,
+ [
+ [
+ "/css/css-fonts/test-synthetic-italic-notref.html",
+ "!="
+ ]
+ ],
+ {}
+ ]
+ ],
"variation-sequences.html": [
"c1f69a5be5875556b5c64e962169aa9efca19ade",
[
@@ -186368,6 +186517,21 @@
]
},
"css-gaps": {
+ "agnostic": {
+ "gap-decorations-003.html": [
+ "2ec4a45beb71f8a0acacb2d14ca5f2f092b13094",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/agnostic/gap-decorations-003-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ]
+ },
"flex": {
"flex-gap-decorations-001.html": [
"b32e2f13d8cdb39c12e26423f882734f2f5bf4fd",
@@ -186616,6 +186780,32 @@
{}
]
],
+ "flex-gap-decorations-020.html": [
+ "6c07493d14d576026e7693b4391fd8baeadbba14",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/flex/flex-gap-decorations-020-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "flex-gap-decorations-021.html": [
+ "c59db4f635b361c4f8f5d77c94129264f560d79b",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/flex/flex-gap-decorations-021-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"flex-gap-decorations-022.html": [
"5f3b512ef76214b3645c329c92bd06ebf23efd9d",
[
@@ -187047,6 +187237,58 @@
{}
]
],
+ "grid-gap-decorations-034.html": [
+ "afe20ef5117b5bc7b628fee1ce86960a9b927adc",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/grid/grid-gap-decorations-034-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-gap-decorations-035.html": [
+ "d2fa76094a96e8b7f786ca903288b1a057c999e3",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/grid/grid-gap-decorations-035-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-gap-decorations-036.html": [
+ "8b1e1e2e1c2d37e9a3367e3d2224b15ded9ebf57",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/grid/grid-gap-decorations-036-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-gap-decorations-037.html": [
+ "656bfee7dfcdd7f568a3ff9bf088c0ece08a57df",
+ [
+ null,
+ [
+ [
+ "/css/css-gaps/grid/grid-gap-decorations-037-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"grid-gap-decorations-38.html": [
"8b87bcd4860ac50a1c2f3de98cec9599bebb77a3",
[
@@ -199035,7 +199277,7 @@
]
],
"conic-gradient-001.html": [
- "37e41094fb28a03d3dbbcd6e88c0c36e1e520b62",
+ "949f955e552d875f6dd8cfade934cae2442332b9",
[
null,
[
@@ -199044,7 +199286,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"css-color-4-colors-default-to-oklab-gradient.html": [
@@ -199077,7 +199335,7 @@
]
],
"gradient-analogous-missing-components-001.html": [
- "0bfd7bb615f7f8d2e5b8b1b1ce11deb3643121d9",
+ "53f14e857c77e397666b135526f576b43d03c41f",
[
null,
[
@@ -199086,11 +199344,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"gradient-analogous-missing-components-002.html": [
- "96038650136fb48d49c3951c2c4433d5fe205650",
+ "881ba723f9153021465535df502b9d18091a34f4",
[
null,
[
@@ -199103,7 +199377,7 @@
]
],
"gradient-analogous-missing-components-003.html": [
- "c4c8995c1ef840f7f42424743643d2aedfd62270",
+ "c97571f54b98be03dfa9cec630b65d6db5763b54",
[
null,
[
@@ -199112,7 +199386,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"gradient-analogous-missing-components-004.html": [
@@ -200520,7 +200810,7 @@
]
],
"gradient-single-stop-none-interpolation.html": [
- "14cd9d763021800a8c4c2898c770bc4015a88f92",
+ "449bde6e25aaaeca8c9072a12295e79bfb0b0236",
[
null,
[
@@ -202126,7 +202416,7 @@
]
},
"infinite-radial-gradient-refcrash.html": [
- "a3a1e7fb069d311162c5cfa427125bac524ffaa2",
+ "a150b619116be7b2c3917347a6794da65b39e9a2",
[
null,
[
@@ -202135,7 +202425,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"linear-gradient-1.html": [
@@ -202301,7 +202607,7 @@
]
],
"multiple-position-color-stop-radial.html": [
- "4b4fd95c4ec21307eee1e2f287f1b0db1d6d1490",
+ "1cb8c5ce03968b283b58bbc1f4d0a92969cf46e5",
[
null,
[
@@ -202310,7 +202616,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-conic-2.html": [
@@ -202401,7 +202723,7 @@
]
],
"normalization-linear-2.html": [
- "e3feeeb49a650beab8783d79ff8003ac011d3842",
+ "9f914cd1240727f367d4607fa158f55be1bb4872",
[
null,
[
@@ -202410,11 +202732,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-linear-degenerate.html": [
- "26647290fb4e891ebe1fa667687ac7cf0f1c3eed",
+ "c485f111a1f26605d12a80d33e0c1fc6f380892e",
[
null,
[
@@ -202423,11 +202761,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-linear.html": [
- "e46645631afa45fc031ffc5fb092d7b6c1e7e660",
+ "8a4e74ddab383beaaf6b8c420da140034ea0c14f",
[
null,
[
@@ -202436,11 +202790,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-radial-2.html": [
- "5ea50a5e035df1807db83ed5a1242253425fc797",
+ "a7ae26865f8f616d773f4cb1f17d3e682b3d5690",
[
null,
[
@@ -202449,11 +202819,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-radial-3.html": [
- "927917ced606cca63ace976c23943fcecab5db64",
+ "c6fcfa8888c7fe933d26f3e5fdaa306871b82bca",
[
null,
[
@@ -202462,11 +202848,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-radial-4.html": [
- "e9d948f062ec70e3e2c73a5211a770facd23b12d",
+ "49a6dbf6a9615249178e0638087ecab915ef40aa",
[
null,
[
@@ -202475,11 +202877,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-radial-degenerate.html": [
- "4fff3ac909a04779a36310fb19c002c6b75d2d3a",
+ "04f04c40bb533d1e42fba31ceedd0dca29b6007d",
[
null,
[
@@ -202488,11 +202906,27 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"normalization-radial.html": [
- "6a510aa52f38a46d91114b5bc0fc3f8b19156097",
+ "e8bab92afb46a43c1b14afd7f0c24371b04f72f2",
[
null,
[
@@ -202501,7 +202935,23 @@
"=="
]
],
- {}
+ {
+ "fuzzy": [
+ [
+ null,
+ [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 40000
+ ]
+ ]
+ ]
+ ]
+ }
]
],
"object-fit-contain-png-001c.html": [
@@ -205737,7 +206187,7 @@
]
],
"tiled-gradients.html": [
- "fdafa1fe99f0db25cca55ce3c13787803e138b49",
+ "46cc842648138b30274b5ee3f18ce7c636e37462",
[
null,
[
@@ -205753,11 +206203,11 @@
[
[
0,
- 255
+ 1
],
[
0,
- 564
+ 40000
]
]
]
@@ -220497,6 +220947,19 @@
{}
]
],
+ "multicol-fill-balance-030.html": [
+ "9fc1f4e859afb74d151d3a4c2d56fd96aacfdc40",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"multicol-fill-balance-nested-000.html": [
"5e466df8077545b4d6474389d296bc26c5b28b86",
[
@@ -234290,6 +234753,19 @@
],
{}
]
+ ],
+ "registered-property-computation-color-005.html": [
+ "9660c934a8569a2692b9932cbf60dea4a8021ed2",
+ [
+ null,
+ [
+ [
+ "/css/css-properties-values-api/registered-property-computation-color-001-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
]
},
"css-pseudo": {
@@ -253843,6 +254319,19 @@
],
{}
]
+ ],
+ "empty-span-001.html": [
+ "4709f34abd543249a19b730a88f02249f4ad46d4",
+ [
+ null,
+ [
+ [
+ "/css/css-text/bidi/empty-span-001-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
]
},
"boundary-shaping": {
@@ -331013,6 +331502,19 @@
{}
]
],
+ "hidpi-invert-filter-background.html": [
+ "1091a3b56a4e74af70e212491782ec94548f74f4",
+ [
+ null,
+ [
+ [
+ "/css/filter-effects/hidpi-invert-filter-background-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"morphology-mirrored.html": [
"f0338e180344f341db60ab0710bdcdb71e8853b7",
[
@@ -335423,6 +335925,19 @@
{}
]
],
+ "has-with-nth-child-sibling-remove.html": [
+ "2c3e83f2bd9c83f02bfaa7ee12a217f2236aafbc",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"lang-pseudo-class-in-has-document-element.html": [
"93ece465dd51c31f67b0f1947747a4a9434fbd28",
[
@@ -335553,6 +336068,19 @@
{}
]
],
+ "negated-last-of-type-invalidation.html": [
+ "40bf8a8f0f4727ffa6b61633e8c2e35dbb812d82",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"negated-negated-first-of-type-when-ancestor-changes.html": [
"7e5376fc31f15febe5db2202e915427ea2e4cc5d",
[
@@ -356021,19 +356549,6 @@
{}
]
],
- "display-css-property-reftest.tentative.html": [
- "e4288cae3b286e8d9b0d9f2ff4c857cd959a460c",
- [
- null,
- [
- [
- "/html/semantics/permission-element/display-css-property-reftest-ref.html",
- "=="
- ]
- ],
- {}
- ]
- ],
"invalid-type-reftest.tentative.html": [
"80f3e793e114fb66f968ac979b6dbd189e3b0b85",
[
@@ -358138,21 +358653,6 @@
]
]
},
- "lifecycle": {
- "set-composited-layer-position.html": [
- "f1a3807d81a7961189feed041ae62a1ffda08f7f",
- [
- null,
- [
- [
- "/lifecycle/set-composited-layer-position-ref.html",
- "=="
- ]
- ],
- {}
- ]
- ]
- },
"mathml": {
"presentation-markup": {
"direction": {
@@ -361731,6 +362231,21 @@
}
}
},
+ "page-lifecycle": {
+ "set-composited-layer-position.html": [
+ "f1a3807d81a7961189feed041ae62a1ffda08f7f",
+ [
+ null,
+ [
+ [
+ "/page-lifecycle/set-composited-layer-position-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ]
+ },
"permissions-policy": {
"experimental-features": {
"vertical-scroll-disabled-scrollbar-tentative.html": [
@@ -372011,7 +372526,7 @@
[]
],
"documentation.yml": [
- "6c92e435c69ae60a2ff73fe482dfc047bb2cb461",
+ "41cf7c331e12f35cf3a9ff893a49f1b8e33bbb66",
[]
],
"epochs.yml": [
@@ -372763,14 +373278,22 @@
[]
],
"util.js": [
- "3e95a936304f3190066f3774e9483394d31a501f",
+ "84507a409e94c58001c0197efb12e63eafab9767",
[]
]
},
+ "rewriter": {
+ "resources": {
+ "iframe-helper.html": [
+ "c9cefebfd74480d2fa83b2079110fa62876a916a",
+ []
+ ]
+ }
+ },
"summarizer": {
"resources": {
"iframe-helper.html": [
- "8db84705a2b87fe958b09d089722fe08700426fa",
+ "2d417e04f624fc2bf10132d84621ef77cc6ac3e1",
[]
]
}
@@ -372782,6 +373305,14 @@
[]
]
}
+ },
+ "writer": {
+ "resources": {
+ "iframe-helper.html": [
+ "bca56e1ecfde55bd3e9c3ef466810d00ad977ae8",
+ []
+ ]
+ }
}
},
"ambient-light": {
@@ -376143,6 +376674,14 @@
[]
]
},
+ "iframes": {
+ "resources": {
+ "dialog-prevents-close.html": [
+ "580e5220dae235bf69cd69e51c45f5660a910e3c",
+ []
+ ]
+ }
+ },
"resources": {
"helpers.js": [
"ad80c28847f3a6802a56527e11d89a2829ecc8f9",
@@ -376745,7 +377284,7 @@
[]
],
"worker-support.js": [
- "39caeb6192f6fee2a9b71d8ea78a1cf9e64e512d",
+ "72e1fbfb20478ea550504a7af9b84bf63ff1e40c",
[]
]
}
@@ -396959,7 +397498,7 @@
[]
],
"helper_iframe.sub.html": [
- "3bd1843d5742dcbbbeca6318c4c9793d3532a7a2",
+ "d5cae23d160ef8ac5a57820eee1d8239ad637532",
[]
],
"helpers.js": [
@@ -415223,7 +415762,7 @@
[]
],
"anchor-center-visibility-change-ref.html": [
- "66bf9083c3a24e6adad0ad724a1e54ccbe6f568b",
+ "bc9872a9093680d8584df0e923c658ce589ef271",
[]
],
"anchor-position-005-print-ref.html": [
@@ -415419,6 +415958,10 @@
"a4feab487c5c9262e6c71d2f16f4bb83384cdcbe",
[]
],
+ "position-area-visibility-change-ref.html": [
+ "87e1804940900132e8b8a062e096924585a5b227",
+ []
+ ],
"sticky-anchor-position-invalid-ref.html": [
"c4a5dd37354f61c66b0e2e53847b8fcc16112fc3",
[]
@@ -417694,6 +418237,10 @@
"8963c0ca2939c4036d9505461c9772b803b586f2",
[]
],
+ "corner-shape-overflow-clip-margin-ref.html": [
+ "2c1ccf86cc6ae5ec138b741d83dfb31347de61c8",
+ []
+ ],
"corner-shape-square-ref.html": [
"4576240ef3288a954c9a627cbafd640eacd95444",
[]
@@ -431600,6 +432147,10 @@
"ca072086c415b058264e495c46cb4a692d8a0684",
[]
],
+ "test-synthetic-bold-notref.html": [
+ "4a952acb46fb5b0f5681176ee3db32758413c48c",
+ []
+ ],
"test-synthetic-italic-2-ref.html": [
"d3165b681c86dbe8b0aff6d91df56a9369d2127b",
[]
@@ -431608,6 +432159,10 @@
"a0721426016c949369ae0114211136f45ce51b27",
[]
],
+ "test-synthetic-italic-notref.html": [
+ "3684f3ae804aa109f2da5188556cd3b36ffa2fc9",
+ []
+ ],
"variation-sequences-ref.html": [
"a44f18bb3e1f3584aa9b3407a0b7033dddd234aa",
[]
@@ -431878,6 +432433,10 @@
"gap-decorations-002-ref.html": [
"42c5ef128b47fc9cdd14c9ce4f8abdffb209d94e",
[]
+ ],
+ "gap-decorations-003-ref.html": [
+ "52e45c4f65f01e5eb98a98590788a0af7bcf7230",
+ []
]
},
"flex": {
@@ -431944,6 +432503,14 @@
"flex-gap-decorations-018-ref.html": [
"644a409bd977acb91812666ac2f9a6e1c1b66830",
[]
+ ],
+ "flex-gap-decorations-020-ref.html": [
+ "b708a78a3472f1a903febe26cbec09da22db1f19",
+ []
+ ],
+ "flex-gap-decorations-021-ref.html": [
+ "1e28d73b4e2ce48d62880be1aa66e26f511ab7b1",
+ []
]
},
"grid": {
@@ -432062,6 +432629,22 @@
"grid-gap-decorations-033-ref.html": [
"e26143a6b93e9fdd53d4055234d89e40d98dc2af",
[]
+ ],
+ "grid-gap-decorations-034-ref.html": [
+ "4e964879e795ec6877b6564c04575d296aa4d94b",
+ []
+ ],
+ "grid-gap-decorations-035-ref.html": [
+ "851360a99a4bb9262e24368fed9a81d34f066a45",
+ []
+ ],
+ "grid-gap-decorations-036-ref.html": [
+ "29ed684d85f72c24fcf6e67187c834f5624eeda3",
+ []
+ ],
+ "grid-gap-decorations-037-ref.html": [
+ "4a2ee5bd5c6fbdb25e5a70eac56a9b0bbac5d56f",
+ []
]
},
"multicol": {
@@ -442684,7 +443267,7 @@
[]
],
"scroll-initial-target-with-text-fragment-navigation-target.html": [
- "aea8e120c15af61717f79b52ddd2f5c957393725",
+ "8b3c168af8a101a2421563babcf24c476201a534",
[]
],
"stash.py": [
@@ -445007,6 +445590,10 @@
[]
],
"bidi": {
+ "empty-span-001-ref.html": [
+ "ce987d65bf4820f67bb72095faca47bf58907f91",
+ []
+ ],
"reference": {
"bidi-lines-001-ref.html": [
"ab13fef116c4eba70a09e01558425bb508173d90",
@@ -451569,7 +452156,7 @@
[]
],
"WEB_FEATURES.yml": [
- "a10f70297916abe13376013b18ae4b2f7cd4dec5",
+ "e699a40acddb78a7ef04314918aa839519eaa3f2",
[]
],
"accent-color-checkbox-checked-001-notref.html": [
@@ -451744,7 +452331,7 @@
],
"parsing": {
"WEB_FEATURES.yml": [
- "b4ae339c2f3301bc1845c39923c05095d9e48499",
+ "3be770b3a51dcebaca35d4a92e1f0b4a2e8004b9",
[]
]
},
@@ -453729,7 +454316,7 @@
[]
],
"content-with-transform-ref.html": [
- "8c2b65e63e78c202c77aee02c0797ef81c25881c",
+ "10166b16a8c4ab41147b02783b20ec59d3e77d5c",
[]
],
"content-with-transparent-background-ref.html": [
@@ -453869,7 +454456,7 @@
[]
],
"inline-with-offset-from-containing-block-ref.html": [
- "4a66af4ece26abd69a41840319783f86001746d0",
+ "2eebf8cf5966409a62ec3aba3c32231adbe79f42",
[]
],
"intrinsic-aspect-ratio-ref.html": [
@@ -458194,6 +458781,10 @@
"d281f2a852ed802161815b9c88ac82c5d60caace",
[]
],
+ "hidpi-invert-filter-background-ref.html": [
+ "ea823309771d02a3511394a0c3e3e8ed759a7a57",
+ []
+ ],
"parsing": {
"WEB_FEATURES.yml": [
"cd7e6695d4de7ff1c83fa704e84ce272cbcc28c2",
@@ -460381,7 +460972,7 @@
[]
],
"iframe.html": [
- "3ec761e08a6266ab24fcea357d866f76d8c9ed2f",
+ "d737dcfc091b7873863e46ba5bdb5e2bef07e2f4",
[]
]
},
@@ -463554,6 +464145,22 @@
"57b6f1e32182865fc12eecc4226a0740e3d0535c",
[]
],
+ "account_picture.py": [
+ "ae453086bc0fe9c238e61894ba7af6ced7bcdadf",
+ []
+ ],
+ "account_picture_get_count.py": [
+ "91c3601fbdc740813d8c98cf7e408b596e1ee3a7",
+ []
+ ],
+ "account_picture_uncached.py": [
+ "51289f37b7c94e6ad4330890155dca3fe5405a85",
+ []
+ ],
+ "account_picture_uncached_get_count.py": [
+ "e2adbd517b8e2475434be71a625ce98997db8518",
+ []
+ ],
"accounts.py": [
"c0117862816ff4668b6dd9416633bee6eb9af227",
[]
@@ -463617,7 +464224,7 @@
]
},
"fedcm-helper.sub.js": [
- "4337adf9f87b045f93d6dbb33398d38f2fce72cf",
+ "b6bbbc19e21bca496df255cf16376c6443f8b1e2",
[]
],
"fedcm-helper.sub.js.headers": [
@@ -463653,7 +464260,7 @@
[]
],
"keys.py": [
- "6b7d67e21e7eea7927a40ab094847b7224d49985",
+ "8ced364116b1c5d55be18b7f88e358b28bcca912",
[]
],
"lfedcm-helpers.js": [
@@ -463684,6 +464291,10 @@
"ed984a42387198f95b2510041e5f73758541e9d3",
[]
],
+ "manifest_accounts_push.json": [
+ "721fe05f94066fc17931573e2d6bf599691b7a3f",
+ []
+ ],
"manifest_broken_login.json": [
"d42bf8fb2692c50648ad412b46014a1a8c60e730",
[]
@@ -463777,7 +464388,7 @@
[]
],
"mark_signedout.sub.headers": [
- "69157b3a371e369df585331a2479144fee444f5c",
+ "5ddbacf85f4641b6ea65479106687bc976d92d65",
[]
],
"no-cors.py": [
@@ -463788,8 +464399,16 @@
"fad93088db5b9204c890fea871574c8b7d1ee4f8",
[]
],
+ "push_accounts": [
+ "ea7eb12beab9f8d38fb48ccf58cfece00a0c60c2",
+ []
+ ],
+ "push_accounts.sub.headers": [
+ "d560fade5a0e4237f751b0c90a87fc25f92aa14a",
+ []
+ ],
"request-params-check.py": [
- "08c28e32b7942d6db83f7b9c2e4664c9cf47987f",
+ "f5b48d9b05386292295e5df0b6b80e24dd1c42bf",
[]
],
"resolve.html": [
@@ -468110,11 +468729,11 @@
[]
],
"generic-sensor-iframe-tests.sub.js": [
- "a63729ec2e62ed5ca6aab02278b6d0f7d38fd437",
+ "764eef06c404f44d41dd5659bdd8ad9f5eebc9e3",
[]
],
"generic-sensor-tests.js": [
- "970dc3314c3cb5005e0222ef8e74f0dd794cf857",
+ "894fc7d2ed0b94985ef74d172d11c8b2e6c18f3e",
[]
],
"resources": {
@@ -468123,7 +468742,7 @@
[]
],
"iframe_sensor_handler.html": [
- "80cdcf7c0d02ffe123b39b86cd2b9cdad5aee7cf",
+ "f8a78aa8b09cf2f0d5e820e56a727692f80b0d21",
[]
]
}
@@ -473834,7 +474453,7 @@
[]
],
"noopener-helper.js": [
- "6dd2c9bc1c9ac2625be861246160e1a4dd7c4088",
+ "9a4097b21e4528fb8491392ddbf4b54c27343098",
[]
],
"popup-test.js": [
@@ -474485,7 +475104,7 @@
}
},
"elements-embedded.js": [
- "c5b4520cc6e776cf49a15bc983dc1d5220134419",
+ "c10461ed6e8c079d53ea9940acc12e9aeae68f06",
[]
],
"elements-forms-weekmonth.js": [
@@ -474525,11 +475144,11 @@
[]
],
"new-harness.js": [
- "49f8e40ad7d23f456e110d57b7a33b05364493e9",
+ "ad6214fb64f60fb4197dd0059a2e8cec3f3a13ec",
[]
],
"original-harness.js": [
- "89a80670334f0559f0f01074adb0487b14d574e6",
+ "6e48a562a6d38fbe63ec268b404f1ee82a97f705",
[]
],
"reflection-original.html": [
@@ -474537,7 +475156,7 @@
[]
],
"reflection.js": [
- "eeecd450fca8139e924affb298e7feb1a1fb46fb",
+ "3423c9358954fddec9884241769ddc11bf6cdb55",
[]
],
"render-blocking": {
@@ -480920,6 +481539,10 @@
]
},
"the-datalist-element": {
+ "WEB_FEATURES.yml": [
+ "c5f2a8811dda16b13199adde7b81e4659f69d57d",
+ []
+ ],
"input-text-focused-ref.html": [
"f78a937f17815a6a063a7465bf53fe402cdb671f",
[]
@@ -481066,6 +481689,10 @@
]
},
"the-meter-element": {
+ "WEB_FEATURES.yml": [
+ "944746a8eece9a2f3ecfd172ff37b98b0a785bb9",
+ []
+ ],
"meter-min-rendering-ref.html": [
"f253945968e49902d1f2c2d60d9d8cd230166c6b",
[]
@@ -481105,6 +481732,12 @@
[]
]
},
+ "the-progress-element": {
+ "WEB_FEATURES.yml": [
+ "95c7b887c3770a821d37849b7cce77daf81ebf44",
+ []
+ ]
+ },
"the-select-element": {
"WEB_FEATURES.yml": [
"9695c9529424d612300127b3350254e15a05c27e",
@@ -481793,10 +482426,6 @@
"462f346edf591e8fa76b52191f00bc2bbe3bbfcc",
[]
],
- "display-css-property-reftest-ref.html": [
- "aa5ffe07a952744499c81039072e49f0a8ea59d4",
- []
- ],
"invalid-type-reftest-ref.html": [
"359872ea61358720c36fe2f0de282009b49f88ac",
[]
@@ -481899,6 +482528,10 @@
"popover-utils.js": [
"7878b125f2f6b1f6d39d1972f7387e8014b6dcf8",
[]
+ ],
+ "toggle-event-source-test.js": [
+ "93ecd270fac574d7a4928e54b71ded77540421e7",
+ []
]
}
},
@@ -486046,8 +486679,12 @@
"d074292053b6d580efda36155c1d82af699494bc",
[]
],
+ "initial-color.html.ini": [
+ "5759f761c6f95aa7113ae07f9cbc247a36832b99",
+ []
+ ],
"non-local-ports.sub.window.js.ini": [
- "87d8cd43c41edcc20ed69f7cafb4de366fef27ff",
+ "36a803d3ed7678cac74bd89b64ec041b425bb887",
[]
]
},
@@ -486326,6 +486963,14 @@
]
}
},
+ "bless.html.ini": [
+ "2feff7063f80c15120f6a15b77543ffd4166187b",
+ []
+ ],
+ "click-multiple.html.ini": [
+ "5c005edd40a4bc972409493b735c1f2f7c4ebdf7",
+ []
+ ],
"click_iframe_crossorigin.sub.html.ini": [
"aa94652ad763060f10aba1e03af806035d29ecd1",
[]
@@ -486878,7 +487523,7 @@
[]
],
"crash-reporting.idl": [
- "a6737ca8482e1d67c40d6d3618424969fa680f96",
+ "6eaee138a828f7749026458265e7db598822330f",
[]
],
"credential-management.idl": [
@@ -487058,7 +487703,7 @@
[]
],
"digital-credentials.idl": [
- "e4ebb3b3e8621b668a18dcdeed7974e6446234e0",
+ "60b63975640c5a131c802ac459d08eb938446df8",
[]
],
"digital-goods.idl": [
@@ -487582,7 +488227,7 @@
[]
],
"speech-api.idl": [
- "0e07b4619a5b80e901f0b8c17a208f9077f9187f",
+ "94a416f262b361e326c5b3c89fa8d160c1118b48",
[]
],
"storage-access.idl": [
@@ -487621,6 +488266,10 @@
"19f55156a6e3a40c8a6c78a303754c1c8ace58de",
[]
],
+ "translation-api.idl": [
+ "6cbad38938a15f373936cf760a9b30b8506bd5e0",
+ []
+ ],
"trust-token-api.idl": [
"9b74290da724b62fb91b3f5532b689cf70a10045",
[]
@@ -487794,7 +488443,7 @@
[]
],
"webnn.idl": [
- "37fcc32501efbeb38c9686a8fc96e1ce062eb30a",
+ "8d0e485bc76e49a616847f305d0b81cc5cce0589",
[]
],
"webrtc-encoded-transform.idl": [
@@ -488254,48 +488903,8 @@
]
}
},
- "lifecycle": {
- "META.yml": [
- "abd5e0f6ed6cc07042968abb4465f1c84d0e83d4",
- []
- ],
- "resources": {
- "beacon.py": [
- "09915ffbcf045ad65d69d564b72736dc5a20365c",
- []
- ],
- "child.html": [
- "708bbfe02dcefb1173a5b15df7627d01739a5e43",
- []
- ],
- "subframe.html": [
- "2f1d70a80a792401891d93f6ddebaea0876400b3",
- []
- ],
- "subframe_worker.html": [
- "350d27437a6465644b3c3149c9e2ad86ff8d806e",
- []
- ],
- "subframe_worker1.js": [
- "2d13e89065af224f08e2749b1150937c244db7a2",
- []
- ],
- "subframe_worker2.js": [
- "32d2741331e5cfed0c4492a55b2b7085d2c52603",
- []
- ],
- "window.html": [
- "58181f32da7337773a0c420ff929631d2ba9ad1d",
- []
- ]
- },
- "set-composited-layer-position-ref.html": [
- "600de56d608e8090849f62ab1c346c33ead33ac5",
- []
- ]
- },
"lint.ignore": [
- "955e5df49077cab63e762988714e1319d551089d",
+ "b39180815c2c6138dedcec0e40ee392d657cdb60",
[]
],
"loading": {
@@ -491554,7 +492163,41 @@
},
"page-lifecycle": {
"META.yml": [
- "8036af19bb9df20e30872a6c954ca4f23dbe9c8c",
+ "abd5e0f6ed6cc07042968abb4465f1c84d0e83d4",
+ []
+ ],
+ "resources": {
+ "beacon.py": [
+ "09915ffbcf045ad65d69d564b72736dc5a20365c",
+ []
+ ],
+ "child.html": [
+ "708bbfe02dcefb1173a5b15df7627d01739a5e43",
+ []
+ ],
+ "subframe.html": [
+ "2f1d70a80a792401891d93f6ddebaea0876400b3",
+ []
+ ],
+ "subframe_worker.html": [
+ "350d27437a6465644b3c3149c9e2ad86ff8d806e",
+ []
+ ],
+ "subframe_worker1.js": [
+ "2d13e89065af224f08e2749b1150937c244db7a2",
+ []
+ ],
+ "subframe_worker2.js": [
+ "32d2741331e5cfed0c4492a55b2b7085d2c52603",
+ []
+ ],
+ "window.html": [
+ "58181f32da7337773a0c420ff929631d2ba9ad1d",
+ []
+ ]
+ },
+ "set-composited-layer-position-ref.html": [
+ "600de56d608e8090849f62ab1c346c33ead33ac5",
[]
]
},
@@ -494937,6 +495580,10 @@
"9c829d3c8885bb9b594e7096a878166e07f3e278",
[]
],
+ "WEB_FEATURES.yml": [
+ "989f1fc7e45c3c1d04746a4cf627981a8652d4d2",
+ []
+ ],
"resources": {
"child.html": [
"4d6895125a2acaad00cc2bc849e026a2632dd88e",
@@ -495624,7 +496271,7 @@
]
},
"idlharness.js": [
- "d52ba9fd3c417955f5cb6eb68f96113057128318",
+ "2eb710c1827cda28b7bf75acd5b3a3d6c67d66fc",
[]
],
"idlharness.js.headers": [
@@ -500363,7 +501010,7 @@
[]
],
"soft-navigation-helper.js": [
- "a29978c8760495ffccbd6fc56d62f4625d89334d",
+ "c9f2b41b552855d6cbd049008c314fe4c953464b",
[]
]
}
@@ -500454,7 +501101,7 @@
[]
],
"utils.sub.js": [
- "d4efc2dc7dce21e1da25842aceda4c3fc50227da",
+ "adb15d4ea9e76759074e0c7cc1b8a56c0f3a046d",
[]
]
},
@@ -502943,7 +503590,7 @@
[]
],
"requirements_build.txt": [
- "60c09170a98e2d16fd3e499962f59b0df8089fd3",
+ "4fb858bbd5fb9ce13886a59ba7338bedc7c3e913",
[]
],
"requirements_macos_color_profile.txt": [
@@ -502951,7 +503598,7 @@
[]
],
"requirements_tc.txt": [
- "ada75c2f761904412048f3525f3010b658d174f9",
+ "e1d74e856b1c2aaccc2d9e76d1b23bb906cb9624",
[]
],
"run_tc.py": [
@@ -503091,7 +503738,7 @@
[]
],
"requirements.txt": [
- "b275ccfd8f1505c29cd1f29fc161e3b50f9af358",
+ "be30f18fb3ae6246996fec73a65a45edfffca81c",
[]
],
"retry.py": [
@@ -503383,7 +504030,7 @@
[]
],
"download.py": [
- "8527fb232ac73ad8749a453e95d9d246b2695389",
+ "8b119abacecf69fe2d5da80aea8db46406c3d60f",
[]
],
"item.py": [
@@ -503411,7 +504058,7 @@
[]
],
"sourcefile.py": [
- "4e74fb207709bb8f8f79df3fc91847b2ec0fe915",
+ "8682c233e8898ae8eb26ca2a3ce260bdab4fb5e2",
[]
],
"spec.py": [
@@ -503534,7 +504181,7 @@
[]
],
"requirements.txt": [
- "cf39afa6b4c0ab83337d7b8518a14e39ece19a1b",
+ "1a151295165dcfd31ab6cd0a74d2c8d8afd90a08",
[]
],
"tests": {
@@ -503550,7 +504197,7 @@
}
},
"mypy.ini": [
- "e05220f4bbee101d23993a71a83db856c955c28c",
+ "22259b03aab75194ac7396c2fe241d0071fdc639",
[]
],
"pytest.ini": [
@@ -503562,7 +504209,7 @@
[]
],
"requirements_mypy.txt": [
- "5edf2d9614d60e520aa53406d450dd6dc8344114",
+ "a846a21ac4f4efacdfa7cb3c93ddf3280df5c934",
[]
],
"requirements_pytest.txt": [
@@ -503570,7 +504217,7 @@
[]
],
"requirements_tests.txt": [
- "ca00b8f1f9835eea866a0462962b705a63366de6",
+ "663b005072985b054a0ee81a4040e8b1fb888ee3",
[]
],
"runner": {
@@ -503637,7 +504284,7 @@
[]
],
"serve.py": [
- "d86e66a3743a6d98c759bf189f31f1798bf8d1d7",
+ "8343a54bcd09ab05ba1c1f7878c0e4d8200ded8c",
[]
],
"test_functional.py": [
@@ -513477,7 +514124,7 @@
[]
],
"requirements.txt": [
- "3bb476fd968b2d754dcadb34b5331db6bf8b7712",
+ "5404a6916bd6c3e59d721f32947da91420d79201",
[]
],
"resources": {
@@ -513907,7 +514554,7 @@
[]
],
"transport.py": [
- "841b9d0933d1388e57ffee4ce2a19895f4fe8efa",
+ "7423155bf3a12cf2c55dc4ab53c56665b9c90dea",
[]
],
"undefined.py": [
@@ -513952,7 +514599,7 @@
[]
],
"capsule.py": [
- "fc8183a65f03a01a3127f342ce65120145d21d17",
+ "1708bd2cea3ad02b076b4ca61a0f3a40df38291e",
[]
],
"handler.py": [
@@ -513964,7 +514611,7 @@
[]
],
"webtransport_h3_server.py": [
- "2dd8f645551d635a1f39761f9d366757adfdfbb5",
+ "d2a31a93c9e8a6e5be2685710e509ed2862d8c8c",
[]
]
},
@@ -513983,7 +514630,7 @@
[]
],
"browser.py": [
- "0ac1b982ed07808ea20aa452fd8c3971e5fbfbdb",
+ "d38017c324fb0f7e4b9be191cc3888b8a9175fcb",
[]
],
"commands.json": [
@@ -514011,7 +514658,7 @@
[]
],
"requirements.txt": [
- "d80d9fc2a3a2b61bfeaee0004be49f7a69cf8f63",
+ "ea6498ce15f5097b8b6004b2965a421b26d0f014",
[]
],
"requirements_android.txt": [
@@ -514022,6 +514669,10 @@
"9da7570da49bbe87171a2e23eb2c94b0113993a4",
[]
],
+ "requirements_metadata.txt": [
+ "3052e99b4fcef90a0a36d4070489bc55535da141",
+ []
+ ],
"revlist.py": [
"ef8dbf043fee0df11e90d88e21af534f1f6e6c3a",
[]
@@ -514187,7 +514838,7 @@
]
},
"requirements.txt": [
- "97b569379553f692f8420efc98504edbb82f84dc",
+ "6605de2deda53dff469509875052070c8e81e42e",
[]
],
"requirements_chromium.txt": [
@@ -514195,7 +514846,7 @@
[]
],
"requirements_firefox.txt": [
- "59a9cd7ba3e67999308be1e8bab630dfec5168e0",
+ "2b98c0a65d4cafd0b0b5394ecd3bb148acf4bab4",
[]
],
"requirements_opera.txt": [
@@ -514203,11 +514854,11 @@
[]
],
"requirements_safari.txt": [
- "0704b2dbf6837b034f9bb1e45b51b81e12757177",
+ "177446e1038e25b60109e2c640e3dea24c75b1e9",
[]
],
"requirements_sauce.txt": [
- "f6f1581d858b3de002c3972b854d0323acd95a7e",
+ "c7bdc25bf5ee33d257856a3d2cfdc1fbb953b5da",
[]
],
"setup.py": [
@@ -514341,7 +514992,7 @@
[]
],
"asyncactions.py": [
- "8397d7838a3d6bd45e28dc613322d00ff8f2aebb",
+ "9f7f313f203541d09e9e1ad7b2e7e25380c1b02d",
[]
],
"base.py": [
@@ -514389,7 +515040,7 @@
[]
],
"protocol.py": [
- "16eb3cbb4a528ac9e4fc4897aa36f2a58e6d68ec",
+ "6b9a0de9bb24c1e4fde56fb88506a9d6579114b7",
[]
],
"pytestrunner": {
@@ -514785,7 +515436,7 @@
]
},
"setup.py": [
- "d66769f06303e92087567ce93443d20cd74bd961",
+ "670c3dfcea6ba9ed8b92ac64e158be46c6ffebbf",
[]
],
"tests": {
@@ -514991,7 +515642,7 @@
[]
],
"test_pipes.py": [
- "c11577acb5041fdde7deb82cdb2ed85cbca5adb8",
+ "e868b6121016f5528d952a6cd3f534535a1d4d80",
[]
],
"test_request.py": [
@@ -515130,7 +515781,7 @@
[]
],
"ws_h2_handshake.py": [
- "ab1ab958a03bba94030d61c085a448c00f08a25c",
+ "99d4dbeac4b3f5be4c98edcd779013ba58f25c97",
[]
]
}
@@ -517298,6 +517949,18 @@
[]
],
"resources": {
+ "audio-worklet-source-phase.js": [
+ "3a07777b1e5a9008156e6b22e4e304f0724c47c0",
+ []
+ ],
+ "cross-origin-wasm-dynamic-source-phase-import.sub.js": [
+ "c9d75f15ff28939779f0f98680868aef42ebfd5c",
+ []
+ ],
+ "cross-origin-wasm-static-source-phase-import.sub.js": [
+ "2bf64c00093a7ac760834a46b40787007f68f8ad",
+ []
+ ],
"execute-start.wasm": [
"ecfdda1f9af82c65ac7276449161288990a31df7",
[]
@@ -517427,11 +518090,11 @@
[]
],
"worker-helper.js": [
- "277bb4c1ea5b798474576123ad011751d8611490",
+ "537781bef78021dcbe06005f0b938cc4826221ed",
[]
],
"worker-source-phase.js": [
- "e1c2703899a50d1e31f73c2a0b76a27c5d6552ea",
+ "3be7479ddec52906e0f1b44abe778e2b255be167",
[]
],
"worker.js": [
@@ -518963,7 +519626,7 @@
},
"browsing_context": {
"__init__.py": [
- "8987e12a967162cfad502cf81429e4e4d74c3023",
+ "618d2c1a23c6bf7bfb57de8bdefae6b5c54d195d",
[]
],
"activate": {
@@ -520475,11 +521138,11 @@
},
"resources": {
"utils.js": [
- "9d5cfc70c10187743807096421975a099f22afc9",
+ "c562b3028bdecd3cd9cb9afacd658132ca3b1420",
[]
],
"utils_validation.js": [
- "77a6d79205b5365d9a92af7d1a2d39df144a0f3f",
+ "3f8687b88f17a00eb29cd28d0cc4a81c75466b7c",
[]
]
},
@@ -551524,11 +552187,14 @@
]
],
"Accelerometer-iframe-access.https.html": [
- "56005696a7f5fb70ed5dd2c25fd5db75a4bf1c0c",
+ "887c6139061f3823331a50f47fd111c46ed01f72",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -551541,11 +552207,14 @@
]
],
"Accelerometer.https.html": [
- "d422fef7264a6e301ca3f583389d632e7776a4c9",
+ "6d6dae5c6198df4792d8d61026d7f4c81c2f6e5e",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -551558,21 +552227,27 @@
]
],
"GravitySensor.https.html": [
- "0f98f3e00dec4038126d1451905ac9d77d90b22a",
+ "c632f0ffe3147612df370e4cf731870f666e8424",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
],
"LinearAccelerationSensor.https.html": [
- "91035cc9628bad32f411fdc6139915931a5641fb",
+ "c8883b4c8a1c35bb0dadc1b4f2f0e3d569a486e0",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -551887,9 +552562,148 @@
]
]
},
+ "rewriter": {
+ "rewriter-abort.tentative.https.window.js": [
+ "0eb716f398bdd08e7e853918506fdf58028eebe0",
+ [
+ "ai/rewriter/rewriter-abort.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Rewriter Abort"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "rewriter-availability-available.tentative.https.window.js": [
+ "a2117486e236d31a424f1920ba468d7531ee5775",
+ [
+ "ai/rewriter/rewriter-availability-available.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Rewriter Availability Available"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "rewriter-availability.tentative.https.window.js": [
+ "e966b5df31ed5c0cb337e8736ae07cabc85dfdf4",
+ [
+ "ai/rewriter/rewriter-availability.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Rewriter Availability"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "rewriter-from-detached-iframe.tentative.https.window.js": [
+ "d7c473438cf89e8a006963f7ab9df2ac7229d079",
+ [
+ "ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Rewriter Detached Iframe"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "rewriter-iframe.tentative.https.html": [
+ "202ee780af75312d0c5835b3ec311b9ac9db696a",
+ [
+ null,
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ]
+ ],
+ "rewriter.tentative.https.window.js": [
+ "da3f002a82b74c921f6e428298d4bbf8269f77a8",
+ [
+ "ai/rewriter/rewriter.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Rewriter"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ]
+ },
"summarizer": {
"summarizer-abort.tentative.https.window.js": [
- "64595ea930c9e21b8044a281c2f9f4d467478772",
+ "14c89056dfb3e5d31ae70bcf81e7e93aa6a97f9e",
[
"ai/summarizer/summarizer-abort.tentative.https.window.html",
{
@@ -551899,8 +552713,8 @@
"Summarizer Abort"
],
[
- "global",
- "window,worker"
+ "script",
+ "/resources/testdriver.js"
],
[
"script",
@@ -551911,7 +552725,7 @@
]
],
"summarizer-availability-available.tentative.https.window.js": [
- "31c21ca777fb09fc8058b57d5d8230d3f3798410",
+ "f569cb43b0fccc7a370d67447ac8545a492b4108",
[
"ai/summarizer/summarizer-availability-available.tentative.https.window.html",
{
@@ -551922,6 +552736,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -551934,7 +552752,7 @@
]
],
"summarizer-availability.tentative.https.window.js": [
- "8691765f6933a576711282750b0d7ebca99e98e8",
+ "85282959f9ea22eb1bad45ef833f0698805bb8bd",
[
"ai/summarizer/summarizer-availability.tentative.https.window.html",
{
@@ -551945,6 +552763,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -551957,7 +552779,7 @@
]
],
"summarizer-create-available.tentative.https.window.js": [
- "c7e27d9766bee9b62d7b8463654dfea7536cb338",
+ "1f108ddd021cdc7c40a550ae457bc608bdd5c866",
[
"ai/summarizer/summarizer-create-available.tentative.https.window.html",
{
@@ -551968,6 +552790,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -551980,7 +552806,7 @@
]
],
"summarizer-create.tentative.https.window.js": [
- "328cceefefb11dab0844cfee5773a5194aabd52e",
+ "d9df70cc2e796389002d24ec579b0954dca5a601",
[
"ai/summarizer/summarizer-create.tentative.https.window.html",
{
@@ -551991,6 +552817,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -552003,14 +552833,17 @@
]
],
"summarizer-iframe.tentative.https.html": [
- "219811c8831e4008726a6507810405e69756fbd6",
+ "9de80e1fd916dfac64554ea15d1c91727a8d3859",
[
null,
- {}
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
]
],
"summarizer-measureInputUsage.tentative.https.window.js": [
- "ce9745acf173c8d94a52427446460a47c6fbb378",
+ "8368096f1f3fe09eb8884ee8e88d2f55720dccf5",
[
"ai/summarizer/summarizer-measureInputUsage.tentative.https.window.html",
{
@@ -552021,6 +552854,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -552033,7 +552870,7 @@
]
],
"summarizer-summarize-streaming.tentative.https.window.js": [
- "dbf41cdadbc679e68279886506660262952f0b5e",
+ "59aa01aeb312ce90958708a089fa33499b4ea32e",
[
"ai/summarizer/summarizer-summarize-streaming.tentative.https.window.html",
{
@@ -552044,6 +552881,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -552056,7 +552897,7 @@
]
],
"summarizer-summarize.tentative.https.window.js": [
- "62a780a3fc7960f30b2f4ab6beab89f9e570699f",
+ "c54052f8b36157e22dc8b083137d0ab4adbd2d70",
[
"ai/summarizer/summarizer-summarize.tentative.https.window.html",
{
@@ -552067,6 +552908,10 @@
],
[
"script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
"../resources/util.js"
],
[
@@ -552104,7 +552949,7 @@
]
],
"translator.optional.https.window.js": [
- "96eca09d28bd61ccc4d31b746216f1f252d0bf3b",
+ "2a4c5a6c5dd3cd8b2fea087aa910428c2a3041bf",
[
"ai/translator/translator.optional.https.window.html",
{
@@ -552142,6 +552987,145 @@
}
]
]
+ },
+ "writer": {
+ "writer-abort.tentative.https.window.js": [
+ "bb877f6d73b9747e85df0022d6d325f1ecc8017d",
+ [
+ "ai/writer/writer-abort.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Writer Abort"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "writer-availability-available.tentative.https.window.js": [
+ "0e3106a14c2ef4880a14132d74a9ed39ca97b4ac",
+ [
+ "ai/writer/writer-availability-available.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Writer Availability Available"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "writer-availability.tentative.https.window.js": [
+ "a68b7d35e64731fe561aa1792cecb50da935b70d",
+ [
+ "ai/writer/writer-availability.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Writer Availability"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "writer-from-detached-iframe.tentative.https.window.js": [
+ "c63d8bb77c953e1f04bbab2987e28f6dd0cc5e1a",
+ [
+ "ai/writer/writer-from-detached-iframe.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Writer Detached Iframe"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ],
+ "writer-iframe.tentative.https.html": [
+ "004ba9ea307d6eefa52108ffb623bbbfe1e90be2",
+ [
+ null,
+ {
+ "testdriver": true,
+ "timeout": "long"
+ }
+ ]
+ ],
+ "writer.tentative.https.window.js": [
+ "6606f2174486f977d25065659638c788b822bdda",
+ [
+ "ai/writer/writer.tentative.https.window.html",
+ {
+ "script_metadata": [
+ [
+ "title",
+ "Writer"
+ ],
+ [
+ "script",
+ "/resources/testdriver.js"
+ ],
+ [
+ "script",
+ "../resources/util.js"
+ ],
+ [
+ "timeout",
+ "long"
+ ]
+ ],
+ "timeout": "long"
+ }
+ ]
+ ]
}
},
"ambient-light": {
@@ -552181,11 +553165,14 @@
]
],
"AmbientLightSensor-iframe-access.https.html": [
- "765c1bee1f818924af037d8eb4e963198a464504",
+ "c45804a51f757af0aa2a09d76497786f9e2ff8df",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
@@ -552197,11 +553184,14 @@
]
],
"AmbientLightSensor.https.html": [
- "f2ed655082ed383b1c16bb5bec9f67e0950836f5",
+ "65049ed826fd82d5e8065aca717f76db6d3359e7",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -561383,7 +562373,16 @@
]
],
"async-navigator-clipboard-basics.https.html": [
- "f7aed80b17ebd0af8f4c255ef83dfc85a7eb71ce",
+ "b71d6665bcba982b9d686f3b1d6115269feb60e3",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "async-navigator-clipboard-change-event.tentative.https.html": [
+ "37e2e6a7bde3ef85de09691e5fa4fba4a644b310",
[
null,
{
@@ -561409,6 +562408,15 @@
}
]
],
+ "async-navigator-clipboard-write-domstring.https.html": [
+ "a16f358f46d4d555ade6a96eb5f14f73c732e1c5",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"async-navigator-clipboard-write-multiple.tentative.https.sub.html": [
"c310203503f3530b881b866b7fc2f8b8ade5b371",
[
@@ -561870,6 +562878,35 @@
{}
]
],
+ "iframes": {
+ "dialog-same-origin-nn.html": [
+ "250fbf7e5f733b89449203b7b881c8f710898dbd",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "dialog-same-origin-ynn.html": [
+ "b5cfab5c5d91315103796e783e1187757932e3db",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "dialog-same-origin-ynyn.html": [
+ "4f55e9b24aa61d026603f2448f81dfe1b9858a8e",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ]
+ },
"inside-event-listeners.html": [
"93996fb5fee32861905dcca605d33f22a369cf94",
[
@@ -564547,7 +565584,7 @@
},
"compute-pressure": {
"compute_pressure_basic.https.window.js": [
- "a120f97a403621c9baa6c2769f5989f7bfadd43d",
+ "a13d1766c533604a60dbb42b9c528104047ce119",
[
"compute-pressure/compute_pressure_basic.https.window.html?globalScope=dedicated_worker",
{
@@ -564888,7 +565925,7 @@
]
],
"compute_pressure_duplicate_updates.https.window.js": [
- "231d4afc345d50e59a2612fc3c343af3a5a5a8c2",
+ "abf53854b40637d17102132d39e8a5e0aeaa438d",
[
"compute-pressure/compute_pressure_duplicate_updates.https.window.html?globalScope=dedicated_worker",
{
@@ -573539,7 +574576,7 @@
]
],
"cookieListItem_attributes.https.any.js": [
- "542bd6c53870b5baaa9ac0f75c2235079b7bfe88",
+ "b42a745d3e4e1a9f4c8a0c6e7d9c04c02f8d1340",
[
"cookie-store/cookieListItem_attributes.https.any.html",
{
@@ -573702,7 +574739,7 @@
]
],
"cookieStore_delete_arguments.https.any.js": [
- "37a551b3a9f2511d915bb06b4d2311e3e7979ae2",
+ "2503de0abb0fecb3493334cd94355ff8c45e908d",
[
"cookie-store/cookieStore_delete_arguments.https.any.html",
{
@@ -573712,6 +574749,10 @@
"Cookie Store API: cookieStore.delete() arguments"
],
[
+ "script",
+ "resources/cookie-test-helpers.js"
+ ],
+ [
"global",
"window,serviceworker"
]
@@ -573727,6 +574768,10 @@
"Cookie Store API: cookieStore.delete() arguments"
],
[
+ "script",
+ "resources/cookie-test-helpers.js"
+ ],
+ [
"global",
"window,serviceworker"
]
@@ -573986,7 +575031,7 @@
]
],
"cookieStore_get_set_across_origins.sub.https.html": [
- "c67ef98bcc944dbfb815993734dcfae7dbd3eb9d",
+ "004e37630ac76016846b7a33633f583242b23a55",
[
null,
{}
@@ -574098,7 +575143,7 @@
]
],
"cookieStore_set_arguments.https.any.js": [
- "064fcc5de529f42c78b853f66f1a5e2f56e6ac01",
+ "3e9ac5f3e983fa227d3bf35604604a902b11a8d3",
[
"cookie-store/cookieStore_set_arguments.https.any.html",
{
@@ -574108,6 +575153,10 @@
"Cookie Store API: cookieStore.set() arguments"
],
[
+ "script",
+ "resources/cookie-test-helpers.js"
+ ],
+ [
"global",
"window,serviceworker"
]
@@ -574123,6 +575172,10 @@
"Cookie Store API: cookieStore.set() arguments"
],
[
+ "script",
+ "resources/cookie-test-helpers.js"
+ ],
+ [
"global",
"window,serviceworker"
]
@@ -580955,6 +582008,20 @@
null,
{}
]
+ ],
+ "corner-shape-outside-left.html": [
+ "b38b7f3f27872e5bf8ad402aa6dabe981a9d5530",
+ [
+ null,
+ {}
+ ]
+ ],
+ "corner-shape-outside-right.html": [
+ "96a297230bb52863ac149c7a8da1ec1e9d20bcac",
+ [
+ null,
+ {}
+ ]
]
},
"parsing": {
@@ -582177,28 +583244,28 @@
]
},
"table-parts-offsetheight.html": [
- "5bdc33b521ae40b94165836381fd3674c11ddf28",
+ "cc49f339de74e40be63dc0403241afc2c7eb0182",
[
null,
{}
]
],
"table-parts-offsets-vertical-lr.tentative.html": [
- "bdac1f40607d2f63dee3cb8aadf6ac93f450a58c",
+ "77516a6146f02000e6c40761fe85de6a283eca40",
[
null,
{}
]
],
"table-parts-offsets-vertical-rl.tentative.html": [
- "1eb751032ca4b7598ee3a413408c61c5a592b3e4",
+ "ea58b145738747114ba6c9f89849f632d1944917",
[
null,
{}
]
],
"table-parts-offsets.tentative.html": [
- "265d761ffb30fd3e99214927a34ee33e3811f977",
+ "4bed47b6a4d5a05810d6c8cb2515e93a8db9bd7d",
[
null,
{}
@@ -582947,7 +584014,7 @@
]
],
"color-computed-relative-color.html": [
- "9bb87459623ac3c50b2154432269adef114fe811",
+ "a5c489e40a6cffd28709757b1645db319a2a70b9",
[
null,
{}
@@ -585273,6 +586340,13 @@
{}
]
],
+ "content-counter-valid.html": [
+ "6de60c9f1d8bff9a38ab8863f4a59dcb85424db3",
+ [
+ null,
+ {}
+ ]
+ ],
"content-invalid.html": [
"efd4ea5136c489ccd38a25732864f4165a9a2b81",
[
@@ -589366,7 +590440,7 @@
]
],
"font-weight-matching.html": [
- "5eb9a99f8742e7b2d549acb9010ab2ee49981f78",
+ "2788039a2d4ca8bef3c34ead1516786624c060e4",
[
null,
{}
@@ -589459,6 +590533,34 @@
{}
]
],
+ "gap-decorations-rule-shorthand-computed-from-longhands.html": [
+ "562c166e90b3cc983c117c8deec63a1b3105cb35",
+ [
+ null,
+ {}
+ ]
+ ],
+ "gap-decorations-rule-shorthand-computed.html": [
+ "7bb3e1858dd9fef26389628aa5ea11cab06fb22d",
+ [
+ null,
+ {}
+ ]
+ ],
+ "gap-decorations-rule-shorthand-invalid.html": [
+ "f7c6b45b16d08e9a3e1db4587dba27ab95b91829",
+ [
+ null,
+ {}
+ ]
+ ],
+ "gap-decorations-rule-shorthand.html": [
+ "420b6757e7fafd4b7d49c4f4aef2ef17a0552704",
+ [
+ null,
+ {}
+ ]
+ ],
"gap-decorations-style-computed.html": [
"8c78bf618e3226609ad451e27ff97816b6b73cf6",
[
@@ -589564,15 +590666,6 @@
{}
]
]
- },
- "serialization": {
- "gap-decorations-properties.html": [
- "4985b5550f25f0ee0a2be125900f16c65c6ec0cf",
- [
- null,
- {}
- ]
- ]
}
},
"css-grid": {
@@ -595567,7 +596660,7 @@
]
],
"dashed-function-cycles.html": [
- "15305be2b287ca3e4fbfad928f8d101ed8463104",
+ "e711c9ed3678bd3b95eeed589b4f88754940b993",
[
null,
{}
@@ -595693,7 +596786,7 @@
]
],
"local-attr-substitution.html": [
- "575372a96696f6c01870c345d6981b36cca257b0",
+ "de2a20fa470a9268980a403c74df5d9e2c89ef20",
[
null,
{}
@@ -596060,6 +597153,13 @@
{}
]
],
+ "offsetProps-001.html": [
+ "a592c5a88d7ec31169c120f14dfbac14a8080510",
+ [
+ null,
+ {}
+ ]
+ ],
"parsing": {
"column-count-computed.html": [
"702632d2dd4d306368951af65e9c32d7f2e2f554",
@@ -599128,6 +600228,13 @@
{}
]
],
+ "resolved-color-value.html": [
+ "2515726fd701356ec2b318ba0c2980d48b7d717f",
+ [
+ null,
+ {}
+ ]
+ ],
"self-utils.html": [
"b770c86c38269656d77c3e382d3fe0391cdd8cd0",
[
@@ -600820,7 +601927,7 @@
]
},
"resnap-on-snap-alignment-change.html": [
- "e4648b1d79813548c763bf08e002b485ff291f56",
+ "760d9afbe2e913ebfef2e4d6d24c59d57ef4e834",
[
null,
{}
@@ -601217,7 +602324,7 @@
]
],
"smooth-anchor-scroll-in-snap-container.html": [
- "c01420b2ee4a00aa2ec143a68b30fb3c0ddb465b",
+ "4892ae3efb5f4f841e83bf2d44e9d848bca002ab",
[
null,
{}
@@ -601250,7 +602357,7 @@
]
],
"changing-scroll-snap-align-nested.tentative.html": [
- "ddea57055174ca7087bdc2587ebf884bc73ff2c5",
+ "d945d00ca18a2351543d5bad3841e42df72957c2",
[
null,
{}
@@ -601715,6 +602822,13 @@
{}
]
],
+ "snapevent-constructor.html": [
+ "a5257d77e3d2d0200c1084e060c09cba3d045990",
+ [
+ null,
+ {}
+ ]
+ ],
"unreachable-snap-positions-001.html": [
"ca4f6033cece748bb1b4b39c755569174a75ecb5",
[
@@ -613053,7 +614167,7 @@
]
],
"attr-cycle.html": [
- "1db82c4cad2fc1ca9dc557508a2a5074385cbf1e",
+ "c876f77a8352ec5b5004f21d6973b7a50c58b8cc",
[
null,
{}
@@ -613663,7 +614777,7 @@
]
],
"if-cycle.html": [
- "74d56dc9ed7c382ee8427feaefacc2198b94216f",
+ "ac3ff7df4ee1fe08be9680c36a14850444c012ec",
[
null,
{}
@@ -614121,7 +615235,7 @@
]
],
"sibling-function-descriptors.tentative.html": [
- "76d2ff8ee4db660e41ede9b188465a6c31843e3b",
+ "8f597aa92e48d47d60436bf866ffd69887faddae",
[
null,
{}
@@ -614141,6 +615255,20 @@
{}
]
],
+ "sibling-index-keyframe-font-variation-settings-dynamic.html": [
+ "d98a72a2fb219e08dac908eca790bae20fc9f234",
+ [
+ null,
+ {}
+ ]
+ ],
+ "sibling-index-keyframe-font-weight-dynamic.html": [
+ "99fe0b3b2e1151ba8e7b7eb60c643a9b386433e5",
+ [
+ null,
+ {}
+ ]
+ ],
"sibling-index-keyframe-length-value-dynamic.html": [
"cbd34602fb3c74f3cea8a1e2192d1b5687e38a05",
[
@@ -614148,6 +615276,34 @@
{}
]
],
+ "sibling-index-keyframe-percent-dynamic.html": [
+ "58d1e7990d3aa73d94aa857386c948e46d763f03",
+ [
+ null,
+ {}
+ ]
+ ],
+ "sibling-index-keyframe-registered-properties-dynamic.html": [
+ "77af5434a1c4903928194bec4174745a3bd1efeb",
+ [
+ null,
+ {}
+ ]
+ ],
+ "sibling-index-keyframe-rotate-dynamic.html": [
+ "67df9c01d196fd8e80f80efaca8b02520aaf2a8f",
+ [
+ null,
+ {}
+ ]
+ ],
+ "sibling-index-keyframe-scale-dynamic.html": [
+ "8b3fe6f7532ccbc9c647ffa703329da52c813d33",
+ [
+ null,
+ {}
+ ]
+ ],
"sibling-index-keyframe-value-dynamic.html": [
"286e0d3d3e2eecdd091df74c8c47f738cb700dd1",
[
@@ -614441,7 +615597,7 @@
]
],
"variable-cycles.html": [
- "950cffb2ab5117d9282cbef8f00e54f16949d07a",
+ "06b270d3b6603ed64036d743a535f3e00cb20b1e",
[
null,
{}
@@ -614616,7 +615772,7 @@
]
],
"variable-substitution-variable-declaration.html": [
- "5239a05c3047fb2283ec9a4e9a213a51c0f87f3a",
+ "28ca7ca4810ebbe7f11c5bfd7e7fc8242e7b1b83",
[
null,
{}
@@ -614680,6 +615836,13 @@
{}
]
],
+ "dynamic-stylesheet-animations-timing-function.html": [
+ "4e43cc0375b972a814693141b8b0118f3323914d",
+ [
+ null,
+ {}
+ ]
+ ],
"dynamic-stylesheet-animations.html": [
"d737d3ab570075e3d88ea827d2296c74e5f35033",
[
@@ -615173,7 +616336,7 @@
]
],
"pseudo-get-computed-style.html": [
- "60e032b1d98e1dc5d670f99edba85a5f8f146dd5",
+ "274e946b825951f0a941c9befe5059452568d9c4",
[
null,
{}
@@ -615334,7 +616497,7 @@
]
],
"web-animation-pseudo-incorrect-name.html": [
- "e8d14f1bb08161169f436634fe9c4937759ed991",
+ "6743ae8aff6deed92f2f2e75b27d6ba8430b6389",
[
null,
{}
@@ -621307,6 +622470,13 @@
]
]
},
+ "quirks-mode-import.html": [
+ "515f8d86e4697e3a49cc1836695c55ad23308e8f",
+ [
+ null,
+ {}
+ ]
+ ],
"scope-selector.html": [
"06b6bc13785dff351b2e518e22aa0889cc77d875",
[
@@ -622937,7 +624107,7 @@
]
],
"allow-attribute-with-get.https.html": [
- "15601d891f25c4c2d75dad2260d1b45a26a9344d",
+ "a13a188c9da1554df1cd38ca07e3fcb87837063f",
[
null,
{
@@ -622998,7 +624168,7 @@
]
],
"get.tentative.https.html": [
- "b04a6e3a713e26f759cc62d81a6a439ea69e189e",
+ "8c0c33c2fa195ac25ef026645f8d3ca95f227c4e",
[
null,
{
@@ -623018,7 +624188,7 @@
]
],
"non-fully-active.https.html": [
- "3c09b132daf76ec719cadf2fc741d60a2a8d0df2",
+ "8d8f889f6ac627d584e27e59e001e2b5e7e7d90a",
[
null,
{
@@ -623027,7 +624197,7 @@
]
],
"user-activation.https.html": [
- "facaf7bddbbd419801a9ffa470f4bb5bbc1ab07c",
+ "1189c32252ae1a1c52fa2d75d11f4ec00b45d57a",
[
null,
{
@@ -649273,6 +650443,26 @@
}
]
],
+ "fedcm-accounts-push": {
+ "fedcm-accounts-push-basic.tentative.https.html": [
+ "3affa4e3a6d745c8e5f0802e287cc3d16ee89ee1",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "fedcm-accounts-push-caches-pictures.tentative.https.html": [
+ "5b069785f98348be621934a50a540dbad6ae52f3",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ]
+ },
"fedcm-after-abort.https.html": [
"3c2f981e82fab32d20303367289180c20e8eb71f",
[
@@ -683813,11 +685003,14 @@
]
],
"enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html": [
- "f3cf0bc97e107e41906ef0fcb0d8ca89885100fe",
+ "8ce0aab33898f3b4cf4e0110810f63c19247ebe4",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
@@ -683848,6 +685041,30 @@
}
]
],
+ "getCurrentPosition-error.https.html": [
+ "0ea929d161eeab86c1baf47682a7bdd7bdbdc268",
+ [
+ null,
+ {
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
+ }
+ ]
+ ],
+ "getCurrentPosition-success.https.html": [
+ "d601b536329e44d2e40aab69a9e98f40074e81c8",
+ [
+ null,
+ {
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
+ }
+ ]
+ ],
"getCurrentPosition_TypeError.https.html": [
"9da8ac1d29247d981171946747b17f4d60fe0f4b",
[
@@ -684117,11 +685334,14 @@
]
],
"Gyroscope-iframe-access.https.html": [
- "c94016764d5176b0703e1b19cd3f4cdbe0c43eb4",
+ "cdabff82f1094d788b3aaaee69301c7d7227f184",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
@@ -684133,11 +685353,14 @@
]
],
"Gyroscope.https.html": [
- "8aab94693abea6198bb9b7d03c2408cd4bec58a4",
+ "ce2c09515f1ea04d24c3394ca7a05e63c342b744",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -729797,6 +731020,13 @@
{}
]
],
+ "embed-javascript-url.html": [
+ "253ba2132738fa020f3ef33d6c8a276090e5332d",
+ [
+ null,
+ {}
+ ]
+ ],
"embed-network-error.sub.html": [
"bae995c101fd2d9d886c918f25fa711c1289559d",
[
@@ -730124,7 +731354,7 @@
]
],
"iframe-loading-lazy-nav-navigation-navigate.html": [
- "1010c540b7fd59521278ece38b34f9e572e4e4a6",
+ "47435f4c48d4e2fb1c5382c27c0325dfc1a7e8bf",
[
null,
{}
@@ -730152,7 +731382,7 @@
]
],
"iframe-loading-lazy-reload-navigation-reload.html": [
- "aefd6c472b5ae888e0786de8e26e8d9ad5111adb",
+ "6633b710828d8f15e8f7edf0834c6260bd270bb3",
[
null,
{}
@@ -730200,6 +731430,41 @@
{}
]
],
+ "iframe_javascript_url_in_src.htm": [
+ "73202af1d7ce64f2d2daed80cb52b5ebb744fa6d",
+ [
+ null,
+ {}
+ ]
+ ],
+ "iframe_javascript_url_initial_insertion.html": [
+ "6989172a2171f910b75b7cc972dbb194fd2e7d55",
+ [
+ null,
+ {}
+ ]
+ ],
+ "iframe_javascript_url_loading_lazy.htm": [
+ "e88592b2a11d827541a6fe436b6d2f67757d50d8",
+ [
+ null,
+ {}
+ ]
+ ],
+ "iframe_javascript_url_not_about_blank.html": [
+ "9d236426c969b2ddd28c46ce4e207fc0142a5735",
+ [
+ null,
+ {}
+ ]
+ ],
+ "iframe_javascript_url_remove_srcdoc.html": [
+ "fee300c5c48bd99f2686d99cef452e238b63b7c6",
+ [
+ null,
+ {}
+ ]
+ ],
"iframe_navigate_ancestor-1.sub.html": [
"5e3b7682cc8dd45a22bb74b5f7b11a6a4a728d72",
[
@@ -730207,6 +731472,13 @@
{}
]
],
+ "iframe_navigate_javascript_url.htm": [
+ "88867790e7d2e58a4e75f21368fa6cd6c90dee7a",
+ [
+ null,
+ {}
+ ]
+ ],
"iframe_remove_src.html": [
"f0ff9ff5082d849d6b987a8ee4b46d5d0d1794e5",
[
@@ -731604,6 +732876,13 @@
{}
]
],
+ "naturalWidth-naturalHeight-unavailable.tentative.html": [
+ "df9eb374b5adc003c93830ab4605b2adad0ae84d",
+ [
+ null,
+ {}
+ ]
+ ],
"naturalWidth-naturalHeight.html": [
"19aa4b9344f9040ac9092c8b415267f5f5815cf2",
[
@@ -731942,6 +733221,13 @@
{}
]
],
+ "object-javascript-url.html": [
+ "79c3ff9c407e96bc02b443c26dc5dceb2b453c75",
+ [
+ null,
+ {}
+ ]
+ ],
"object-setcustomvalidity.html": [
"44574ffd11faac8a082c2d6b749adf5d8ee2f7ee",
[
@@ -734449,6 +735735,15 @@
}
]
],
+ "select-optgroup-arrow-keys.tentative.html": [
+ "00ba0e3a39bdd971bf1a7ea26ec716ca04aecb44",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"select-option-arrow-scroll.tentative.html": [
"cb65bddc0715bca966d456ebb7136f39a657ec0e",
[
@@ -734468,7 +735763,7 @@
]
],
"select-parsing.tentative.html": [
- "0c6972bcab5b8d039bb1634d675276d2d7c8a28a",
+ "5fe50d507758838d04ab3a6fe9bea3ba5f30e203",
[
null,
{}
@@ -734554,6 +735849,13 @@
{}
]
],
+ "selectedcontent-mutations.tentative.html": [
+ "45f2ff7813992313292b4aa682a9bcd43e4fb277",
+ [
+ null,
+ {}
+ ]
+ ],
"selectedcontent-restore.tentative.html": [
"da5fe450abbae0d19826021f114cc6388f97bc57",
[
@@ -734564,7 +735866,7 @@
]
],
"selectedcontent.tentative.html": [
- "d32990515370eeddac07a41eb12c8c418adbdb15",
+ "ce298adc23e32b0b74c8f9e237b1fa5789a9660b",
[
null,
{
@@ -735100,6 +736402,15 @@
}
]
],
+ "details-toggle-source.tentative.html": [
+ "1a571f5441449a964bf9aea27246ef13f937944c",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"details.html": [
"5ed14c53afc9371275917d460f5b9638ab9a091e",
[
@@ -735283,7 +736594,7 @@
]
],
"dialog-closedby-corner-cases.html": [
- "06a9084415410e208ea3d75bcf04547aad829072",
+ "511acaccef334c8ad5c6255c7543b8cf69e1801f",
[
null,
{
@@ -735292,6 +736603,15 @@
}
]
],
+ "dialog-closedby-show-stacked.html": [
+ "30021a79be3b3f91a2958c6aed360c97e25a84cf",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"dialog-closedby-start-open.html": [
"0606d9b04afd002d7319b8a9ad7b990ca67cf359",
[
@@ -735480,6 +736800,15 @@
{}
]
],
+ "dialog-toggle-source.tentative.html": [
+ "7e6fe25dabf79d9430fcfa98afe83f3520d62686",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"focus-after-close.html": [
"7137edcd1a18080c96d627e5f40da13b1d36437f",
[
@@ -736016,13 +737345,6 @@
{}
]
],
- "display-css-property.tentative.html": [
- "b87b6aa9e0449a969765666a18a03670e3ae3091",
- [
- null,
- {}
- ]
- ],
"granted-selector.html": [
"9fd00114bdfdb49fe293c265ee6baf497b464d7f",
[
@@ -736516,6 +737838,13 @@
{}
]
],
+ "popover-toggle-source.tentative.html": [
+ "00ced8f7070aa4ac677c7fc0a64b3b150f95039b",
+ [
+ null,
+ {}
+ ]
+ ],
"popover-top-layer-combinations.html": [
"024794f57853307e15532e7f1c5ff894a61fa51d",
[
@@ -741404,7 +742733,7 @@
]
],
"interesttarget-keyboard-behavior.tentative.html": [
- "7040019e7504da05d46cc6d1745d6491f72574b4",
+ "997c2b9382508902ae2025bb4f71d6f2de0f56f5",
[
null,
{
@@ -741441,7 +742770,7 @@
]
],
"interesttarget-pseudo-classes.tentative.html": [
- "7cd50ebfe20b006c1d07af9941b98c5391993563",
+ "924c4d5fbc82f323741c27690f2b36fcc79961ae",
[
null,
{
@@ -752390,36 +753719,6 @@
]
]
},
- "lifecycle": {
- "child-display-none.tentative.html": [
- "d4ca6dab1e068703c1b5e94e22b8cb31f786879f",
- [
- null,
- {}
- ]
- ],
- "child-out-of-viewport.tentative.html": [
- "4d8f868bfb55043b4b65a93cd7f8e282dcf12f79",
- [
- null,
- {}
- ]
- ],
- "freeze.html": [
- "a2a9a7d3f147da9069bde019ec5940a213fbae79",
- [
- null,
- {}
- ]
- ],
- "worker-dispay-none.tentative.html": [
- "0bcfde6d179bb5573ce78fa46827211e7c38dc35",
- [
- null,
- {}
- ]
- ]
- },
"loading": {
"early-hints": {
"404-with-early-hints.h2.window.js": [
@@ -753738,11 +755037,14 @@
]
],
"Magnetometer-iframe-access.https.html": [
- "7aabd0eb61b3c7867619169c2da77ca0af128e7c",
+ "455a06b060bf02e433cbe40ad9c7baf26484892b",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
@@ -753754,11 +755056,14 @@
]
],
"Magnetometer.https.html": [
- "6beb534509d79f0079d8c4e121020eb529f7a160",
+ "964ef2bd8752959ac1e6f81539dd26d3767beb3a",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -764115,20 +765420,26 @@
]
],
"AbsoluteOrientationSensor-iframe-access.https.html": [
- "4831b5e719200d34903d2d20dce2675a70e3a3e5",
+ "599bff7b4a3b0cd23af16bdca765abdfe89fc39b",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
"AbsoluteOrientationSensor.https.html": [
- "4c516da145169e29d0a1f5bbd1bf326404b722d5",
+ "0a6e2dae897d3ad42d4a4b4a7b347e69beeaa753",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -764176,20 +765487,26 @@
]
],
"RelativeOrientationSensor-iframe-access.https.html": [
- "fe995e2d1b982db7dff6729da7e5148487d8fbd7",
+ "7e55cb3b69e7bbe5d82b95ff7d557ce329e0a7bf",
[
null,
{
- "testdriver": true
+ "testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ]
}
]
],
"RelativeOrientationSensor.https.html": [
- "35dc8c3111363721c0f6645778b1cd96ec1a6483",
+ "9ad37a627c1a48ee94198ee7790f8a3a860df98f",
[
null,
{
"testdriver": true,
+ "testdriver_features": [
+ "bidi"
+ ],
"timeout": "long"
}
]
@@ -764214,6 +765531,27 @@
]
},
"page-lifecycle": {
+ "child-display-none.tentative.html": [
+ "d4ca6dab1e068703c1b5e94e22b8cb31f786879f",
+ [
+ null,
+ {}
+ ]
+ ],
+ "child-out-of-viewport.tentative.html": [
+ "4d8f868bfb55043b4b65a93cd7f8e282dcf12f79",
+ [
+ null,
+ {}
+ ]
+ ],
+ "freeze.html": [
+ "a2a9a7d3f147da9069bde019ec5940a213fbae79",
+ [
+ null,
+ {}
+ ]
+ ],
"idlharness.html": [
"55a7cbc2429c81a182c1373780f4bba457060a50",
[
@@ -764222,6 +765560,13 @@
"timeout": "long"
}
]
+ ],
+ "worker-dispay-none.tentative.html": [
+ "0bcfde6d179bb5573ce78fa46827211e7c38dc35",
+ [
+ null,
+ {}
+ ]
]
},
"page-visibility": {
@@ -770171,6 +771516,39 @@
}
]
],
+ "pointerevent_click_during_parent_capture.html": [
+ "f25e61aade3abb3d95185e4981b4740f15bfab52",
+ [
+ "pointerevents/pointerevent_click_during_parent_capture.html?pointerType=mouse&preventDefault=",
+ {
+ "testdriver": true
+ }
+ ],
+ [
+ "pointerevents/pointerevent_click_during_parent_capture.html?pointerType=mouse&preventDefault=pointerdown",
+ {
+ "testdriver": true
+ }
+ ],
+ [
+ "pointerevents/pointerevent_click_during_parent_capture.html?pointerType=touch&preventDefault=",
+ {
+ "testdriver": true
+ }
+ ],
+ [
+ "pointerevents/pointerevent_click_during_parent_capture.html?pointerType=touch&preventDefault=pointerdown",
+ {
+ "testdriver": true
+ }
+ ],
+ [
+ "pointerevents/pointerevent_click_during_parent_capture.html?pointerType=touch&preventDefault=touchstart",
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"pointerevent_click_is_a_pointerevent.html": [
"9087a42436e0c82f519a2427999f4b5a7edf502f",
[
@@ -786281,7 +787659,7 @@
]
],
"sanitizer-basic-filtering.tentative.html": [
- "38c764ae181418014488cf86126398158e653157",
+ "0be3604ecfe4a3fb189a63c4c346ddaddf85f95d",
[
null,
{}
@@ -788982,15 +790360,15 @@
{}
]
],
- "timeline-scope-computed.tentative.html": [
- "2e0a024a60007652daa90aaed2125a6dbbb6f051",
+ "timeline-scope-computed.html": [
+ "1096a9aa136eec6efe8b9f2cb30205bcc8683073",
[
null,
{}
]
],
- "timeline-scope-parsing.tentative.html": [
- "61bf6975a81447024d5e814229fdbd987b7c8223",
+ "timeline-scope-parsing.html": [
+ "ff6fcb7e5a5560baf81e147c92e4f1b2fe21e6d4",
[
null,
{}
@@ -797936,15 +799314,6 @@
}
]
],
- "replacestate.tentative.html": [
- "d47b9b653881f57e085fef94360c9245e23c022f",
- [
- null,
- {
- "testdriver": true
- }
- ]
- ],
"second-interaction-not-softnav.tentative.html": [
"a9bb337060d00a5e21075f2c2cb53570e500afaf",
[
@@ -797956,6 +799325,15 @@
],
"smoke": {
"tentative": {
+ "almost-soft-navigation.html": [
+ "aa5732f9fb7e735d72c732a8299f5832db410ce0",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"basic.html": [
"9bfedf09b1934e00a85cd030388ed470f575f7b0",
[
@@ -797964,6 +799342,24 @@
"testdriver": true
}
]
+ ],
+ "dom.html": [
+ "66d23b22788c4749d7b990b89b0cef612872f5f4",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "task-attribution.html": [
+ "8f6f93c8daf6c089efd0eee7fefdc1a8ffa704f1",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
]
}
},
@@ -798003,15 +799399,6 @@
}
]
],
- "soft-navigation-no-url.tentative.html": [
- "a0055c654c2049c9df444510c892489e363d0bb3",
- [
- null,
- {
- "testdriver": true
- }
- ]
- ],
"softnav-after-lcp-paint-larger-than-viewport.tentative.html": [
"3c930d8be4cd459d9167404be13ad9ac219ec422",
[
@@ -798960,7 +800347,7 @@
"tentative": {
"service-worker": {
"basic.sub.https.html": [
- "98e089bcc660f24ba3e82425e2b23ef928a0f08a",
+ "5b2a4d00dba107fcd2e97b46bf632097f4cc6f30",
[
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=fetch-handler",
{
@@ -798968,58 +800355,118 @@
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=fetch-handler&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=fetch-handler-to-fallback",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=fetch-handler-to-fallback&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=no-controller",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=no-controller&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=no-fetch-handler",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=cross-site&sw=no-fetch-handler&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-modify-referrer",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-modify-referrer&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-modify-url",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-modify-url&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-to-fallback",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=fetch-handler-to-fallback&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=no-controller",
{
"timeout": "long"
}
],
[
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=no-controller&clientId",
+ {
+ "timeout": "long"
+ }
+ ],
+ [
"speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=no-fetch-handler",
{
"timeout": "long"
}
+ ],
+ [
+ "speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html?origin=same-site&sw=no-fetch-handler&clientId",
+ {
+ "timeout": "long"
+ }
]
],
"redirect.sub.https.html": [
@@ -800924,14 +802371,14 @@
},
"speech-api": {
"SpeechRecognition-availableOnDevice.https.html": [
- "db48f2a7a6fe671443e8e38c3a5f183c4190bff4",
+ "ace8edd91647dc0fb08d32353a68d4adde93f53f",
[
null,
{}
]
],
"SpeechRecognition-basics.https.html": [
- "827844096f6e58a7b64f1192958c8a2475a1410f",
+ "91cf8e6d3e54a64a6cac0cf776fa618b99966cbc",
[
null,
{}
@@ -800952,7 +802399,7 @@
]
],
"SpeechRecognition-installOnDevice.https.html": [
- "2f5b359c571d6d9cc97815ae6ba46e4249ec569e",
+ "5f78fc8c9c17fffb544775f28c1bd11fb8ebba7c",
[
null,
{
@@ -802116,7 +803563,7 @@
]
],
"requestStorageAccess-cross-origin-fetch.sub.https.window.js": [
- "21592a9225f646e51f935b044a476217f4e1e4f4",
+ "91826bcbaeb12a0d33370d2724a497868cc3ef93",
[
"storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.html",
{
@@ -802199,7 +803646,7 @@
]
],
"requestStorageAccess-cross-site-fetch.sub.https.window.js": [
- "b46f42d1211f4205a23c02f03c4117e35e241d81",
+ "f0c9ff91ef7454154b8c47ad3a19fa5e87742d27",
[
"storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.html",
{
@@ -814619,16 +816066,16 @@
],
"tentative": {
"integrity-policy": {
- "parsing.https.html": [
+ "parsing.html": [
"205854419a7d58871e39a5cfb3a86ccd38cd5492",
[
- "subresource-integrity/tentative/integrity-policy/parsing.https.html?type=enforce",
+ "subresource-integrity/tentative/integrity-policy/parsing.html?type=enforce",
{
"timeout": "long"
}
],
[
- "subresource-integrity/tentative/integrity-policy/parsing.https.html?type=report",
+ "subresource-integrity/tentative/integrity-policy/parsing.html?type=report",
{
"timeout": "long"
}
@@ -834773,6 +836220,13 @@
{}
]
],
+ "script-src-allows-source-phase-wasm.tentative.html": [
+ "b96fc756e5c0edbe8a5e0c8c63c075b0028059dc",
+ [
+ null,
+ {}
+ ]
+ ],
"script-src-allows-wasm.tentative.html": [
"07faf9a5a1cff52532c01d0b80c29fbd83fd2dbc",
[
@@ -834787,6 +836241,20 @@
{}
]
],
+ "source-phase-blocked-by-csp.tentative.html": [
+ "86c8d96835ea0479c04d874e1cdcb8523a206371",
+ [
+ null,
+ {}
+ ]
+ ],
+ "source-phase-preload.tentative.html": [
+ "90bfb484741af90ff5d37cbf59062b47c6a732b9",
+ [
+ null,
+ {}
+ ]
+ ],
"source-phase.tentative.html": [
"870b16bd0a0ce8db80d403fc12aeecaf5e6ccedb",
[
@@ -834823,7 +836291,7 @@
]
],
"worker-import-source-phase.tentative.html": [
- "e193f3efc69330779408e56fddf09348fb6249fc",
+ "56aea9f96554021abebabc5d8de1112edf021b88",
[
null,
{}
@@ -834842,6 +836310,13 @@
null,
{}
]
+ ],
+ "worklet-import-source-phase.tentative.https.html": [
+ "9a9714a2a3edd002192b042df5abf2afa354e0cc",
+ [
+ null,
+ {}
+ ]
]
},
"historical.any.js": [
@@ -859254,7 +860729,7 @@
]
],
"prelu.https.any.js": [
- "b89de832d3e4c583b13d12a29c92a62f0c01a95e",
+ "cfd043ce61744b5281f8322d7cf3486b1227cf79",
[
"webnn/conformance_tests/prelu.https.any.html?cpu",
{
@@ -859365,7 +860840,7 @@
]
],
"qdq_subgraph.https.any.js": [
- "aa816cce7fb2cd3d0a3f81d0453c8c199bf052fe",
+ "70e8cab0d95ee7d2870a462621de80be95cf2e79",
[
"webnn/conformance_tests/qdq_subgraph.https.any.html?cpu",
{
@@ -882272,7 +883747,7 @@
]
],
"RTCRtpScriptTransform-encoded-transform.https.html": [
- "9eb7020a781c2d2715fcac3583e7142b50b1da2f",
+ "ffb29e7dec6f8901198a12e3ddf8c817ee6d13ed",
[
null,
{
@@ -882290,12 +883765,55 @@
]
],
"idlharness.https.window.js": [
- "2c6ef19ca82a56c799b97b5eb9af3edb900a40b5",
+ "d3eea3bc138cad7676690e274006a5c521ec038d",
[
- "webrtc-encoded-transform/idlharness.https.window.html",
+ "webrtc-encoded-transform/idlharness.https.window.html?exclude=SFrameTransform.*",
{
"script_metadata": [
[
+ "variant",
+ "?exclude=SFrameTransform.*"
+ ],
+ [
+ "variant",
+ "?include=SFrameTransform.*"
+ ],
+ [
+ "script",
+ "/common/subset-tests-by-key.js"
+ ],
+ [
+ "script",
+ "/resources/WebIDLParser.js"
+ ],
+ [
+ "script",
+ "/resources/idlharness.js"
+ ],
+ [
+ "script",
+ "./RTCPeerConnection-helper.js"
+ ]
+ ]
+ }
+ ],
+ [
+ "webrtc-encoded-transform/idlharness.https.window.html?include=SFrameTransform.*",
+ {
+ "script_metadata": [
+ [
+ "variant",
+ "?exclude=SFrameTransform.*"
+ ],
+ [
+ "variant",
+ "?include=SFrameTransform.*"
+ ],
+ [
+ "script",
+ "/common/subset-tests-by-key.js"
+ ],
+ [
"script",
"/resources/WebIDLParser.js"
],
@@ -925182,13 +926700,6 @@
{}
]
],
- "font-family-name-000.xht": [
- "2afa0bafc0466afb0c5ca27a8c2eaceaad5a520b",
- [
- null,
- {}
- ]
- ],
"font-size-adjust-003.xht": [
"1886ccc6bfdb027b797efe69f127f41bc6aa46f8",
[
@@ -925209,20 +926720,6 @@
null,
{}
]
- ],
- "test-synthetic-bold.xht": [
- "2d34f02a92a0a65e61623a810337ebb72c1990e7",
- [
- null,
- {}
- ]
- ],
- "test-synthetic-italic.xht": [
- "05b9cf67984c023a2e41dc52a6cd27e627ca8c0e",
- [
- null,
- {}
- ]
]
},
"css-grid": {
@@ -927808,14 +929305,14 @@
},
"context_created": {
"context_created.py": [
- "2982f78d99188ba77f4bf243cb7dd363644ed6a2",
+ "3c26dbed7dca0ae8b837982ade47def01a343560",
[
null,
{}
]
],
"original_opener.py": [
- "18c9483e7ce83389472f7a3bef0617a3ef180083",
+ "9ac59a3a325bcb8dea88e1c66a6a7b483f559861",
[
null,
{}
@@ -927824,7 +929321,7 @@
},
"context_destroyed": {
"context_destroyed.py": [
- "2fd0cd6bb479ee97b50a2137e7993dbbc8a94ec5",
+ "0576221de4c3f63f9017c88c480a02fa012f61f3",
[
null,
{}
@@ -927854,21 +929351,21 @@
]
],
"reference_context.py": [
- "8511495594b40d00ab4a3a90a0788ab0848020af",
+ "a39df42acc170dcaa2d571c27c6d4d7d532ef5fd",
[
null,
{}
]
],
"type.py": [
- "17703d60123e28571919cd87d5c90143f4bad7bf",
+ "f6dcdcfa06485cec355fc4dd4691421477c22846",
[
null,
{}
]
],
"user_context.py": [
- "490188c265d461d285772bb6c9c79215b6b5ff6d",
+ "92282c6be6a1aa91a9fdd9e9803c868fd124fe5c",
[
null,
{}
@@ -931389,7 +932886,7 @@
},
"interop": {
"beforeunload_prompt.py": [
- "1e47f6906761bc614575cb061a8d57cc23a2cde1",
+ "68a025ef38cb67c0a06de93a5b51939235e9bf8a",
[
null,
{}
diff --git a/tests/wpt/meta/css/css-align/abspos/align-self-stretch-auto-margins.html.ini b/tests/wpt/meta/css/css-align/abspos/align-self-stretch-auto-margins.html.ini
deleted file mode 100644
index cfef366e7b3..00000000000
--- a/tests/wpt/meta/css/css-align/abspos/align-self-stretch-auto-margins.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[align-self-stretch-auto-margins.html]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-align/abspos/justify-self-stretch-auto-margins.html.ini b/tests/wpt/meta/css/css-align/abspos/justify-self-stretch-auto-margins.html.ini
deleted file mode 100644
index 75934b08795..00000000000
--- a/tests/wpt/meta/css/css-align/abspos/justify-self-stretch-auto-margins.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[justify-self-stretch-auto-margins.html]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-align/blocks/justify-self-auto-margins-2.html.ini b/tests/wpt/meta/css/css-align/blocks/justify-self-auto-margins-2.html.ini
deleted file mode 100644
index 046c147dc0b..00000000000
--- a/tests/wpt/meta/css/css-align/blocks/justify-self-auto-margins-2.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[justify-self-auto-margins-2.html]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html.ini b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html.ini
new file mode 100644
index 00000000000..8e5b9e03056
--- /dev/null
+++ b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html.ini
@@ -0,0 +1,24 @@
+[corner-shape-outside-left.html]
+ [corner-shape: notch with shape-outside]
+ expected: FAIL
+
+ [corner-shape: bevel with shape-outside]
+ expected: FAIL
+
+ [corner-shape: notch bevel with shape-outside]
+ expected: FAIL
+
+ [corner-shape: round with shape-outside]
+ expected: FAIL
+
+ [corner-shape: square with shape-outside]
+ expected: FAIL
+
+ [corner-shape: scoop with shape-outside]
+ expected: FAIL
+
+ [corner-shape: superellipse(1.5) with shape-outside]
+ expected: FAIL
+
+ [corner-shape: superellipse(-.8) with shape-outside]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html.ini b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html.ini
new file mode 100644
index 00000000000..dd9d372d6e6
--- /dev/null
+++ b/tests/wpt/meta/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html.ini
@@ -0,0 +1,24 @@
+[corner-shape-outside-right.html]
+ [corner-shape: notch with shape-outside]
+ expected: FAIL
+
+ [corner-shape: bevel with shape-outside]
+ expected: FAIL
+
+ [corner-shape: notch bevel with shape-outside]
+ expected: FAIL
+
+ [corner-shape: round with shape-outside]
+ expected: FAIL
+
+ [corner-shape: square with shape-outside]
+ expected: FAIL
+
+ [corner-shape: scoop with shape-outside]
+ expected: FAIL
+
+ [corner-shape: superellipse(1.5) with shape-outside]
+ expected: FAIL
+
+ [corner-shape: superellipse(-.8) with shape-outside]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini b/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
index 9fd4765e11e..9a7822335e1 100644
--- a/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
+++ b/tests/wpt/meta/css/css-color/parsing/color-computed-relative-color.html.ini
@@ -502,3 +502,6 @@
[Property color value 'light-dark(color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple), color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple))']
expected: FAIL
+
+ [Property color value 'LCH(from var(--accent) l c calc(h + 180 * sibling-index()))']
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-content/parsing/content-counter-valid.html.ini b/tests/wpt/meta/css/css-content/parsing/content-counter-valid.html.ini
new file mode 100644
index 00000000000..9242fa4310d
--- /dev/null
+++ b/tests/wpt/meta/css/css-content/parsing/content-counter-valid.html.ini
@@ -0,0 +1,9 @@
+[content-counter-valid.html]
+ [e.style['content'\] = "\\"\\" / counter(cnt)" should set the property value]
+ expected: FAIL
+
+ [e.style['content'\] = "\\"regular text\\" / \\"alt text 1\\" counter(cnt) \\"alt text 2\\"" should set the property value]
+ expected: FAIL
+
+ [e.style['content'\] = "\\"regular text\\" / counter(cnt) \\"alt text\\"" should set the property value]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-fonts/font-family-name-000.xht.ini b/tests/wpt/meta/css/css-fonts/font-family-name-000.xht.ini
new file mode 100644
index 00000000000..0c8b2be2c66
--- /dev/null
+++ b/tests/wpt/meta/css/css-fonts/font-family-name-000.xht.ini
@@ -0,0 +1,2 @@
+[font-family-name-000.xht]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-020.html.ini b/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-020.html.ini
new file mode 100644
index 00000000000..857a5ae7976
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-020.html.ini
@@ -0,0 +1,2 @@
+[flex-gap-decorations-020.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-021.html.ini b/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-021.html.ini
new file mode 100644
index 00000000000..bbc998c27d7
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/flex/flex-gap-decorations-021.html.ini
@@ -0,0 +1,2 @@
+[flex-gap-decorations-021.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-034.html.ini b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-034.html.ini
new file mode 100644
index 00000000000..d82c2aea219
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-034.html.ini
@@ -0,0 +1,2 @@
+[grid-gap-decorations-034.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-035.html.ini b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-035.html.ini
new file mode 100644
index 00000000000..dd21da4180a
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-035.html.ini
@@ -0,0 +1,2 @@
+[grid-gap-decorations-035.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-036.html.ini b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-036.html.ini
new file mode 100644
index 00000000000..3473543d37c
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-036.html.ini
@@ -0,0 +1,2 @@
+[grid-gap-decorations-036.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-037.html.ini b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-037.html.ini
new file mode 100644
index 00000000000..7f6385e228f
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/grid/grid-gap-decorations-037.html.ini
@@ -0,0 +1,2 @@
+[grid-gap-decorations-037.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html.ini b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html.ini
new file mode 100644
index 00000000000..d0bcf9cc50d
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html.ini
@@ -0,0 +1,24 @@
+[gap-decorations-rule-shorthand-computed-from-longhands.html]
+ [column-rule computed from width: 5px, style: solid, color: rgb(0, 128, 0)]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(auto, 5px), style: repeat(auto, solid), color: repeat(auto, rgb(255, 0, 0))]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(auto, thin medium), style: solid, color: repeat(8, red blue)]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(6, 15px thick), style: repeat(auto, solid), color: repeat(auto, red)]
+ expected: FAIL
+
+ [column-rule computed from width: 15px 25px 35px, style: solid dotted, color: green]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(auto, 5px), style: solid double, color: repeat(7, red)]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(auto, 5px 8px 10px), style: repeat(auto, solid double), color: repeat(auto, red green blue)]
+ expected: FAIL
+
+ [column-rule computed from width: repeat(2, 1px 3px 5px), style: repeat(2, solid double), color: repeat(2, red)]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html.ini b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html.ini
new file mode 100644
index 00000000000..444bf84a6ba
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html.ini
@@ -0,0 +1,39 @@
+[gap-decorations-rule-shorthand-computed.html]
+ [Property column-rule value '5px solid currentcolor']
+ expected: FAIL
+
+ [Property column-rule value 'rgb(0, 0, 255) 10px solid']
+ expected: FAIL
+
+ [Property column-rule value 'dotted']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(auto, 5px solid rgb(0, 0, 255))']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(auto, 5px solid rgb(255, 255, 0), 10px dotted rgb(0, 128, 0))']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(4, 15px dotted rgb(0, 255, 255))']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(1, 15px ridge rgb(255, 0, 0), 10px dotted rgb(0, 255, 0), 15px double rgb(0, 0, 255))']
+ expected: FAIL
+
+ [Property column-rule value '5px double rgb(58, 58, 16), repeat(4, 5px ridge rgb(18, 18, 18))']
+ expected: FAIL
+
+ [Property column-rule value '15px dashed rgb(0, 255, 0), repeat(3, 3px double rgb(255, 0, 0), 10px dotted rgb(0, 0, 255))']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(4, 5px solid rgb(255, 0, 255)), repeat(3, 5px solid rgb(0, 0, 255), 10px dotted rgb(0, 128, 128))']
+ expected: FAIL
+
+ [Property column-rule value 'repeat(auto, 5px solid rgb(255, 0, 255)), 13px dotted rgb(0, 0, 128), 10px dotted rgb(0, 128, 128), 15px double rgb(0, 0, 128)']
+ expected: FAIL
+
+ [Property column-rule value '5px solid rgb(255, 0, 255), repeat(auto, 5px solid rgb(255, 0, 255)), 10px dotted rgb(0, 128, 128)']
+ expected: FAIL
+
+ [Property column-rule value '10px dotted rgb(0, 128, 128), repeat(4, 20px hidden rgb(0, 128, 128), 30px ridge rgb(255, 0, 255)), repeat(auto, 5px solid rgb(255, 0, 255))']
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand.html.ini b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand.html.ini
new file mode 100644
index 00000000000..33544f753a7
--- /dev/null
+++ b/tests/wpt/meta/css/css-gaps/parsing/gap-decorations-rule-shorthand.html.ini
@@ -0,0 +1,192 @@
+[gap-decorations-rule-shorthand.html]
+ [e.style['column-rule'\] = "5px solid red" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px solid red" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px solid red" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px solid red" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "double" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "double" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "double" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "double" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "blue 10px" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "blue 10px" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "blue 10px" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "blue 10px" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid green)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid green)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid green)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid green)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid yellow, 10px dotted blue)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid yellow, 10px dotted blue)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid yellow, 10px dotted blue)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 5px solid yellow, 10px dotted blue)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, blue 6px, 5px solid red)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, blue 6px, 5px solid red)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, blue 6px, 5px solid red)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, blue 6px, 5px solid red)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, 15px dotted pink)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, 15px dotted pink)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, 15px dotted pink)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, 15px dotted pink)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(1, 15px ridge yellow, 10px dotted blue, 15px double green)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(1, 15px ridge yellow, 10px dotted blue, 15px double green)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(1, 15px ridge yellow, 10px dotted blue, 15px double green)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(1, 15px ridge yellow, 10px dotted blue, 15px double green)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(3, lime 16px, dashed purple, 10px dotted)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(3, lime 16px, dashed purple, 10px dotted)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(3, lime 16px, dashed purple, 10px dotted)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(3, lime 16px, dashed purple, 10px dotted)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "thin, dashed, hotpink" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "thin, dashed, hotpink" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "thin, dashed, hotpink" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "thin, dashed, hotpink" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px double salmon, repeat(4, 5px ridge red)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px double salmon, repeat(4, 5px ridge red)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px double salmon, repeat(4, 5px ridge red)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "5px double salmon, repeat(4, 5px ridge red)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(2, dashed gray, 10px blue dotted, 20px double), 5px solid red, repeat(4, blue 6px, 5px solid white)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(2, dashed gray, 10px blue dotted, 20px double), 5px solid red, repeat(4, blue 6px, 5px solid white)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(2, dashed gray, 10px blue dotted, 20px double), 5px solid red, repeat(4, blue 6px, 5px solid white)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(2, dashed gray, 10px blue dotted, 20px double), 5px solid red, repeat(4, blue 6px, 5px solid white)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, thick hidden skyblue), repeat(3, 5px solid red, 10px dotted)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, thick hidden skyblue), repeat(3, 5px solid red, 10px dotted)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, thick hidden skyblue), repeat(3, 5px solid red, 10px dotted)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(4, thick hidden skyblue), repeat(3, 5px solid red, 10px dotted)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 10px solid red), medium dotted green, repeat(3, thick dashed blue, 15px double green)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 10px solid red), medium dotted green, repeat(3, thick dashed blue, 15px double green)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 10px solid red), medium dotted green, repeat(3, thick dashed blue, 15px double green)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "repeat(auto, 10px solid red), medium dotted green, repeat(3, thick dashed blue, 15px double green)" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "ridge red, repeat(auto, 5px solid green), 10px dotted blue" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "ridge red, repeat(auto, 5px solid green), 10px dotted blue" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "ridge red, repeat(auto, 5px solid green), 10px dotted blue" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "ridge red, repeat(auto, 5px solid green), 10px dotted blue" should not set unrelated longhands]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "10px dotted salmon, repeat(4, thin blue, hidden 5px purple), repeat(auto, 5px solid red, teal)" should set column-rule-color]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "10px dotted salmon, repeat(4, thin blue, hidden 5px purple), repeat(auto, 5px solid red, teal)" should set column-rule-style]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "10px dotted salmon, repeat(4, thin blue, hidden 5px purple), repeat(auto, 5px solid red, teal)" should set column-rule-width]
+ expected: FAIL
+
+ [e.style['column-rule'\] = "10px dotted salmon, repeat(4, thin blue, hidden 5px purple), repeat(auto, 5px solid red, teal)" should not set unrelated longhands]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-gaps/serialization/gap-decorations-properties.html.ini b/tests/wpt/meta/css/css-gaps/serialization/gap-decorations-properties.html.ini
deleted file mode 100644
index bc4c6eb5666..00000000000
--- a/tests/wpt/meta/css/css-gaps/serialization/gap-decorations-properties.html.ini
+++ /dev/null
@@ -1,189 +0,0 @@
-[gap-decorations-properties.html]
- [gap-rule-paint-order]
- expected: FAIL
-
- [gap-rule-paint-order.row-over-column]
- expected: FAIL
-
- [gap-rule-paint-order.column-over-row]
- expected: FAIL
-
- [column-rule-break]
- expected: FAIL
-
- [column-rule-break.none]
- expected: FAIL
-
- [column-rule-break.spanning-item]
- expected: FAIL
-
- [column-rule-break.intersection]
- expected: FAIL
-
- [column-rule-color]
- expected: FAIL
-
- [column-rule-color.red]
- expected: FAIL
-
- [column-rule-color.blue]
- expected: FAIL
-
- [column-rule-color.repeat(4, blue red green) repeat(auto, red)]
- expected: FAIL
-
- [column-rule-color.blue red]
- expected: FAIL
-
- [column-rule-outset]
- expected: FAIL
-
- [column-rule-outset.10px]
- expected: FAIL
-
- [column-rule-outset.50%]
- expected: FAIL
-
- [column-rule-style]
- expected: FAIL
-
- [column-rule-style.none]
- expected: FAIL
-
- [column-rule-style.hidden]
- expected: FAIL
-
- [column-rule-style.dotted]
- expected: FAIL
-
- [column-rule-style.dashed]
- expected: FAIL
-
- [column-rule-style.solid]
- expected: FAIL
-
- [column-rule-style.double]
- expected: FAIL
-
- [column-rule-style.groove]
- expected: FAIL
-
- [column-rule-style.ridge]
- expected: FAIL
-
- [column-rule-style.inset]
- expected: FAIL
-
- [column-rule-style.outset]
- expected: FAIL
-
- [column-rule-style.dotted dashed]
- expected: FAIL
-
- [column-rule-style.repeat(3, dotted)]
- expected: FAIL
-
- [column-rule-width]
- expected: FAIL
-
- [column-rule-width.10px]
- expected: FAIL
-
- [column-rule-width.thin]
- expected: FAIL
-
- [column-rule-width.medium]
- expected: FAIL
-
- [column-rule-width.thick]
- expected: FAIL
-
- [row-rule-break]
- expected: FAIL
-
- [row-rule-break.none]
- expected: FAIL
-
- [row-rule-break.spanning-item]
- expected: FAIL
-
- [row-rule-break.intersection]
- expected: FAIL
-
- [row-rule-color]
- expected: FAIL
-
- [row-rule-color.red]
- expected: FAIL
-
- [row-rule-color.blue]
- expected: FAIL
-
- [row-rule-color.repeat(4, blue red green) repeat(auto, red)]
- expected: FAIL
-
- [row-rule-color.blue red]
- expected: FAIL
-
- [row-rule-outset]
- expected: FAIL
-
- [row-rule-outset.10px]
- expected: FAIL
-
- [row-rule-outset.50%]
- expected: FAIL
-
- [row-rule-style]
- expected: FAIL
-
- [row-rule-style.none]
- expected: FAIL
-
- [row-rule-style.hidden]
- expected: FAIL
-
- [row-rule-style.dotted]
- expected: FAIL
-
- [row-rule-style.dashed]
- expected: FAIL
-
- [row-rule-style.solid]
- expected: FAIL
-
- [row-rule-style.double]
- expected: FAIL
-
- [row-rule-style.groove]
- expected: FAIL
-
- [row-rule-style.ridge]
- expected: FAIL
-
- [row-rule-style.inset]
- expected: FAIL
-
- [row-rule-style.outset]
- expected: FAIL
-
- [row-rule-style.dotted dashed]
- expected: FAIL
-
- [row-rule-style.repeat(3, dotted)]
- expected: FAIL
-
- [row-rule-width]
- expected: FAIL
-
- [row-rule-width.10px]
- expected: FAIL
-
- [row-rule-width.thin]
- expected: FAIL
-
- [row-rule-width.medium]
- expected: FAIL
-
- [row-rule-width.thick]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-mixins/dashed-function-cycles.html.ini b/tests/wpt/meta/css/css-mixins/dashed-function-cycles.html.ini
index 7faf9c2b2e4..e669e57fb2e 100644
--- a/tests/wpt/meta/css/css-mixins/dashed-function-cycles.html.ini
+++ b/tests/wpt/meta/css/css-mixins/dashed-function-cycles.html.ini
@@ -73,3 +73,6 @@
[Locals are function specific]
expected: FAIL
+
+ [Local with self-cycle in unused fallback]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-mixins/local-attr-substitution.html.ini b/tests/wpt/meta/css/css-mixins/local-attr-substitution.html.ini
index 91d1e249d4e..20b0a33e2b6 100644
--- a/tests/wpt/meta/css/css-mixins/local-attr-substitution.html.ini
+++ b/tests/wpt/meta/css/css-mixins/local-attr-substitution.html.ini
@@ -19,3 +19,6 @@
[attr() cycle through function]
expected: FAIL
+
+ [attr() cycle through unused fallback in local]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-overflow/overflow-video.html.ini b/tests/wpt/meta/css/css-overflow/overflow-video.html.ini
new file mode 100644
index 00000000000..1d0a9d754d6
--- /dev/null
+++ b/tests/wpt/meta/css/css-overflow/overflow-video.html.ini
@@ -0,0 +1,2 @@
+[overflow-video.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-text/bidi/empty-span-001.html.ini b/tests/wpt/meta/css/css-text/bidi/empty-span-001.html.ini
new file mode 100644
index 00000000000..9c86908991d
--- /dev/null
+++ b/tests/wpt/meta/css/css-text/bidi/empty-span-001.html.ini
@@ -0,0 +1,2 @@
+[empty-span-001.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/attr-cycle.html.ini b/tests/wpt/meta/css/css-values/attr-cycle.html.ini
index 4fd32c202c1..8cdd7a59625 100644
--- a/tests/wpt/meta/css/css-values/attr-cycle.html.ini
+++ b/tests/wpt/meta/css/css-values/attr-cycle.html.ini
@@ -47,8 +47,14 @@
[CSS Values and Units Test: attr 18]
expected: FAIL
- [CSS Values and Units Test: attr 19]
+ [CSS Values and Units Test: attr 20]
expected: FAIL
- [CSS Values and Units Test: attr 20]
+ [CSS Values and Units Test: attr 15]
+ expected: FAIL
+
+ [CSS Values and Units Test: attr 17]
+ expected: FAIL
+
+ [CSS Values and Units Test: attr 21]
expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-function-descriptors.tentative.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-function-descriptors.tentative.html.ini
index 3c65d9bcf19..19644f0fe48 100644
--- a/tests/wpt/meta/css/css-values/tree-counting/sibling-function-descriptors.tentative.html.ini
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-function-descriptors.tentative.html.ini
@@ -22,3 +22,9 @@
[sibling-count() should not be allowed in @counter-style descriptors]
expected: FAIL
+
+ [sibling-index() should not be allowed in @font-feature-values descriptors]
+ expected: FAIL
+
+ [sibling-count() should not be allowed in @font-feature-values descriptors]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html.ini
new file mode 100644
index 00000000000..eb0a7a5e9dd
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html.ini
@@ -0,0 +1,6 @@
+[sibling-index-keyframe-font-variation-settings-dynamic.html]
+ [Initially, the sibling-index() is 3 for #target]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index()]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html.ini
new file mode 100644
index 00000000000..6b569fc343a
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html.ini
@@ -0,0 +1,6 @@
+[sibling-index-keyframe-font-weight-dynamic.html]
+ [Initially, the sibling-index() is 3 for #target]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index()]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html.ini
new file mode 100644
index 00000000000..a83235f2e08
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html.ini
@@ -0,0 +1,6 @@
+[sibling-index-keyframe-percent-dynamic.html]
+ [Initially, the sibling-index() is 3 for #target]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index()]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini
new file mode 100644
index 00000000000..807d5e54ab4
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html.ini
@@ -0,0 +1,54 @@
+[sibling-index-keyframe-registered-properties-dynamic.html]
+ [Initially, the sibling-index() is 3 for --time]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --angle]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --resolution]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --percentage]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --number]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --integer]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --length]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --length-percentage]
+ expected: FAIL
+
+ [Initially, the sibling-index() is 3 for --color]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --time]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --angle]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --resolution]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --percentage]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --number]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --integer]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --length]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --length-percentage]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index() for --color]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html.ini
new file mode 100644
index 00000000000..794bf34f831
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html.ini
@@ -0,0 +1,6 @@
+[sibling-index-keyframe-rotate-dynamic.html]
+ [Initially, the sibling-index() is 3 for #target]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index()]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html.ini b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html.ini
new file mode 100644
index 00000000000..504e2f50d1c
--- /dev/null
+++ b/tests/wpt/meta/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html.ini
@@ -0,0 +1,6 @@
+[sibling-index-keyframe-scale-dynamic.html]
+ [Initially, the sibling-index() is 3 for #target]
+ expected: FAIL
+
+ [Removing a preceding sibling of #target reduces the sibling-index()]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-variables/variable-cycles.html.ini b/tests/wpt/meta/css/css-variables/variable-cycles.html.ini
new file mode 100644
index 00000000000..a1fa15bd634
--- /dev/null
+++ b/tests/wpt/meta/css/css-variables/variable-cycles.html.ini
@@ -0,0 +1,3 @@
+[variable-cycles.html]
+ [Cycle in unused fallback]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/css-variables/variable-substitution-variable-declaration.html.ini b/tests/wpt/meta/css/css-variables/variable-substitution-variable-declaration.html.ini
new file mode 100644
index 00000000000..735752f3430
--- /dev/null
+++ b/tests/wpt/meta/css/css-variables/variable-substitution-variable-declaration.html.ini
@@ -0,0 +1,12 @@
+[variable-substitution-variable-declaration.html]
+ [target6 --varC]
+ expected: FAIL
+
+ [target7 --varC]
+ expected: FAIL
+
+ [target9 --varB]
+ expected: FAIL
+
+ [target9 --varC]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/filter-effects/hidpi-invert-filter-background.html.ini b/tests/wpt/meta/css/filter-effects/hidpi-invert-filter-background.html.ini
new file mode 100644
index 00000000000..cc4d44f0620
--- /dev/null
+++ b/tests/wpt/meta/css/filter-effects/hidpi-invert-filter-background.html.ini
@@ -0,0 +1,2 @@
+[hidpi-invert-filter-background.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/selectors/invalidation/has-with-nth-child-sibling-remove.html.ini b/tests/wpt/meta/css/selectors/invalidation/has-with-nth-child-sibling-remove.html.ini
new file mode 100644
index 00000000000..58a45ec370c
--- /dev/null
+++ b/tests/wpt/meta/css/selectors/invalidation/has-with-nth-child-sibling-remove.html.ini
@@ -0,0 +1,2 @@
+[has-with-nth-child-sibling-remove.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html.ini b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html.ini
deleted file mode 100644
index 60a4fa51f8a..00000000000
--- a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[a-click.html]
- [aElement.click() before the load event must NOT replace]
- expected: FAIL
diff --git a/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini b/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
deleted file mode 100644
index d6188c03424..00000000000
--- a/tests/wpt/meta/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[traverse_the_history_4.html]
- [Multiple history traversals, last would be aborted]
- expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini b/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini
new file mode 100644
index 00000000000..dbbc149ee4a
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/media-elements/media_fragment_seek.html.ini
@@ -0,0 +1,2 @@
+[media_fragment_seek.html]
+ expected: CRASH
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html.ini
new file mode 100644
index 00000000000..e07fe430a2b
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html.ini
@@ -0,0 +1,7 @@
+[embed-javascript-url.html]
+ expected: TIMEOUT
+ [location.href = 'javascript:"test"' should fire a load event]
+ expected: TIMEOUT
+
+ [location.href = 'javascript:1' should not fire a load event]
+ expected: NOTRUN
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html.ini
index 0c94be22223..920391c61dd 100644
--- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html.ini
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html.ini
@@ -1,3 +1,6 @@
[iframe-loading-lazy-reload-navigation-reload.html]
[Reloading iframe loading='lazy' before it is loaded: location.reload]
expected: FAIL
+
+ [Reloading iframe loading='lazy' before it is loaded: navigation.reload]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm.ini
new file mode 100644
index 00000000000..66d33308cd7
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm.ini
@@ -0,0 +1,40 @@
+[iframe_javascript_url_in_src.htm]
+ expected: TIMEOUT
+ [String object: javascript:new String("foo")]
+ expected: TIMEOUT
+
+ [undefined: javascript:void(0)]
+ expected: TIMEOUT
+
+ [number: javascript:1]
+ expected: TIMEOUT
+
+ [boolean: javascript:true]
+ expected: TIMEOUT
+
+ [null: javascript:null]
+ expected: TIMEOUT
+
+ [global: javascript:window]
+ expected: TIMEOUT
+
+ [host object: javascript:document]
+ expected: TIMEOUT
+
+ [function: javascript:(() => { return function() {}; })()]
+ expected: TIMEOUT
+
+ [regexp: javascript:/foo/]
+ expected: TIMEOUT
+
+ [array: javascript:["foo"\]]
+ expected: TIMEOUT
+
+ [object: javascript:{"foo": "bar"}]
+ expected: TIMEOUT
+
+ [ArrayBuffer: javascript:new ArrayBuffer(8)]
+ expected: TIMEOUT
+
+ [TypeError: javascript:new TypeError("foo")]
+ expected: TIMEOUT
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html.ini
new file mode 100644
index 00000000000..0df7c29c568
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html.ini
@@ -0,0 +1,3 @@
+[iframe_javascript_url_initial_insertion.html]
+ [javascript: URL in iframe src, initial insertion check]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm.ini
new file mode 100644
index 00000000000..8a829e693a7
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm.ini
@@ -0,0 +1,3 @@
+[iframe_javascript_url_loading_lazy.htm]
+ [javascript: URL in iframe src and loading="lazy"]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html.ini
new file mode 100644
index 00000000000..2731e6d0a84
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html.ini
@@ -0,0 +1,3 @@
+[iframe_javascript_url_not_about_blank.html]
+ [javascript: URL in iframe src, initial src is not about:blank]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html.ini
new file mode 100644
index 00000000000..d4d519b44f6
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html.ini
@@ -0,0 +1,3 @@
+[iframe_javascript_url_remove_srcdoc.html]
+ [javascript: URL in iframe src, removing srcdoc]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html.ini
new file mode 100644
index 00000000000..5c4c37fa7e1
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html.ini
@@ -0,0 +1,90 @@
+[naturalWidth-naturalHeight-unavailable.tentative.html]
+ [SVG image, no natural dimensions]
+ expected: FAIL
+
+ [SVG image, percengage natural dimensions]
+ expected: FAIL
+
+ [SVG image, negative percengage natural dimensions]
+ expected: FAIL
+
+ [SVG image, with natural width]
+ expected: FAIL
+
+ [SVG image, with natural height]
+ expected: FAIL
+
+ [SVG image, with natural width of 0]
+ expected: FAIL
+
+ [SVG image, with natural height of 0]
+ expected: FAIL
+
+ [SVG image, with natural width being negative]
+ expected: FAIL
+
+ [SVG image, with natural height being negative]
+ expected: FAIL
+
+ [SVG image, no natural dimensions, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, percengage natural dimensions, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, negative percengage natural dimensions, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural width, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural height, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural width of 0, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural height of 0, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural width being negative, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural height being negative, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, no natural dimensions, viewBox with 0 width/height]
+ expected: FAIL
+
+ [SVG image, no natural dimensions, viewBox with 0 width]
+ expected: FAIL
+
+ [SVG image, no natural dimensions, viewBox with 0 height]
+ expected: FAIL
+
+ [SVG image, with natural width, viewBox with 0 width/height]
+ expected: FAIL
+
+ [SVG image, with natural width, viewBox with 0 width]
+ expected: FAIL
+
+ [SVG image, with natural width, viewBox with 0 height]
+ expected: FAIL
+
+ [SVG image, with natural height, viewBox with 0 width/height]
+ expected: FAIL
+
+ [SVG image, with natural height, viewBox with 0 width]
+ expected: FAIL
+
+ [SVG image, with natural height, viewBox with 0 height]
+ expected: FAIL
+
+ [SVG image, with natural width and height, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural width and height of 0, and aspect ratio from viewBox]
+ expected: FAIL
+
+ [SVG image, with natural width and height being negative, and aspect ratio from viewBox]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-object-element/object-javascript-url.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-object-element/object-javascript-url.html.ini
new file mode 100644
index 00000000000..d1c90754358
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-object-element/object-javascript-url.html.ini
@@ -0,0 +1,7 @@
+[object-javascript-url.html]
+ expected: TIMEOUT
+ [location.href = 'javascript:"test"' should fire a load event]
+ expected: TIMEOUT
+
+ [location.href = 'javascript:1' should not fire a load event]
+ expected: NOTRUN
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm.ini b/tests/wpt/meta/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm.ini
new file mode 100644
index 00000000000..4cb15eeee5e
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm.ini
@@ -0,0 +1,3 @@
+[intrinsic_sizes.htm]
+ [default object size after src is removed]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html.ini b/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html.ini
new file mode 100644
index 00000000000..4f7b9917493
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html.ini
@@ -0,0 +1,3 @@
+[selectedcontent-mutations.tentative.html]
+ [MutationObserver records during parsing of <select> with <selectedcontent>]
+ expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/permission-element/display-css-property-reftest.tentative.html.ini b/tests/wpt/meta/html/semantics/permission-element/display-css-property-reftest.tentative.html.ini
deleted file mode 100644
index 01e47dd8995..00000000000
--- a/tests/wpt/meta/html/semantics/permission-element/display-css-property-reftest.tentative.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[display-css-property-reftest.tentative.html]
- expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/permission-element/display-css-property.tentative.html.ini b/tests/wpt/meta/html/semantics/permission-element/display-css-property.tentative.html.ini
deleted file mode 100644
index 3653fbe90d3..00000000000
--- a/tests/wpt/meta/html/semantics/permission-element/display-css-property.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[display-css-property.tentative.html]
- ['display' should be either 'inline-block' or 'none']
- expected: FAIL
diff --git a/tests/wpt/meta/html/semantics/popovers/popover-toggle-source.tentative.html.ini b/tests/wpt/meta/html/semantics/popovers/popover-toggle-source.tentative.html.ini
new file mode 100644
index 00000000000..0792a3bfa23
--- /dev/null
+++ b/tests/wpt/meta/html/semantics/popovers/popover-toggle-source.tentative.html.ini
@@ -0,0 +1,21 @@
+[popover-toggle-source.tentative.html]
+ [ToggleEvent.source on popover elements: showPopover() without source.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: showPopover() with source.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: Calling click() on a popovertarget button.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: Calling click() on a command button.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: showPopover() then popovertarget button.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: showPopover(invoker) then popovertarget button.]
+ expected: FAIL
+
+ [ToggleEvent.source on popover elements: popovertarget button then hidePopover().]
+ expected: FAIL
diff --git a/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini b/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini
index fb5e4d1adbe..20d32f43049 100644
--- a/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini
+++ b/tests/wpt/meta/navigation-timing/test-navigation-type-reload.html.ini
@@ -16,9 +16,3 @@
[Reload fetchStart > Original fetchStart]
expected: FAIL
-
- [Reload domContentLoadedEventEnd > Original domContentLoadedEventEnd]
- expected: FAIL
-
- [Reload domComplete > Original domComplete]
- expected: FAIL
diff --git a/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini b/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini
deleted file mode 100644
index 5d07f60e0b6..00000000000
--- a/tests/wpt/meta/resize-observer/change-layout-in-error.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[change-layout-in-error.html]
- [Changing layout in window error handler should not result in lifecyle loop when resize observer loop limit is reached.]
- expected: FAIL
diff --git a/tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.https.html.ini b/tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.html.ini
index 8634900f9c2..e736aad10ce 100644
--- a/tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.https.html.ini
+++ b/tests/wpt/meta/subresource-integrity/tentative/integrity-policy/parsing.html.ini
@@ -1,9 +1,8 @@
-[parsing.https.html?type=enforce]
+[parsing.html?type=report]
+
+[parsing.html?type=enforce]
[Ensure that test is working with a valid destination]
expected: FAIL
[Ensure that test is working with a valid destination and source]
expected: FAIL
-
-
-[parsing.https.html?type=report]
diff --git a/tests/wpt/meta/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html.ini b/tests/wpt/meta/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html.ini
new file mode 100644
index 00000000000..3165f13d148
--- /dev/null
+++ b/tests/wpt/meta/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html.ini
@@ -0,0 +1,2 @@
+[script-src-allows-source-phase-wasm.tentative.html]
+ expected: ERROR
diff --git a/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html.ini b/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html.ini
new file mode 100644
index 00000000000..00fce44edf8
--- /dev/null
+++ b/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html.ini
@@ -0,0 +1,4 @@
+[source-phase-blocked-by-csp.tentative.html]
+ expected: TIMEOUT
+ [Importing a WebAssembly module should be guarded by script-src CSP.]
+ expected: NOTRUN
diff --git a/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-preload.tentative.html.ini b/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-preload.tentative.html.ini
new file mode 100644
index 00000000000..73015a5b451
--- /dev/null
+++ b/tests/wpt/meta/wasm/webapi/esm-integration/source-phase-preload.tentative.html.ini
@@ -0,0 +1,7 @@
+[source-phase-preload.tentative.html]
+ expected: TIMEOUT
+ [Static source phase import.]
+ expected: TIMEOUT
+
+ [Dynamic source phase import.]
+ expected: NOTRUN
diff --git a/tests/wpt/meta/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html.ini b/tests/wpt/meta/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html.ini
new file mode 100644
index 00000000000..d62d13afb69
--- /dev/null
+++ b/tests/wpt/meta/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html.ini
@@ -0,0 +1,3 @@
+[worklet-import-source-phase.tentative.https.html]
+ [Import a source phase module to a worklet]
+ expected: FAIL
diff --git a/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini b/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini
index c9d88fc368b..960779501c4 100644
--- a/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini
+++ b/tests/wpt/meta/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini
@@ -796,3 +796,12 @@
[X SNR (34.8385032008375 dB) is not greater than or equal to 65.737. Got 34.8385032008375.]
expected: FAIL
+
+ [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[14650\]\t-1.0451291387880701e-7\t8.6956524848937988e-1\t8.6956535300229376e-1\t1.0000001201898467e+0\t3.8985999999999999e-3\n\t[14651\]\t3.0547976493835449e-1\t8.9879405498504639e-1\t5.9331429004669189e-1\t6.6012262403823208e-1\t3.8985999999999999e-3\n\tMax AbsError of 8.6956535300229376e-1 at index of 14650.\n\tMax RelError of 1.0000001201898467e+0 at index of 14650.\n]
+ expected: FAIL
+
+ [X SNR (42.96525217144102 dB) is not greater than or equal to 65.737. Got 42.96525217144102.]
+ expected: FAIL
+
+ [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[14650\]\t2.4329547374028208e-17\t8.6956524848937988e-1\t8.6956524848937988e-1\t1.0000000000000000e+0\t3.8985999999999999e-3\n\t[14651\]\t3.0547976493835449e-1\t8.9879405498504639e-1\t5.9331429004669189e-1\t6.6012262403823208e-1\t3.8985999999999999e-3\n\tMax AbsError of 8.6956524848937988e-1 at index of 14650.\n\tMax RelError of 1.0000000000000000e+0 at index of 14650.\n]
+ expected: FAIL
diff --git a/tests/wpt/tests/.github/workflows/documentation.yml b/tests/wpt/tests/.github/workflows/documentation.yml
index 6c92e435c69..41cf7c331e1 100644
--- a/tests/wpt/tests/.github/workflows/documentation.yml
+++ b/tests/wpt/tests/.github/workflows/documentation.yml
@@ -2,7 +2,11 @@ name: documentation
on:
push:
branches:
- - ubuntu-24.04
+ - master
+ paths:
+ - 'docs/**'
+ - 'resources/**'
+ - 'tools/**'
pull_request:
paths:
- 'docs/**'
@@ -30,4 +34,4 @@ jobs:
- name: Run website_build.sh
run: ./tools/ci/website_build.sh
env:
- DEPLOY_TOKEN: dummy
+ DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
diff --git a/tests/wpt/tests/accelerometer/Accelerometer-iframe-access.https.html b/tests/wpt/tests/accelerometer/Accelerometer-iframe-access.https.html
index 56005696a7f..887c6139061 100644
--- a/tests/wpt/tests/accelerometer/Accelerometer-iframe-access.https.html
+++ b/tests/wpt/tests/accelerometer/Accelerometer-iframe-access.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/accelerometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/accelerometer/Accelerometer.https.html b/tests/wpt/tests/accelerometer/Accelerometer.https.html
index d422fef7264..6d6dae5c619 100644
--- a/tests/wpt/tests/accelerometer/Accelerometer.https.html
+++ b/tests/wpt/tests/accelerometer/Accelerometer.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/accelerometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/accelerometer/GravitySensor.https.html b/tests/wpt/tests/accelerometer/GravitySensor.https.html
index 0f98f3e00de..c632f0ffe31 100644
--- a/tests/wpt/tests/accelerometer/GravitySensor.https.html
+++ b/tests/wpt/tests/accelerometer/GravitySensor.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/accelerometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/accelerometer/LinearAccelerationSensor.https.html b/tests/wpt/tests/accelerometer/LinearAccelerationSensor.https.html
index 91035cc9628..c8883b4c8a1 100644
--- a/tests/wpt/tests/accelerometer/LinearAccelerationSensor.https.html
+++ b/tests/wpt/tests/accelerometer/LinearAccelerationSensor.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/accelerometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/ai/resources/util.js b/tests/wpt/tests/ai/resources/util.js
index 3e95a936304..84507a409e9 100644
--- a/tests/wpt/tests/ai/resources/util.js
+++ b/tests/wpt/tests/ai/resources/util.js
@@ -3,6 +3,12 @@ const kValidAvailabilities =
const kAvailableAvailabilities = ['downloadable', 'downloading', 'available'];
const kTestPrompt = 'Please write a sentence in English.';
+const kTestContext = 'This is a test; this is only a test.';
+
+const getId = (() => {
+ let idCount = 0;
+ return () => idCount++;
+})();
// Takes an array of dictionaries mapping keys to value arrays, e.g.:
// [ {Shape: ["Square", "Circle", undefined]}, {Count: [1, 2]} ]
@@ -175,3 +181,47 @@ async function testMonitor(createFunc, options = {}) {
}
return result;
}
+
+function run_iframe_test(iframe, test_name) {
+ const id = getId();
+ iframe.contentWindow.postMessage({id, type: test_name}, '*');
+ const {promise, resolve, reject} = Promise.withResolvers();
+ window.onmessage = message => {
+ if (message.data.id !== id) {
+ return;
+ }
+ if (message.data.success) {
+ resolve(message.data.success);
+ } else {
+ reject(message.data.err)
+ }
+ };
+ return promise;
+}
+
+function load_iframe(src, permission_policy) {
+ let iframe = document.createElement('iframe');
+ const {promise, resolve} = Promise.withResolvers();
+ iframe.onload = () => {
+ resolve(iframe);
+ };
+ iframe.src = src;
+ iframe.allow = permission_policy;
+ document.body.appendChild(iframe);
+ return promise;
+}
+
+async function createSummarizer(options = {}) {
+ await test_driver.bless();
+ return await Summarizer.create(options);
+}
+
+async function createWriter(options = {}) {
+ await test_driver.bless();
+ return await Writer.create(options);
+}
+
+async function createRewriter(options = {}) {
+ await test_driver.bless();
+ return await Rewriter.create(options);
+}
diff --git a/tests/wpt/tests/ai/rewriter/resources/iframe-helper.html b/tests/wpt/tests/ai/rewriter/resources/iframe-helper.html
new file mode 100644
index 00000000000..c9cefebfd74
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/resources/iframe-helper.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<script src="/resources/testdriver.js"></script>
+<body></body>
+<script>
+test_driver.set_test_context(parent);
+
+window.onmessage = async message => {
+ const { id, type } = message.data;
+ try {
+ switch (type) {
+ case 'RewriterCreate':
+ await test_driver.bless('Rewriter.create', Rewriter.create, window);
+ parent.postMessage({ id, success: 'Success' }, '*');
+ break;
+ case 'RewriterAvailability':
+ const availability = await Rewriter.availability();
+ parent.postMessage({ id, success: availability }, '*');
+ break;
+ }
+ } catch (err) {
+ parent.postMessage({ id, err: err }, '*');
+ }
+};
+</script>
diff --git a/tests/wpt/tests/ai/rewriter/rewriter-abort.tentative.https.window.js b/tests/wpt/tests/ai/rewriter/rewriter-abort.tentative.https.window.js
new file mode 100644
index 00000000000..0eb716f398b
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter-abort.tentative.https.window.js
@@ -0,0 +1,35 @@
+// META: title=Rewriter Abort
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async t => {
+ await testAbortPromise(t, signal => {
+ return createRewriter({signal: signal});
+ });
+}, 'Aborting Rewriter.create().');
+
+promise_test(async t => {
+ const rewriter = await createRewriter();
+ await testAbortPromise(t, signal => {
+ return rewriter.rewrite(kTestPrompt, { signal: signal });
+ });
+}, 'Aborting Rewriter.rewrite().');
+
+promise_test(async t => {
+ const rewriter = await createRewriter();
+ await testAbortReadableStream(t, signal => {
+ return rewriter.rewriteStreaming(kTestPrompt, { signal: signal });
+ });
+}, 'Aborting Rewriter.rewriteStreaming().');
+
+promise_test(async t => {
+ const rewriter = await createRewriter();
+ const controller = new AbortController();
+ const streamingResponse = rewriter.rewriteStreaming(
+ kTestPrompt, { signal: controller.signal });
+ for await (const chunk of streamingResponse); // Do nothing
+ controller.abort();
+}, 'Aborting Rewriter.rewriteStreaming() after finished reading.');
diff --git a/tests/wpt/tests/ai/rewriter/rewriter-availability-available.tentative.https.window.js b/tests/wpt/tests/ai/rewriter/rewriter-availability-available.tentative.https.window.js
new file mode 100644
index 00000000000..a2117486e23
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter-availability-available.tentative.https.window.js
@@ -0,0 +1,34 @@
+// META: title=Rewriter Availability Available
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ const availability = await Rewriter.availability();
+ assert_in_array(availability, kAvailableAvailabilities);
+}, 'Rewriter.availability() is available with no options');
+
+promise_test(async () => {
+ const availability = await Rewriter.availability({
+ tone: 'as-is',
+ format: 'as-is',
+ length: 'as-is',
+ expectedInputLanguages: ['en-GB'],
+ expectedContextLanguages: ['en'],
+ outputLanguage: 'en',
+ });
+ assert_in_array(availability, kAvailableAvailabilities);
+}, 'Rewriter.availability() returns available with supported options');
+
+promise_test(async () => {
+ const availability = await Rewriter.availability({
+ tone: 'as-is',
+ format: 'as-is',
+ length: 'as-is',
+ expectedInputLanguages: ['es'], // not supported
+ expectedContextLanguages: ['en'],
+ outputLanguage: 'es', // not supported
+ });
+ assert_equals(availability, 'unavailable');
+}, 'Rewriter.availability() returns unavailable for unsupported languages');
diff --git a/tests/wpt/tests/ai/rewriter/rewriter-availability.tentative.https.window.js b/tests/wpt/tests/ai/rewriter/rewriter-availability.tentative.https.window.js
new file mode 100644
index 00000000000..e966b5df31e
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter-availability.tentative.https.window.js
@@ -0,0 +1,31 @@
+// META: title=Rewriter Availability
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ assert_true(!!Rewriter);
+ assert_equals(typeof Rewriter.availability, 'function');
+}, 'Rewriter.availability() is defined');
+
+promise_test(async () => {
+ const availability = await Rewriter.availability();
+ assert_in_array(availability, kValidAvailabilities);
+}, 'Rewriter.availability() returns a valid value with no options');
+
+promise_test(async () => {
+ // An array of plausible test option values.
+ const kCreateOptionsSpec = [
+ {tone: [undefined, 'as-is', 'more-formal', 'more-casual']},
+ {format: [undefined, 'as-is', 'plain-text', 'markdown']},
+ {length: [undefined, 'as-is', 'shorter', 'longer']},
+ {expectedInputLanguages: [[], ['en'], ['es'], ['jp', 'fr']]},
+ {expectedContextLanguages: [[], ['en'], ['es'], ['jp', 'fr']]},
+ {outputLanguage: [undefined, 'en', 'es', 'jp', 'fr']}
+ ];
+ for (const options of generateOptionCombinations(kCreateOptionsSpec)) {
+ const availability = await Rewriter.availability(options);
+ assert_in_array(availability, kValidAvailabilities, options);
+ }
+}, 'Rewriter.availability() returns a valid value with plausible options');
diff --git a/tests/wpt/tests/ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.js b/tests/wpt/tests/ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.js
new file mode 100644
index 00000000000..d7c473438cf
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.js
@@ -0,0 +1,56 @@
+// META: title=Rewriter Detached Iframe
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Rewriter create()', null, iframe.contentWindow);
+ iframe.contentWindow.Rewriter.create();
+ iframe.remove();
+}, 'Detaching iframe during Rewriter.create() should not leak memory');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Rewriter create()', null, iframe.contentWindow);
+ const iframeWindow = iframe.contentWindow;
+ const iframeDOMException = iframeWindow.DOMException;
+ const iframeRewriter = iframeWindow.Rewriter;
+ iframe.remove();
+
+ await promise_rejects_dom(
+ t, 'InvalidStateError', iframeDOMException, iframeRewriter.create());
+}, 'Rewriter.create() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Rewriter create()', null, iframe.contentWindow);
+ const iframeDOMException = iframe.contentWindow.DOMException;
+ const rewriter = await iframe.contentWindow.Rewriter.create();
+ iframe.remove();
+
+ await promise_rejects_dom(
+ t, 'InvalidStateError', iframeDOMException, rewriter.rewrite('hello'));
+}, 'Rewriter.rewrite() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Rewriter create()', null, iframe.contentWindow);
+ const iframeWindow = iframe.contentWindow;
+ const iframeDOMException = iframeWindow.DOMException;
+ const rewriter = await iframeWindow.Rewriter.create();
+ iframe.remove();
+
+ assert_throws_dom(
+ 'InvalidStateError', iframeDOMException, () => rewriter.rewriteStreaming('hello'));
+}, 'Rewriter.rewriteStreaming() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Rewriter create()', null, iframe.contentWindow);
+ const rewriter = await iframe.contentWindow.Rewriter.create();
+ rewriter.rewrite('hello');
+ iframe.remove();
+}, 'Detaching iframe during Rewriter.rewrite() should not leak memory');
diff --git a/tests/wpt/tests/ai/rewriter/rewriter-iframe.tentative.https.html b/tests/wpt/tests/ai/rewriter/rewriter-iframe.tentative.https.html
new file mode 100644
index 00000000000..202ee780af7
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter-iframe.tentative.https.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="../resources/util.js"></script>
+<body></body>
+<script>
+'use strict';
+
+const { HTTPS_ORIGIN, HTTPS_NOTSAMESITE_ORIGIN } = get_host_info();
+const PATH = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
+const IFRAME_PATH = PATH + 'resources/iframe-helper.html';
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ await promise_rejects_dom(t, 'NotAllowedError', run_iframe_test(iframe, 'RewriterCreate'));
+}, 'Throw a \'NotAllowedError\' when creating Rewriter within cross-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, 'rewriter');
+ assert_equals(await run_iframe_test(iframe, 'RewriterCreate'), 'Success');
+}, 'Rewriter can be created within cross-origin iframe with permission policy');
+
+promise_test(async t => {
+ const src = HTTPS_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(await run_iframe_test(iframe, 'RewriterCreate'), 'Success');
+}, 'Rewriter can be used within same-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(
+ await run_iframe_test(iframe, 'RewriterAvailability'), 'unavailable');
+}, 'Rewriter is unavailable within cross-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, 'rewriter');
+ assert_in_array(
+ await run_iframe_test(iframe, 'RewriterAvailability'),
+ kAvailableAvailabilities);
+}, 'Rewriter is available within cross-origin iframe with permission policy');
+
+promise_test(async t => {
+ const src = HTTPS_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_in_array(
+ await run_iframe_test(iframe, 'RewriterAvailability'),
+ kAvailableAvailabilities);
+}, 'Rewriter is available within same-origin iframe');
+
+</script>
diff --git a/tests/wpt/tests/ai/rewriter/rewriter.tentative.https.window.js b/tests/wpt/tests/ai/rewriter/rewriter.tentative.https.window.js
new file mode 100644
index 00000000000..da3f002a82b
--- /dev/null
+++ b/tests/wpt/tests/ai/rewriter/rewriter.tentative.https.window.js
@@ -0,0 +1,173 @@
+// META: title=Rewriter
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ assert_true(!!Rewriter);
+}, 'Rewriter must be defined.');
+
+promise_test(async t => {
+ // Creating Rewriter without user activation rejects with NotAllowedError.
+ await promise_rejects_dom(t, 'NotAllowedError', Rewriter.create());
+
+ // Creating Rewriter with user activation succeeds.
+ await createRewriter();
+
+ // Expect available after create.
+ assert_equals(await Rewriter.availability(), 'available');
+
+ // Now that it is available, we should no longer need user activation.
+ await Rewriter.create();
+}, 'Rewriter.create() requires user activation when availability is "downloadable."');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ assert_equals(Object.prototype.toString.call(rewriter), '[object Rewriter]');
+}, 'Rewriter.create() must be return a Rewriter.');
+
+promise_test(async () => {
+ await testMonitor(createRewriter);
+}, 'Rewriter.create() notifies its monitor on downloadprogress');
+
+promise_test(async t => {
+ await testCreateMonitorWithAbort(t, Rewriter.create);
+}, 'Progress events are not emitted after aborted.');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ assert_equals(rewriter.sharedContext, '');
+ assert_equals(rewriter.tone, 'as-is');
+ assert_equals(rewriter.format, 'as-is');
+ assert_equals(rewriter.length, 'as-is');
+}, 'Rewriter.create() default values.');
+
+promise_test(async () => {
+ const sharedContext = 'This is a shared context string';
+ const rewriter = await createRewriter({sharedContext: sharedContext});
+ assert_equals(rewriter.sharedContext, sharedContext);
+}, 'Rewriter.sharedContext');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({tone: 'more-formal'});
+ assert_equals(rewriter.tone, 'more-formal');
+}, 'Creating a Rewriter with "more-formal" tone');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({tone: 'more-casual'});
+ assert_equals(rewriter.tone, 'more-casual');
+}, 'Creating a Rewriter with "more-casual" tone');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({format: 'plain-text'});
+ assert_equals(rewriter.format, 'plain-text');
+}, 'Creating a Rewriter with "plain-text" format');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({format: 'markdown'});
+ assert_equals(rewriter.format, 'markdown');
+}, 'Creating a Rewriter with "markdown" format');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({length: 'shorter'});
+ assert_equals(rewriter.length, 'shorter');
+}, 'Creating a Rewriter with "shorter" length');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({length: 'longer'});
+ assert_equals(rewriter.length, 'longer');
+}, 'Creating a Rewriter with "longer" length');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({expectedInputLanguages: ['en']});
+ assert_array_equals(rewriter.expectedInputLanguages, ['en']);
+}, 'Creating a Rewriter with expectedInputLanguages');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({expectedContextLanguages: ['en']});
+ assert_array_equals(rewriter.expectedContextLanguages, ['en']);
+}, 'Creating a Rewriter with expectedContextLanguages');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({outputLanguage: 'en'});
+ assert_equals(rewriter.outputLanguage, 'en');
+}, 'Creating a Rewriter with outputLanguage');
+
+promise_test(async () => {
+ const rewriter = await createRewriter({});
+ assert_equals(rewriter.expectedInputLanguages, null);
+ assert_equals(rewriter.expectedContextLanguages, null);
+ assert_equals(rewriter.outputLanguage, null);
+}, 'Creating a Rewriter without optional attributes');
+
+promise_test(
+ async (t) => {
+ const rewriter = await createRewriter();
+ let result = await rewriter.rewrite('');
+ assert_equals(result, '');
+ result = await rewriter.rewrite(' ');
+ assert_equals(result, ' ');
+ },
+ 'Rewriter.rewrite() with an empty input or whitespace returns the ' +
+ 'original input');
+
+promise_test(async (t) => {
+ const rewriter = await createRewriter();
+ const result = await rewriter.rewrite('hello', {context: ' '});
+ assert_not_equals(result, '');
+}, 'Rewriter.rewrite() with a whitespace context returns a non-empty result');
+
+promise_test(async (t) => {
+ const rewriter = await createRewriter();
+ rewriter.destroy();
+ await promise_rejects_dom(t, 'InvalidStateError', rewriter.rewrite('hello'));
+}, 'Rewriter.rewrite() fails after destroyed');
+
+promise_test(async (t) => {
+ const rewriter = await createRewriter();
+ rewriter.destroy();
+ assert_throws_dom(
+ 'InvalidStateError', () => rewriter.rewriteStreaming('hello'));
+}, 'Rewriter.rewriteStreaming() fails after destroyed');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ const result = await rewriter.measureInputUsage(kTestPrompt);
+ assert_greater_than(result, 0);
+}, 'Rewriter.measureInputUsage() returns non-empty result');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ const result = await rewriter.rewrite(kTestPrompt, {context: kTestContext});
+ assert_equals(typeof result, 'string');
+}, 'Simple Rewriter.rewrite() call');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ const streamingResponse =
+ rewriter.rewriteStreaming(kTestPrompt, {context: kTestContext});
+ assert_equals(
+ Object.prototype.toString.call(streamingResponse),
+ '[object ReadableStream]');
+ let result = '';
+ for await (const chunk of streamingResponse) {
+ result += chunk;
+ }
+ assert_greater_than(result.length, 0);
+}, 'Simple Rewriter.rewriteStreaming() call');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ await Promise.all(
+ [rewriter.rewrite(kTestPrompt), rewriter.rewrite(kTestPrompt)]);
+}, 'Multiple Rewriter.rewrite() calls are resolved successfully.');
+
+promise_test(async () => {
+ const rewriter = await createRewriter();
+ await Promise.all([
+ rewriter.rewriteStreaming(kTestPrompt),
+ rewriter.rewriteStreaming(kTestPrompt)
+ ]);
+}, 'Multiple Rewriter.rewriteStreaming() calls are resolved successfully.');
diff --git a/tests/wpt/tests/ai/summarizer/resources/iframe-helper.html b/tests/wpt/tests/ai/summarizer/resources/iframe-helper.html
index 8db84705a2b..2d417e04f62 100644
--- a/tests/wpt/tests/ai/summarizer/resources/iframe-helper.html
+++ b/tests/wpt/tests/ai/summarizer/resources/iframe-helper.html
@@ -1,21 +1,26 @@
<!DOCTYPE HTML>
<meta charset="utf-8">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body></body>
<script>
+test_driver.set_test_context(parent);
+
window.onmessage = async message => {
- switch (message.data.type) {
- case 'SummarizerCreate':
- Summarizer.create()
- .then(t => parent.postMessage('Success', '*'))
- .catch(err => parent.postMessage('Failure: ' + err.name, '*'));
- break;
- case 'SummarizerAvailability':
- Summarizer.availability({
- type: "tl;dr",
- format: "plain-text",
- length: "medium"})
- .then(availability => parent.postMessage(availability, '*'))
- .catch(err => parent.postMessage('Failure: ' + err.name, '*'));
- break;
- };
+ const { id, type } = message.data;
+ try {
+ switch (type) {
+ case 'SummarizerCreate':
+ await test_driver.bless('Summarizer.create', Summarizer.create, window);
+ parent.postMessage({id, success: 'Success'}, '*');
+ break;
+ case 'SummarizerAvailability':
+ const availability = await Summarizer.availability();
+ parent.postMessage({id, success: availability}, '*');
+ break;
+ }
+ } catch (err) {
+ parent.postMessage({id, err: err}, '*');
+ }
};
</script>
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-abort.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-abort.tentative.https.window.js
index 64595ea930c..14c89056dfb 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-abort.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-abort.tentative.https.window.js
@@ -1,25 +1,25 @@
// META: title=Summarizer Abort
-// META: global=window,worker
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
'use strict';
promise_test(async t => {
await testAbortPromise(t, signal => {
- return Summarizer.create({ signal: signal });
+ return createSummarizer({signal: signal});
});
-}, "Aborting Summarizer.create().");
+}, 'Aborting Summarizer.create().');
promise_test(async t => {
- const session = await Summarizer.create();
+ const session = await createSummarizer();
await testAbortPromise(t, signal => {
return session.summarize(kTestPrompt, { signal: signal });
});
-}, "Aborting Summarizer.summarize().");
+}, 'Aborting Summarizer.summarize().');
promise_test(async t => {
- const session = await Summarizer.create();
+ const session = await createSummarizer();
await testAbortReadableStream(t, signal => {
return session.summarizeStreaming(kTestPrompt, { signal: signal });
});
-}, "Aborting Summarizer.summarizeStreaming().");
+}, 'Aborting Summarizer.summarizeStreaming().');
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-availability-available.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-availability-available.tentative.https.window.js
index 31c21ca777f..f569cb43b0f 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-availability-available.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-availability-available.tentative.https.window.js
@@ -1,4 +1,5 @@
// META: title=Summarizer Availability Available
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-availability.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-availability.tentative.https.window.js
index 8691765f693..85282959f9e 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-availability.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-availability.tentative.https.window.js
@@ -1,4 +1,5 @@
// META: title=Summarizer Availability
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-create-available.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-create-available.tentative.https.window.js
index c7e27d9766b..1f108ddd021 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-create-available.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-create-available.tentative.https.window.js
@@ -1,11 +1,12 @@
// META: title=Summarizer Create Available
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
'use strict';
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
assert_equals(typeof summarizer, 'object');
assert_equals(typeof summarizer.summarize, 'function');
@@ -29,54 +30,52 @@ promise_test(async () => {
}, 'Summarizer.create() returns a valid object with default options');
promise_test(async () => {
- const summarizer = await testMonitor(Summarizer.create);
+ const summarizer = await testMonitor(createSummarizer);
assert_equals(typeof summarizer, 'object');
}, 'Summarizer.create() notifies its monitor on downloadprogress');
+promise_test(async t => {
+ await testCreateMonitorWithAbort(t, Summarizer.create);
+}, 'Progress events are not emitted after aborted.');
+
promise_test(async () => {
const sharedContext = 'This is a shared context string';
- const summarizer = await Summarizer.create({sharedContext: sharedContext});
+ const summarizer = await createSummarizer({sharedContext: sharedContext});
assert_equals(summarizer.sharedContext, sharedContext);
}, 'Summarizer.sharedContext');
promise_test(async () => {
- const summarizer = await Summarizer.create({type: 'headline'});
+ const summarizer = await createSummarizer({type: 'headline'});
assert_equals(summarizer.type, 'headline');
}, 'Summarizer.type');
promise_test(async () => {
- const summarizer = await Summarizer.create({format: 'plain-text'});
+ const summarizer = await createSummarizer({format: 'plain-text'});
assert_equals(summarizer.format, 'plain-text');
}, 'Summarizer.format');
promise_test(async () => {
- const summarizer = await Summarizer.create({length: 'medium'});
+ const summarizer = await createSummarizer({length: 'medium'});
assert_equals(summarizer.length, 'medium');
}, 'Summarizer.length');
promise_test(async () => {
- const summarizer = await Summarizer.create({
- expectedInputLanguages: ['en']
- });
+ const summarizer = await createSummarizer({expectedInputLanguages: ['en']});
assert_array_equals(summarizer.expectedInputLanguages, ['en']);
}, 'Summarizer.expectedInputLanguages');
promise_test(async () => {
- const summarizer = await Summarizer.create({
- expectedContextLanguages: ['en']
- });
+ const summarizer = await createSummarizer({expectedContextLanguages: ['en']});
assert_array_equals(summarizer.expectedContextLanguages, ['en']);
}, 'Summarizer.expectedContextLanguages');
promise_test(async () => {
- const summarizer = await Summarizer.create({
- outputLanguage: 'en'
- });
+ const summarizer = await createSummarizer({outputLanguage: 'en'});
assert_equals(summarizer.outputLanguage, 'en');
}, 'Summarizer.outputLanguage');
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
assert_equals(summarizer.expectedInputLanguages, null);
assert_equals(summarizer.expectedContextLanguages, null);
assert_equals(summarizer.outputLanguage, null);
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-create.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-create.tentative.https.window.js
index 328cceefefb..d9df70cc2e7 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-create.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-create.tentative.https.window.js
@@ -1,4 +1,5 @@
// META: title=Summarizer Create
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
@@ -8,3 +9,17 @@ promise_test(async () => {
assert_true(!!Summarizer);
assert_equals(typeof Summarizer.create, 'function');
}, 'Summarizer.create() is defined');
+
+promise_test(async t => {
+ // Creating Summarizer without user activation rejects with NotAllowedError.
+ await promise_rejects_dom(t, 'NotAllowedError', Summarizer.create());
+
+ // Creating Summarizer with user activation succeeds.
+ await createSummarizer();
+
+ // Expect available after create.
+ assert_equals(await Summarizer.availability(), 'available');
+
+ // Now that it is available, we should no longer need user activation.
+ await Summarizer.create();
+}, 'Summarizer.create() requires user activation when availability is "downloadable."');
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-iframe.tentative.https.html b/tests/wpt/tests/ai/summarizer/summarizer-iframe.tentative.https.html
index 219811c8831..9de80e1fd91 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-iframe.tentative.https.html
+++ b/tests/wpt/tests/ai/summarizer/summarizer-iframe.tentative.https.html
@@ -1,7 +1,11 @@
<!DOCTYPE html>
+<meta name="timeout" content="long">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
+<script src="../resources/util.js"></script>
<body></body>
<script>
'use strict';
@@ -10,106 +14,45 @@ const { HTTPS_ORIGIN, HTTPS_NOTSAMESITE_ORIGIN } = get_host_info();
const PATH = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
const IFRAME_PATH = PATH + 'resources/iframe-helper.html';
-function load_iframe(src, permission_policy, test_name) {
- let iframe = document.createElement('iframe');
- return new Promise((resolve, reject) => {
- iframe.onload = () => {
- iframe.contentWindow.postMessage({type: test_name}, '*');
- resolve(iframe);
- }
- iframe.src = src;
- iframe.allow = permission_policy;
- document.body.appendChild(iframe);
- });
-}
-
promise_test(async t => {
const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
- await load_iframe(src, /*permission_policy=*/"", "SummarizerCreate");
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data == 'Failure: NotAllowedError') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Throw a 'NotAllowedError' when creating Summarizer within cross-origin iframe");
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ await promise_rejects_dom(t, 'NotAllowedError', run_iframe_test(iframe, 'SummarizerCreate'));
+}, 'Throw a \'NotAllowedError\' when creating Summarizer within cross-origin iframe');
promise_test(async t => {
const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
- load_iframe(src, "summarizer", "SummarizerCreate");
-
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data == 'Success') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Summarizer can be created within cross-origin iframe with permission policy");
+ const iframe = await load_iframe(src, 'summarizer');
+ assert_equals(await run_iframe_test(iframe, 'SummarizerCreate'), 'Success');
+}, 'Summarizer can be created within cross-origin iframe with permission policy');
promise_test(async t => {
const src = HTTPS_ORIGIN + IFRAME_PATH;
- load_iframe(src, /*permission_policy=*/"", "SummarizerCreate");
-
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data == 'Success') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Summarizer can be used within same-origin iframe");
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(await run_iframe_test(iframe, 'SummarizerCreate'), 'Success');
+}, 'Summarizer can be used within same-origin iframe');
promise_test(async t => {
const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
- load_iframe(src, /*permission_policy=*/"", "SummarizerAvailability");
-
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data == 'unavailable') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Summarizer is unavailable within cross-origin iframe");
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(
+ await run_iframe_test(iframe, 'SummarizerAvailability'), 'unavailable');
+}, 'Summarizer is unavailable within cross-origin iframe');
promise_test(async t => {
const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
- load_iframe(src, "summarizer", "SummarizerAvailability");
-
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data != 'unavailable') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Summarizer is available within cross-origin iframe with permission policy");
+ const iframe = await load_iframe(src, 'summarizer');
+ assert_in_array(
+ await run_iframe_test(iframe, 'SummarizerAvailability'),
+ kAvailableAvailabilities);
+}, 'Summarizer is available within cross-origin iframe with permission policy');
promise_test(async t => {
const src = HTTPS_ORIGIN + IFRAME_PATH;
- load_iframe(src, /*permission_policy=*/"", "SummarizerAvailability");
-
- return new Promise((resolve, reject) => {
- window.onmessage = message => {
- if (message.data != 'unavailable') {
- resolve();
- } else {
- reject(message.data)
- }
- }
- });
-}, "Summarizer is available within same-origin iframe");
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_in_array(
+ await run_iframe_test(iframe, 'SummarizerAvailability'),
+ kAvailableAvailabilities);
+}, 'Summarizer is available within same-origin iframe');
</script>
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js
index ce9745acf17..8368096f1f3 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js
@@ -1,11 +1,12 @@
// META: title=Summarizer measureInputUsage
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
'use strict';
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
const result = await summarizer.measureInputUsage(kTestPrompt);
assert_equals(typeof result, 'number');
assert_greater_than(result, 0);
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js
index dbf41cdadbc..59aa01aeb31 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js
@@ -1,11 +1,12 @@
// META: title=Summarizer Summarize Streaming
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
'use strict';
promise_test(async t => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
const streamingResponse = summarizer.summarizeStreaming(
"The web-platform-tests Project is a cross-browser test suite for the Web-platform stack. Writing tests in a way that allows them to be run in all browsers gives browser projects confidence that they are shipping software that is compatible with other implementations, and that later implementations will be compatible with their implementations. This in turn gives Web authors/developers confidence that they can actually rely on the Web platform to deliver on the promise of working across browsers and devices without needing extra layers of abstraction to paper over the gaps left by specification editors and implementors.");
assert_equals(
@@ -19,13 +20,13 @@ promise_test(async t => {
if (done) {
break;
}
- result = value;
+ result += value;
}
assert_greater_than(result.length, 0);
}, 'Summarizer.summarizeStreaming() returns ReadableStream with a non-empty text.');
promise_test(async t => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
const streamingResponse = summarizer.summarizeStreaming("");
assert_equals(
Object.prototype.toString.call(streamingResponse),
@@ -36,7 +37,7 @@ promise_test(async t => {
}, 'Summarizer.summarizeStreaming() returns a ReadableStream without any chunk on an empty input.');
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
await Promise.all([
summarizer.summarizeStreaming(kTestPrompt),
summarizer.summarizeStreaming(kTestPrompt)
diff --git a/tests/wpt/tests/ai/summarizer/summarizer-summarize.tentative.https.window.js b/tests/wpt/tests/ai/summarizer/summarizer-summarize.tentative.https.window.js
index 62a780a3fc7..c54052f8b36 100644
--- a/tests/wpt/tests/ai/summarizer/summarizer-summarize.tentative.https.window.js
+++ b/tests/wpt/tests/ai/summarizer/summarizer-summarize.tentative.https.window.js
@@ -1,18 +1,19 @@
// META: title=Summarizer Create Available
+// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long
'use strict';
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
const result = await summarizer.summarize(kTestPrompt);
assert_equals(typeof result, 'string');
assert_greater_than(result.length, 0);
}, 'Summarizer.summarize() returns non-empty result.');
promise_test(async () => {
- const summarizer = await Summarizer.create();
+ const summarizer = await createSummarizer();
await Promise.all([
summarizer.summarize(kTestPrompt),
summarizer.summarize(kTestPrompt)
diff --git a/tests/wpt/tests/ai/translator/translator.optional.https.window.js b/tests/wpt/tests/ai/translator/translator.optional.https.window.js
index 96eca09d28b..2a4c5a6c5dd 100644
--- a/tests/wpt/tests/ai/translator/translator.optional.https.window.js
+++ b/tests/wpt/tests/ai/translator/translator.optional.https.window.js
@@ -57,14 +57,6 @@ promise_test(async t => {
assert_equals(translator.targetLanguage, 'ja');
}, 'Translator: sourceLanguage and targetLanguage are equal to their respective option passed in to Translator.create.');
-promise_test(async (t) => {
- const translator =
- await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
- translator.destroy();
- await promise_rejects_dom(
- t, 'InvalidStateError', translator.translate('hello'));
-}, 'Translator.translate() fails after destroyed');
-
promise_test(async t => {
const controller = new AbortController();
controller.abort();
@@ -103,11 +95,53 @@ promise_test(async t => {
}, 'Aborting Translator.translate().');
promise_test(async t => {
+ const translator =
+ await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
+
+ const text = 'this string is in English';
+ const promises =
+ [translator.translate(text), translator.measureInputUsage(text)];
+
+ translator.destroy();
+
+ promises.push(translator.translate(text), translator.measureInputUsage(text));
+
+ for (const promise of promises) {
+ await promise_rejects_dom(t, 'AbortError', promise);
+ }
+}, 'Calling Translator.destroy() aborts calls to translate and measureInputUsage.');
+
+promise_test(async t => {
+ const controller = new AbortController();
+ const translator = await createTranslator(
+ {sourceLanguage: 'en', targetLanguage: 'ja', signal: controller.signal});
+
+ const text = 'this string is in English';
+ const promises =
+ [translator.translate(text), translator.measureInputUsage(text)];
+
+ const error = new Error('The create abort signal was aborted.');
+ controller.abort(error);
+
+ promises.push(translator.translate(text), translator.measureInputUsage(text));
+
+ for (const promise of promises) {
+ await promise_rejects_exactly(t, error, promise);
+ }
+}, 'Translator.create()\'s abort signal destroys its Translator after creation.');
+
+
+promise_test(async t => {
await testMonitor(
createTranslator, {sourceLanguage: 'en', targetLanguage: 'ja'});
}, 'Translator.create() notifies its monitor on downloadprogress');
promise_test(async t => {
+ await testCreateMonitorWithAbort(
+ t, createTranslator, {sourceLanguage: 'en', targetLanguage: 'ja'});
+}, 'Progress events are not emitted after aborted.');
+
+promise_test(async t => {
const translator =
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
diff --git a/tests/wpt/tests/ai/writer/resources/iframe-helper.html b/tests/wpt/tests/ai/writer/resources/iframe-helper.html
new file mode 100644
index 00000000000..bca56e1ecfd
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/resources/iframe-helper.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<script src="/resources/testdriver.js"></script>
+
+<body></body>
+<script>
+ test_driver.set_test_context(parent);
+
+ window.onmessage = async message => {
+ const { id, type } = message.data;
+ try {
+ switch (type) {
+ case 'WriterCreate':
+ await test_driver.bless('Writer.create', Writer.create, window);
+ parent.postMessage({ id, success: 'Success' }, '*');
+ break;
+ case 'WriterAvailability':
+ const availability = await Writer.availability();
+ parent.postMessage({ id, success: availability }, '*');
+ break;
+ }
+ } catch (err) {
+ parent.postMessage({ id, err: err }, '*');
+ }
+ };
+</script> \ No newline at end of file
diff --git a/tests/wpt/tests/ai/writer/writer-abort.tentative.https.window.js b/tests/wpt/tests/ai/writer/writer-abort.tentative.https.window.js
new file mode 100644
index 00000000000..bb877f6d73b
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer-abort.tentative.https.window.js
@@ -0,0 +1,37 @@
+// META: title=Writer Abort
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async t => {
+ await testAbortPromise(t, signal => {
+ return createWriter({signal: signal});
+ });
+}, 'Aborting Writer.create().');
+
+promise_test(async t => {
+ const writer = await createWriter();
+ await testAbortPromise(t, signal => {
+ return writer.write(kTestPrompt, { signal: signal });
+ });
+}, 'Aborting Writer.write().');
+
+promise_test(async t => {
+ const writer = await createWriter();
+ await testAbortReadableStream(t, signal => {
+ return writer.writeStreaming(kTestPrompt, { signal: signal });
+ });
+}, 'Aborting Writer.writeStreaming().');
+
+promise_test(async (t) => {
+ const writer = await createWriter();
+ const controller = new AbortController();
+ const streamingResponse = writer.writeStreaming(kTestPrompt, {
+ signal: controller.signal,
+ context: kTestContext,
+ });
+ for await (const chunk of streamingResponse); // Do nothing
+ controller.abort();
+}, 'Aborting Writer.writeStreaming() after finished reading.');
diff --git a/tests/wpt/tests/ai/writer/writer-availability-available.tentative.https.window.js b/tests/wpt/tests/ai/writer/writer-availability-available.tentative.https.window.js
new file mode 100644
index 00000000000..0e3106a14c2
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer-availability-available.tentative.https.window.js
@@ -0,0 +1,34 @@
+// META: title=Writer Availability Available
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ const availability = await Writer.availability();
+ assert_in_array(availability, kAvailableAvailabilities);
+}, 'Writer.availability() is available with no options');
+
+promise_test(async () => {
+ const availability = await Writer.availability({
+ tone: 'neutral',
+ format: 'plain-text',
+ length: 'medium',
+ expectedInputLanguages: ['en-GB'],
+ expectedContextLanguages: ['en'],
+ outputLanguage: 'en',
+ });
+ assert_in_array(availability, kAvailableAvailabilities);
+}, 'Writer.availability() returns available with supported options');
+
+promise_test(async () => {
+ const availability = await Writer.availability({
+ tone: 'neutral',
+ format: 'plain-text',
+ length: 'medium',
+ expectedInputLanguages: ['es'], // not supported
+ expectedContextLanguages: ['en'],
+ outputLanguage: 'es', // not supported
+ });
+ assert_equals(availability, 'unavailable');
+}, 'Writer.availability() returns unavailable for unsupported languages');
diff --git a/tests/wpt/tests/ai/writer/writer-availability.tentative.https.window.js b/tests/wpt/tests/ai/writer/writer-availability.tentative.https.window.js
new file mode 100644
index 00000000000..a68b7d35e64
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer-availability.tentative.https.window.js
@@ -0,0 +1,31 @@
+// META: title=Writer Availability
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ assert_true(!!Writer);
+ assert_equals(typeof Writer.availability, 'function');
+}, 'Writer.availability() is defined');
+
+promise_test(async () => {
+ const availability = await Writer.availability();
+ assert_in_array(availability, kValidAvailabilities);
+}, 'Writer.availability() returns a valid value with no options');
+
+promise_test(async () => {
+ // An array of plausible test option values.
+ const kCreateOptionsSpec = [
+ {tone: [undefined, 'formal', 'neutral', 'casual']},
+ {format: [undefined, 'plain-text', 'markdown']},
+ {length: [undefined, 'short', 'medium', 'long']},
+ {expectedInputLanguages: [[], ['en'], ['es'], ['jp', 'fr']]},
+ {expectedContextLanguages: [[], ['en'], ['es'], ['jp', 'fr']]},
+ {outputLanguage: [undefined, 'en', 'es', 'jp', 'fr']}
+ ];
+ for (const options of generateOptionCombinations(kCreateOptionsSpec)) {
+ const availability = await Writer.availability(options);
+ assert_in_array(availability, kValidAvailabilities, options);
+ }
+}, 'Writer.availability() returns a valid value with plausible options');
diff --git a/tests/wpt/tests/ai/writer/writer-from-detached-iframe.tentative.https.window.js b/tests/wpt/tests/ai/writer/writer-from-detached-iframe.tentative.https.window.js
new file mode 100644
index 00000000000..c63d8bb77c9
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer-from-detached-iframe.tentative.https.window.js
@@ -0,0 +1,56 @@
+// META: title=Writer Detached Iframe
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Writer create()', null, iframe.contentWindow);
+ iframe.contentWindow.Writer.create();
+ iframe.remove();
+}, 'Detaching iframe during Writer.create() should not leak memory');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Writer create()', null, iframe.contentWindow);
+ const iframeWindow = iframe.contentWindow;
+ const iframeDOMException = iframeWindow.DOMException;
+ const iframeWriter = iframeWindow.Writer;
+ iframe.remove();
+
+ await promise_rejects_dom(
+ t, 'InvalidStateError', iframeDOMException, iframeWriter.create());
+}, 'Writer.create() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Writer create()', null, iframe.contentWindow);
+ const iframeDOMException = iframe.contentWindow.DOMException;
+ const writer = await iframe.contentWindow.Writer.create();
+ iframe.remove();
+
+ await promise_rejects_dom(
+ t, 'InvalidStateError', iframeDOMException, writer.write('hello'));
+}, 'Writer.write() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Writer create()', null, iframe.contentWindow);
+ const iframeWindow = iframe.contentWindow;
+ const iframeDOMException = iframeWindow.DOMException;
+ const writer = await iframeWindow.Writer.create();
+ iframe.remove();
+
+ assert_throws_dom(
+ 'InvalidStateError', iframeDOMException, () => writer.writeStreaming('hello'));
+}, 'Writer.writeStreaming() fails on a detached iframe.');
+
+promise_test(async (t) => {
+ const iframe = document.body.appendChild(document.createElement('iframe'));
+ await test_driver.bless('Writer create()', null, iframe.contentWindow);
+ const writer = await iframe.contentWindow.Writer.create();
+ writer.write('hello');
+ iframe.remove();
+}, 'Detaching iframe during Writer.write() should not leak memory');
diff --git a/tests/wpt/tests/ai/writer/writer-iframe.tentative.https.html b/tests/wpt/tests/ai/writer/writer-iframe.tentative.https.html
new file mode 100644
index 00000000000..004ba9ea307
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer-iframe.tentative.https.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="../resources/util.js"></script>
+<body></body>
+<script>
+'use strict';
+
+const { HTTPS_ORIGIN, HTTPS_NOTSAMESITE_ORIGIN } = get_host_info();
+const PATH = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
+const IFRAME_PATH = PATH + 'resources/iframe-helper.html';
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ await promise_rejects_dom(t, 'NotAllowedError', run_iframe_test(iframe, 'WriterCreate'));
+}, 'Throw a \'NotAllowedError\' when creating Writer within cross-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, 'writer');
+ assert_equals(await run_iframe_test(iframe, 'WriterCreate'), 'Success');
+}, 'Writer can be created within cross-origin iframe with permission policy');
+
+promise_test(async t => {
+ const src = HTTPS_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(await run_iframe_test(iframe, 'WriterCreate'), 'Success');
+}, 'Writer can be used within same-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_equals(
+ await run_iframe_test(iframe, 'WriterAvailability'), 'unavailable');
+}, 'Writer is unavailable within cross-origin iframe');
+
+promise_test(async t => {
+ const src = HTTPS_NOTSAMESITE_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, 'writer');
+ assert_in_array(
+ await run_iframe_test(iframe, 'WriterAvailability'),
+ kAvailableAvailabilities);
+}, 'Writer is available within cross-origin iframe with permission policy');
+
+promise_test(async t => {
+ const src = HTTPS_ORIGIN + IFRAME_PATH;
+ const iframe = await load_iframe(src, /*permission_policy=*/'');
+ assert_in_array(
+ await run_iframe_test(iframe, 'WriterAvailability'),
+ kAvailableAvailabilities);
+}, 'Writer is available within same-origin iframe');
+
+</script>
diff --git a/tests/wpt/tests/ai/writer/writer.tentative.https.window.js b/tests/wpt/tests/ai/writer/writer.tentative.https.window.js
new file mode 100644
index 00000000000..6606f217448
--- /dev/null
+++ b/tests/wpt/tests/ai/writer/writer.tentative.https.window.js
@@ -0,0 +1,175 @@
+// META: title=Writer
+// META: script=/resources/testdriver.js
+// META: script=../resources/util.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async () => {
+ assert_true(!!Writer);
+}, 'Writer must be defined.');
+
+promise_test(async t => {
+ // Creating Writer without user activation rejects with NotAllowedError.
+ await promise_rejects_dom(t, 'NotAllowedError', Writer.create());
+
+ // Creating Writer with user activation succeeds.
+ await createWriter();
+
+ // Expect available after create.
+ assert_equals(await Writer.availability(), 'available');
+
+ // Now that it is available, we should no longer need user activation.
+ await Writer.create();
+}, 'Writer.create() requires user activation when availability is "downloadable."');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ assert_equals(Object.prototype.toString.call(writer), '[object Writer]');
+}, 'Writer.create() must be return a Writer.');
+
+promise_test(async () => {
+ await testMonitor(createWriter);
+}, 'Writer.create() notifies its monitor on downloadprogress');
+
+promise_test(async t => {
+ await testCreateMonitorWithAbort(t, Writer.create);
+}, 'Progress events are not emitted after aborted.');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ assert_equals(writer.sharedContext, '');
+ assert_equals(writer.tone, 'neutral');
+ assert_equals(writer.format, 'plain-text');
+ assert_equals(writer.length, 'medium');
+}, 'Writer.create() default values.');
+
+promise_test(async (t) => {
+ const controller = new AbortController();
+ controller.abort();
+ const createPromise = createWriter({signal: controller.signal});
+ await promise_rejects_dom(t, 'AbortError', createPromise);
+}, 'Writer.create() call with an aborted signal.');
+
+promise_test(async () => {
+ const sharedContext = 'This is a shared context string';
+ const writer = await createWriter({sharedContext: sharedContext});
+ assert_equals(writer.sharedContext, sharedContext);
+}, 'Writer.sharedContext');
+
+promise_test(async () => {
+ const writer = await createWriter({tone: 'formal'});
+ assert_equals(writer.tone, 'formal');
+}, 'Creating a Writer with "formal" tone');
+
+promise_test(async () => {
+ const writer = await createWriter({tone: 'casual'});
+ assert_equals(writer.tone, 'casual');
+}, 'Creating a Writer with "casual" tone');
+
+promise_test(async () => {
+ const writer = await createWriter({format: 'markdown'});
+ assert_equals(writer.format, 'markdown');
+}, 'Creating a Writer with "markdown" format');
+
+promise_test(async () => {
+ const writer = await createWriter({length: 'short'});
+ assert_equals(writer.length, 'short');
+}, 'Creating a Writer with "short" length');
+
+promise_test(async () => {
+ const writer = await createWriter({length: 'long'});
+ assert_equals(writer.length, 'long');
+}, 'Creating a Writer with "long" length');
+
+promise_test(async () => {
+ const writer = await createWriter({expectedInputLanguages: ['en']});
+ assert_array_equals(writer.expectedInputLanguages, ['en']);
+}, 'Creating a Writer with expectedInputLanguages');
+
+
+promise_test(async (t) => {
+ promise_rejects_js(
+ t, RangeError,
+ createWriter({expectedInputLanguages: ['en-abc-invalid']}));
+}, 'Creating a Writer with malformed language string');
+
+promise_test(async () => {
+ const writer = await createWriter({expectedContextLanguages: ['en']});
+ assert_array_equals(writer.expectedContextLanguages, ['en']);
+}, 'Creating a Writer with expectedContextLanguages');
+
+promise_test(async () => {
+ const writer = await createWriter({outputLanguage: 'en'});
+ assert_equals(writer.outputLanguage, 'en');
+}, 'Creating a Writer with outputLanguage');
+
+promise_test(async () => {
+ const writer = await createWriter({});
+ assert_equals(writer.expectedInputLanguages, null);
+ assert_equals(writer.expectedContextLanguages, null);
+ assert_equals(writer.outputLanguage, null);
+}, 'Creating a Writer without optional attributes');
+
+promise_test(async (t) => {
+ const writer = await createWriter();
+ let result = await writer.write('');
+ assert_equals(result, '');
+ result = await writer.write(' ');
+ assert_equals(result, '');
+}, 'Writer.write() with an empty input or whitespace returns an empty text');
+
+promise_test(async (t) => {
+ const writer = await createWriter();
+ const result = await writer.write('hello', {context: ' '});
+ assert_not_equals(result, '');
+}, 'Writer.write() with a whitespace context returns a non-empty result');
+
+promise_test(async (t) => {
+ const writer = await createWriter();
+ writer.destroy();
+ await promise_rejects_dom(t, 'InvalidStateError', writer.write('hello'));
+}, 'Writer.write() fails after destroyed');
+
+promise_test(async (t) => {
+ const writer = await createWriter();
+ writer.destroy();
+ assert_throws_dom('InvalidStateError', () => writer.writeStreaming('hello'));
+}, 'Writer.writeStreaming() fails after destroyed');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ const result = await writer.measureInputUsage(kTestPrompt);
+ assert_greater_than(result, 0);
+}, 'Writer.measureInputUsage() returns non-empty result');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ const result = await writer.write(kTestPrompt, {context: kTestContext});
+ assert_equals(typeof result, 'string');
+}, 'Simple Writer.write() call');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ const streamingResponse =
+ writer.writeStreaming(kTestPrompt, {context: kTestContext});
+ assert_equals(
+ Object.prototype.toString.call(streamingResponse),
+ '[object ReadableStream]');
+ let result = '';
+ for await (const chunk of streamingResponse) {
+ result += chunk;
+ }
+ assert_greater_than(result.length, 0);
+}, 'Simple Writer.writeStreaming() call');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ await Promise.all([writer.write(kTestPrompt), writer.write(kTestPrompt)]);
+}, 'Multiple Writer.write() calls are resolved successfully.');
+
+promise_test(async () => {
+ const writer = await createWriter();
+ await Promise.all(
+ [writer.writeStreaming(kTestPrompt), writer.writeStreaming(kTestPrompt)]);
+}, 'Multiple Writer.writeStreaming() calls are resolved successfully.');
diff --git a/tests/wpt/tests/ambient-light/AmbientLightSensor-iframe-access.https.html b/tests/wpt/tests/ambient-light/AmbientLightSensor-iframe-access.https.html
index 765c1bee1f8..c45804a51f7 100644
--- a/tests/wpt/tests/ambient-light/AmbientLightSensor-iframe-access.https.html
+++ b/tests/wpt/tests/ambient-light/AmbientLightSensor-iframe-access.https.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://w3c.github.io/ambient-light/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/ambient-light/AmbientLightSensor.https.html b/tests/wpt/tests/ambient-light/AmbientLightSensor.https.html
index f2ed655082e..65049ed826f 100644
--- a/tests/wpt/tests/ambient-light/AmbientLightSensor.https.html
+++ b/tests/wpt/tests/ambient-light/AmbientLightSensor.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/ambient-light/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
index f7aed80b17e..b71d6665bcb 100644
--- a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
+++ b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-basics.https.html
@@ -24,56 +24,6 @@ test(() => {
assert_equals(navigator.clipboard, navigator.clipboard);
}, 'navigator.clipboard exists');
-promise_test(async t => {
- await getPermissions();
- const text_plain = "This text was copied using `Clipboard.prototype.write`.";
- const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
- await navigator.clipboard.write([
- new ClipboardItem({
- "text/plain": text_plain,
- "text/html" : html_text
- }),
- ]);
- }, 'navigator.clipboard.write(DOMString) succeeds');
-
-promise_test(async () => {
- await getPermissions();
- const promise_text_string = Promise.resolve('hello');
- const promise_html_string = Promise.resolve("<p style='color: red; font-style: oblique;'>hello</p>");
- const item = new ClipboardItem({
- 'text/plain': promise_text_string,
- 'text/html': promise_html_string
- });
- await navigator.clipboard.write([item]);
-}, 'navigator.clipboard.write(Promise<DOMString>) succeeds');
-
-promise_test(async t => {
- await getPermissions();
- const text_plain = 'hello';
- const html_text = "<p style='color: red; font-style: oblique;'>hello</p>";
- const image = await fetch("/clipboard-apis/resources/greenbox.png");
- const item = new ClipboardItem({
- 'text/plain': text_plain,
- 'text/html': new Blob([html_text], {type: 'text/html'}),
- 'image/png': image.blob(), // Promise<Blob>
- 'web text/csv': 'hello,world'
- });
- await navigator.clipboard.write([item]);
-}, 'navigator.clipboard.write(web_custom_format) succeeds');
-
-promise_test(async () => {
- await getPermissions();
- const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
- const item = new ClipboardItem({
- 'text/plain': 'hello',
- 'text/html': new Blob([html_text], {type: 'text/html'})
- });
- const text = await item.getType('text/plain');
- const blob = await item.getType('text/html');
- assert_true(text instanceof Blob, "item.getType('text/plain') didn't return a Blob");
- assert_true(blob instanceof Blob, "item.getType('text/html') didn't return a Blob");
-}, 'validate GetType(type) on a contructed ClipboardItem returns Blob');
-
promise_test(async () => {
await getPermissions();
const blob = new Blob(['hello'], {type: 'text/plain'});
diff --git a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html
new file mode 100644
index 00000000000..37e2e6a7bde
--- /dev/null
+++ b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>
+ 'clipboardchange' event should be fired upon setting clipboard using JS
+</title>
+<link rel="help" href="https://www.w3.org/TR/clipboard-apis/#clipboard-event-clipboardchange" />
+
+<body>
+ Body needed for test_driver.click()
+ <p><button id="button">Put payload in the clipboard</button></p>
+ <div id="output"></div>
+ <iframe id="iframe" srcdoc="<p>Some text</p>"></iframe>
+ <link rel="help" href="https://issues.chromium.org/issues/41442253" />
+
+ <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/user-activation.js"></script>
+
+ <script>
+ function waitForRender() {
+ return new Promise(resolve => {
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+ }
+
+ button.onclick = () => document.execCommand("copy");
+ document.oncopy = (ev) => {
+ ev.preventDefault();
+ ev.clipboardData.setData("text/html", `<div>Test html</div>`);
+ };
+
+ function triggerCopyToClipboard() {
+ return test_driver.click(button);
+ }
+
+ promise_test(async (test) => {
+ let clipboardChangeEventCount = 0;
+ let eventType = "";
+ navigator.clipboard.addEventListener("clipboardchange", (ev) => {
+ clipboardChangeEventCount++;
+ eventType = ev.type;
+ });
+ await triggerCopyToClipboard();
+ assert_equals(clipboardChangeEventCount, 1, "clipboardchange event should be called exactly once");
+ assert_equals(eventType, "clipboardchange", "Event type should be 'clipboardchange'");
+ }, "clipboardchange event is invoked");
+
+ promise_test(async (test) => {
+ await tryGrantWritePermission();
+ let clipboardChangeEventCount = 0;
+ navigator.clipboard.addEventListener("clipboardchange", (ev) => {
+ clipboardChangeEventCount++;
+ });
+ await navigator.clipboard.writeText("Test text");
+ await waitForRender();
+ assert_equals(clipboardChangeEventCount, 1, "clipboardchange event should be called exactly once");
+ }, "clipboardchange event is invoked with async clipboard API");
+
+ promise_test(async (test) => {
+ let onClipboardChangeAttributeCount = 0;
+ navigator.clipboard.onclipboardchange = () => {
+ onClipboardChangeAttributeCount++;
+ };
+ await triggerCopyToClipboard();
+ assert_equals(onClipboardChangeAttributeCount, 1, "onclipboardchange attribute should be called exactly once");
+ }, "clipboardchange event is invoked using onclipboardchange attribute");
+
+ promise_test(async (test) => {
+ let listenerCallCount = 0;
+ function clipboardChangeListener() {
+ listenerCallCount++;
+ }
+
+ // 1. Add listener and verify it's called
+ navigator.clipboard.addEventListener("clipboardchange", clipboardChangeListener);
+ await triggerCopyToClipboard();
+ assert_equals(listenerCallCount, 1, "Event listener should be called exactly once after adding");
+
+ // 2. Remove listener and verify it's not called
+ navigator.clipboard.removeEventListener("clipboardchange", clipboardChangeListener);
+ await triggerCopyToClipboard();
+ assert_equals(listenerCallCount, 1, "Event listener should not be called after removing");
+
+ // 3. Re-add listener and verify it's called again
+ navigator.clipboard.addEventListener("clipboardchange", clipboardChangeListener);
+ await triggerCopyToClipboard();
+ assert_equals(listenerCallCount, 2, "Event listener should be called exactly once after re-adding");
+ }, "clipboardchange event listener behavior when adding, removing, and re-adding");
+
+ promise_test(async (test) => {
+ // Focus the document and acquire permission to write to the clipboard
+ await test_driver.click(document.body);
+ await tryGrantWritePermission();
+
+ const iframe = document.getElementById('iframe');
+
+ let frameEventCount = 0;
+ let focusEventFired = false;
+ iframe.contentWindow.addEventListener("focus", () => {
+ focusEventFired = true;
+ });
+
+ // Add listener to iframe
+ iframe.contentWindow.navigator.clipboard.addEventListener("clipboardchange", () => {
+ assert_true(focusEventFired, "focus event should fire before clipboardchange event");
+ frameEventCount++;
+ });
+
+ // Ensure iFrame doesn't have the focus
+ assert_false(iframe.contentWindow.document.hasFocus(), "iFrame should not have focus");
+ assert_false(focusEventFired, "focus event should not have fired yet");
+
+ // Trigger multiple clipboard changes
+ await navigator.clipboard.writeText("Test text");
+ await navigator.clipboard.writeText("Test text 2");
+ await waitForRender();
+
+ assert_equals(frameEventCount, 0, "iframe should not recieve any clipboardchange event yet");
+
+ iframe.focus();
+ assert_true(iframe.contentWindow.document.hasFocus(), "iFrame should have focus");
+ assert_equals(frameEventCount, 1, "iframe should receive event only 1 event after focus");
+ }, "clipboardchange event should only fire in the focused context");
+ </script>
+</body> \ No newline at end of file
diff --git a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html
new file mode 100644
index 00000000000..a16f358f46d
--- /dev/null
+++ b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Async Clipboard input type validation tests - DOMString input in write API</title>
+<link rel="help" href="https://w3c.github.io/clipboard-apis/#typedefdef-clipboarditemdata">
+
+<body>Body needed for test_driver.click()</body>
+<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/user-activation.js"></script>
+<script>
+
+ // Permissions are required in order to invoke navigator.clipboard functions in
+ // an automated test.
+ async function getPermissions() {
+ await tryGrantReadPermission();
+ await tryGrantWritePermission();
+ await waitForUserActivation();
+ }
+
+ test(() => {
+ assert_not_equals(navigator.clipboard, undefined);
+ assert_true(navigator.clipboard instanceof Clipboard);
+ assert_equals(navigator.clipboard, navigator.clipboard);
+ }, 'navigator.clipboard exists');
+
+ promise_test(async t => {
+ await getPermissions();
+ const text_plain = "This text was copied using `Clipboard.prototype.write`.";
+ const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
+ await navigator.clipboard.write([
+ new ClipboardItem({
+ "text/plain": text_plain,
+ "text/html": html_text
+ }),
+ ]);
+ }, 'navigator.clipboard.write(DOMString) succeeds');
+
+ promise_test(async () => {
+ await getPermissions();
+ const promise_text_string = Promise.resolve('hello');
+ const promise_html_string = Promise.resolve("<p style='color: red; font-style: oblique;'>hello</p>");
+ const item = new ClipboardItem({
+ 'text/plain': promise_text_string,
+ 'text/html': promise_html_string
+ });
+ await navigator.clipboard.write([item]);
+ }, 'navigator.clipboard.write(Promise<DOMString>) succeeds');
+
+ promise_test(async () => {
+ await getPermissions();
+ const promise_html_string = `
+ <table>
+ <tbody>
+ <tr>
+ <td>0,00€</td>
+ </tr>
+ <tr>
+ <td>0,00€</td>
+ </tr>
+ </tbody>
+ </table>
+ `;
+ const item = new ClipboardItem({
+ 'text/html': promise_html_string
+ });
+ await navigator.clipboard.write([item]);
+ }, 'navigator.clipboard.write(Promise<DOMString>) with utf-16 string succeeds');
+
+ promise_test(async t => {
+ await getPermissions();
+ const text_plain = 'hello';
+ const html_text = "<p style='color: red; font-style: oblique;'>hello</p>";
+ const image = await fetch("/clipboard-apis/resources/greenbox.png");
+ const item = new ClipboardItem({
+ 'text/plain': text_plain,
+ 'text/html': new Blob([html_text], {type: 'text/html'}),
+ 'image/png': image.blob(), // Promise<Blob>
+ 'web text/csv': 'hello,world'
+ });
+ await navigator.clipboard.write([item]);
+ }, 'navigator.clipboard.write(web_custom_format) succeeds');
+
+ promise_test(async () => {
+ await getPermissions();
+ const html_text = "<p style='color: red; font-style: oblique;'>Test</p>";
+ const item = new ClipboardItem({
+ 'text/plain': 'hello',
+ 'text/html': new Blob([html_text], {type: 'text/html'})
+ });
+ const text = await item.getType('text/plain');
+ const blob = await item.getType('text/html');
+ assert_true(text instanceof Blob, "item.getType('text/plain') should return a Blob");
+ assert_true(blob instanceof Blob, "item.getType('text/html') should return a Blob");
+ }, 'validate GetType(type) on a constructed ClipboardItem returns Blob');
+
+ promise_test(async () => {
+ await getPermissions();
+ // Test string with various non-Latin characters: Chinese, Arabic, Cyrillic, emoji
+ const nonLatinText = "你好 مرحبا Привет 👋🌍";
+ const item = new ClipboardItem({
+ 'text/plain': nonLatinText
+ });
+ await navigator.clipboard.write([item]);
+
+ // Read back the text and verify it matches
+ const readText = await navigator.clipboard.readText();
+ assert_equals(readText, nonLatinText,
+ "Text read from clipboard should match the non-Latin text that was written");
+ }, 'write non-Latin characters with DOMString and verify readText returns the same string');
+</script> \ No newline at end of file
diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html
new file mode 100644
index 00000000000..250fbf7e5f7
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
+<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/testdriver-actions.js"></script>
+<script src="../resources/helpers.js"></script>
+
+<body>
+ <iframe id="iframe1" src="resources/dialog-prevents-close.html"></iframe>
+ <iframe id="iframe2" src="resources/dialog-prevents-close.html"></iframe>
+
+ <script>
+ function awaitEvent(el, type, signal) {
+ return new Promise((resolve) =>
+ el.addEventListener(type, resolve, { once: true, signal }),
+ );
+ }
+
+ async function iframeDialogIsOpen(iframe, signal) {
+ const reply = awaitEvent(window, "message", signal);
+ iframe.contentWindow.postMessage("dialog_open", "*");
+ const {data} = (await reply);
+ if (data.error) throw new Error(data.error);
+ return data.open;
+ }
+
+ promise_test(async (t) => {
+ await awaitEvent(iframe1, "load", t.get_signal());
+ await awaitEvent(iframe2, "load", t.get_signal());
+
+ assert_true(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is open");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is open");
+
+ await test_driver.send_keys(iframe1, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is now closed");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ await test_driver.send_keys(iframe2, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is still closed");
+ assert_false(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is now closed");
+ });
+ </script>
+</body>
diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html
new file mode 100644
index 00000000000..b5cfab5c5d9
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
+<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/testdriver-actions.js"></script>
+<script src="../resources/helpers.js"></script>
+
+<body>
+ <iframe id="iframe1" src="resources/dialog-prevents-close.html"></iframe>
+ <iframe id="iframe2" src="resources/dialog-prevents-close.html"></iframe>
+
+ <script>
+ function awaitEvent(el, type, signal) {
+ return new Promise((resolve) =>
+ el.addEventListener(type, resolve, { once: true, signal }),
+ );
+ }
+
+ async function iframeDialogIsOpen(iframe, signal) {
+ const reply = awaitEvent(window, "message", signal);
+ iframe.contentWindow.postMessage("dialog_open", "*");
+ const {data} = (await reply);
+ if (data.error) throw new Error(data.error);
+ return data.open;
+ }
+
+ promise_test(async (t) => {
+ await awaitEvent(iframe1, "load", t.get_signal());
+ await awaitEvent(iframe2, "load", t.get_signal());
+
+ test_driver.bless();
+
+ assert_true(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is open");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is open");
+
+ await test_driver.send_keys(iframe1, "\uE00C");
+
+ assert_true(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is still open");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ await test_driver.send_keys(iframe1, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is now closed");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ await test_driver.send_keys(iframe2, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is still closed");
+ assert_false(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is now closed");
+ });
+ </script>
+</body>
diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html
new file mode 100644
index 00000000000..4f55e9b24aa
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
+<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/testdriver-actions.js"></script>
+<script src="../resources/helpers.js"></script>
+
+<body>
+ <iframe id="iframe1" src="resources/dialog-prevents-close.html"></iframe>
+ <iframe id="iframe2" src="resources/dialog-prevents-close.html"></iframe>
+
+ <script>
+ function awaitEvent(el, type, signal) {
+ return new Promise((resolve) =>
+ el.addEventListener(type, resolve, { once: true, signal }),
+ );
+ }
+
+ async function iframeDialogIsOpen(iframe, signal) {
+ const reply = awaitEvent(window, "message", signal);
+ iframe.contentWindow.postMessage("dialog_open", "*");
+ const {data} = (await reply);
+ if (data.error) throw new Error(data.error);
+ return data.open;
+ }
+
+ promise_test(async (t) => {
+ await awaitEvent(iframe1, "load", t.get_signal());
+ await awaitEvent(iframe2, "load", t.get_signal());
+
+ test_driver.bless();
+
+ assert_true(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is open");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is open");
+
+ await test_driver.send_keys(iframe1, "\uE00C");
+
+ assert_true(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is still open");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ await test_driver.send_keys(iframe1, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is now closed");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ test_driver.bless();
+
+ await test_driver.send_keys(iframe2, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is now closed");
+ assert_true(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is still open");
+
+ await test_driver.send_keys(iframe2, "\uE00C");
+
+ assert_false(await iframeDialogIsOpen(iframe1, t.get_signal()), "Dialog 1 is still closed");
+ assert_false(await iframeDialogIsOpen(iframe2, t.get_signal()), "Dialog 2 is now closed");
+ });
+ </script>
+</body>
diff --git a/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html b/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html
new file mode 100644
index 00000000000..580e5220dae
--- /dev/null
+++ b/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+ <dialog id="d"></dialog>
+ <script>
+ d.showModal();
+ d.addEventListener("cancel", (e) => e.preventDefault());
+ window.addEventListener("message", async (e) => {
+ if (event.data == "dialog_open") {
+ window.parent.postMessage({ open: d.open }, "*");
+ } else {
+ window.parent.postMessage({ error: `invalid command: ${e.data}` }, "*");
+ }
+ });
+ </script>
+</body>
diff --git a/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js b/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js
index a120f97a403..a13d1766c53 100644
--- a/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js
+++ b/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js
@@ -31,12 +31,14 @@ pressure_test(async (t) => {
const observer = new PressureObserver(resolve);
t.add_cleanup(() => observer.disconnect());
observer.observe('cpu').catch(reject);
- update_virtual_pressure_source('cpu', 'critical').catch(reject);
+ update_virtual_pressure_source('cpu', 'critical', 0.5).catch(reject);
});
assert_equals(1, changes.length);
assert_equals(changes[0].state, 'critical');
assert_equals(changes[0].source, 'cpu');
assert_equals(typeof changes[0].time, 'number');
+ assert_equals(typeof changes[0].ownContributionEstimate, 'number');
+ assert_equals(changes[0].ownContributionEstimate, 0.5);
}, 'Basic functionality test');
pressure_test(async (t) => {
@@ -45,6 +47,25 @@ pressure_test(async (t) => {
await remove_virtual_pressure_source('cpu');
});
+ const changes = await new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ update_virtual_pressure_source('cpu', 'critical').catch(reject);
+ });
+ assert_equals(1, changes.length);
+ assert_equals(changes[0].state, 'critical');
+ assert_equals(changes[0].source, 'cpu');
+ assert_equals(typeof changes[0].time, 'number');
+ assert_equals(changes[0].ownContributionEstimate, null);
+}, 'Basic functionality test with no ownContributionEstimate');
+
+pressure_test(async (t) => {
+ await create_virtual_pressure_source('cpu');
+ t.add_cleanup(async () => {
+ await remove_virtual_pressure_source('cpu');
+ });
+
const observer = new PressureObserver(() => {
assert_unreached('The observer callback should not be called');
});
diff --git a/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js b/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js
index 231d4afc345..abf53854b40 100644
--- a/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js
+++ b/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js
@@ -19,15 +19,15 @@ pressure_test(async (t) => {
const syncObserver = new SyncPressureObserver(t);
await syncObserver.observer().observe('cpu');
- await update_virtual_pressure_source('cpu', 'critical');
+ await update_virtual_pressure_source('cpu', 'critical', 0.2);
await syncObserver.waitForUpdate();
assert_equals(syncObserver.changes()[0][0].state, 'critical');
- await update_virtual_pressure_source('cpu', 'critical');
+ await update_virtual_pressure_source('cpu', 'critical', 0.2);
await new Promise(resolve => {t.step_timeout(resolve, 3000)});
assert_equals(syncObserver.changes().length, 1);
- await update_virtual_pressure_source('cpu', 'nominal');
+ await update_virtual_pressure_source('cpu', 'nominal'), 0.2;
await syncObserver.waitForUpdate();
assert_equals(syncObserver.changes()[1][0].state, 'nominal');
diff --git a/tests/wpt/tests/compute-pressure/resources/worker-support.js b/tests/wpt/tests/compute-pressure/resources/worker-support.js
index 39caeb6192f..72e1fbfb204 100644
--- a/tests/wpt/tests/compute-pressure/resources/worker-support.js
+++ b/tests/wpt/tests/compute-pressure/resources/worker-support.js
@@ -43,8 +43,8 @@ function remove_virtual_pressure_source(source) {
return send_message({command: 'remove', params: [source]});
}
-function update_virtual_pressure_source(source, state) {
- return send_message({command: 'update', params: [source, state]});
+function update_virtual_pressure_source(source, state, estimate) {
+ return send_message({command: 'update', params: [source, state, estimate]});
}
const uuid = new URLSearchParams(location.search).get('uuid');
diff --git a/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js b/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js
index 542bd6c5387..b42a745d3e4 100644
--- a/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js
+++ b/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js
@@ -161,7 +161,7 @@ promise_test(async testCase => {
assert_equals(cookie.name, 'cookie-name');
assert_equals(cookie.value, 'cookie-value');
assert_equals(cookie.domain, null);
- assert_equals(cookie.path, currentDirectory + '/');
+ assert_equals(cookie.path, currentDirectory);
assert_equals(cookie.expires, null);
assert_equals(cookie.secure, true);
assert_equals(cookie.sameSite, 'strict');
@@ -169,7 +169,7 @@ promise_test(async testCase => {
for (const key of kCookieListItemKeys) {
assert_in_array(key, itemKeys);
}
-}, 'CookieListItem - cookieStore.set adds / to path if it does not end with /');
+}, 'CookieListItem - cookieStore.set does not add / to path if it does not end with /');
['strict', 'lax', 'none'].forEach(sameSiteValue => {
promise_test(async testCase => {
@@ -208,19 +208,22 @@ promise_test(async testCase => {
assert_equals(cookie.secure, true);
}, 'CookieListItem - secure defaults to true');
-promise_test(async testCase => {
- await cookieStore.delete('cookie-name');
- testCase.add_cleanup(async () => {
+
+if (self.GLOBAL.isWindow()) {
+ promise_test(async testCase => {
await cookieStore.delete('cookie-name');
- });
+ testCase.add_cleanup(async () => {
+ await cookieStore.delete('cookie-name');
+ });
- let encodedCookie = encodeURIComponent(JSON.stringify("cookie-name=1; max-age=99999999999999999999999999999; path=/"));
- await fetch(`/cookies/resources/cookie.py?set=${encodedCookie}`);
+ let encodedCookie = encodeURIComponent(JSON.stringify("cookie-name=1; max-age=99999999999999999999999999999; path=/"));
+ await fetch(`/cookies/resources/cookie.py?set=${encodedCookie}`);
- assert_equals(document.cookie, "cookie-name=1", 'The cookie was set as expected.');
+ assert_equals(document.cookie, "cookie-name=1", 'The cookie was set as expected.');
- const cookie = await cookieStore.get('cookie-name');
- assert_equals(cookie.name, 'cookie-name');
- assert_equals(cookie.value, '1');
- assert_approx_equals(cookie.expires, kFourHundredDaysFromNow, kOneDay);
-}, "Test max-age attribute over the 400 days");
+ const cookie = await cookieStore.get('cookie-name');
+ assert_equals(cookie.name, 'cookie-name');
+ assert_equals(cookie.value, '1');
+ assert_approx_equals(cookie.expires, kFourHundredDaysFromNow, kOneDay);
+ }, "Test max-age attribute over the 400 days");
+}
diff --git a/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js b/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js
index 37a551b3a9f..2503de0abb0 100644
--- a/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js
+++ b/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js
@@ -1,11 +1,14 @@
// META: title=Cookie Store API: cookieStore.delete() arguments
+// META: script=resources/cookie-test-helpers.js
// META: global=window,serviceworker
'use strict';
promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-value');
-
+ testCase.add_cleanup(async () => {
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
+ });
await cookieStore.delete('cookie-name');
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
@@ -14,7 +17,7 @@ promise_test(async testCase => {
promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
await cookieStore.delete({ name: 'cookie-name' });
@@ -42,7 +45,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', domain: currentDomain });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', domain: currentDomain });
+ await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Max-Age=0`);
});
await cookieStore.delete({ name: 'cookie-name', domain: currentDomain });
@@ -79,7 +82,8 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', path: currentDirectory });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
});
await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
@@ -96,7 +100,8 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', path: currentDirectory });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
});
await cookieStore.delete({ name: 'cookie-name', path: subDirectory });
@@ -109,18 +114,36 @@ promise_test(async testCase => {
const currentUrl = new URL(self.location.href);
const currentPath = currentUrl.pathname;
const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/'));
- await cookieStore.set(
- { name: 'cookie-name',
- value: 'cookie-value',
- path: currentDirectory + '/' });
+ await setCookieStringHttp(`cookie-name=cookie-value; Path=${currentDirectory};`);
+
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
});
await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
-}, 'cookieStore.delete with missing / at the end of path');
+}, 'cookieStore.delete does not append / at the end of path');
+
+promise_test(async testCase => {
+ if (typeof self.document === 'undefined') {
+ // The test is being run from a service worker context where document is undefined
+ testCase.done();
+ return;
+ }
+ const currentUrl = new URL(self.location.href);
+ const currentPath = currentUrl.pathname;
+ const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/'));
+ await setCookieStringDocument('cookie-name=cookie-value; path=' + currentDirectory);
+ testCase.add_cleanup(async () => {
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
+ });
+ await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ const cookie = await cookieStore.get('cookie-name');
+ assert_equals(cookie, null);
+}, 'cookieStore.delete can delete a cookie set by document.cookie if document is defined');
promise_test(async testCase => {
const currentUrl = new URL(self.location.href);
@@ -136,7 +159,7 @@ promise_test(async testCase => {
promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie_attributes = await cookieStore.get('cookie-name');
@@ -151,7 +174,7 @@ promise_test(async testCase => {
promise_test(async testCase => {
await cookieStore.set('', 'cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('');
+ await setCookieStringHttp(`=deleted; Max-Age=0`);
});
await cookieStore.delete('');
@@ -162,10 +185,25 @@ promise_test(async testCase => {
promise_test(async testCase => {
await cookieStore.set('', 'cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('');
+ await setCookieStringHttp(`=deleted; Max-Age=0`);
});
await cookieStore.delete({ name: '' });
const cookie = await cookieStore.get('');
assert_equals(cookie, null);
}, 'cookieStore.delete with empty name in options');
+
+promise_test(async testCase => {
+ // Cookies having a __Host- prefix are not allowed to specify a domain
+ await cookieStore.delete('cookie-name');
+
+ const currentUrl = new URL(self.location.href);
+ const currentDomain = currentUrl.hostname;
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.delete(
+ { name: '__Host-cookie-name',
+ value: 'cookie-value',
+ domain: currentDomain }));
+ const cookie = await cookieStore.get('cookie-name');
+ assert_equals(cookie, null);
+}, 'cookieStore.delete with a __Host- prefix should not have a domain');
diff --git a/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html b/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html
index c67ef98bcc9..004e37630ac 100644
--- a/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html
+++ b/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html
@@ -63,4 +63,87 @@ promise_test(async t => {
assert_equals(frameCookie.name, 'cookie-name');
assert_equals(frameCookie.value, 'cookie-value');
}, 'cookieStore.get() in cross-origin frame sees cookieStore.set()');
+
+promise_test(async t => {
+ const iframe = await createIframe(kCorsUrl, t);
+ assert_true(iframe != null);
+
+ document.cookie = "__Host-test=a; Path=/; Secure";
+ iframe.contentWindow.postMessage({
+ opname: 'set-host-cookie',
+ name: '__Host-test',
+ value: 'b',
+ }, kCorsBase);
+
+ const message = await waitForMessage();
+ t.add_cleanup(async () => {
+ await cookieStore.delete({ name: '__Host-test'});
+ });
+
+ assert_equals(document.cookie, '__Host-test=a');
+
+ // Cleanup iframe cookie
+ iframe.contentWindow.postMessage({
+ opname: 'delete-host-cookie',
+ name: '__Host-test',
+ }, kCorsBase);
+ await waitForMessage();
+}, 'cookieStore.set() in cross-origin does not overwrite the __Host- cookie');
+
+promise_test(async t => {
+ const iframe = await createIframe(kCorsUrl, t);
+ assert_true(iframe != null);
+
+ document.cookie = "__Host-test=a; Path=/; Secure";
+ await cookieStore.set({name: "__Host-test", value: "a", path: "/"});
+ t.add_cleanup(async () => {
+ await cookieStore.delete({ name: '__Host-test'});
+ });
+
+ iframe.contentWindow.postMessage({
+ opname: 'set-host-cookie',
+ name: '__Host-test',
+ value: 'b',
+ }, kCorsBase);
+
+ let message = await waitForMessage();
+
+ let cookies = await cookieStore.getAll();
+ assert_equals(cookies.length, 1);
+ assert_equals(cookies[0].name, '__Host-test');
+ assert_equals(cookies[0].value, 'a');
+
+ iframe.contentWindow.postMessage({
+ opname: 'get-cookie',
+ name: '__Host-test',
+ }, kCorsBase);
+ message = await waitForMessage();
+ let { frameCookie } = message;
+ assert_not_equals(frameCookie, null);
+ assert_equals(frameCookie.name, '__Host-test');
+ assert_equals(frameCookie.value, 'b');
+
+ // Make sure deleting the cookie doesn't affect the other domain's cookie
+ await cookieStore.delete({ name: '__Host-test'});
+ cookies = await cookieStore.getAll();
+ assert_equals(cookies.length, 0);
+
+ iframe.contentWindow.postMessage({
+ opname: 'get-cookie',
+ name: '__Host-test',
+ }, kCorsBase);
+ message = await waitForMessage();
+ ({ frameCookie } = message);
+ assert_not_equals(frameCookie, null);
+ assert_equals(frameCookie.name, '__Host-test');
+ assert_equals(frameCookie.value, 'b');
+
+ // Cleanup iframe cookie
+ iframe.contentWindow.postMessage({
+ opname: 'delete-host-cookie',
+ name: '__Host-test',
+ }, kCorsBase);
+ await waitForMessage();
+}, "__Host- cookies set via cookieStore.set() in same-site domains don't overwrite each other");
+
</script>
diff --git a/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js b/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js
index 064fcc5de52..3e9ac5f3e98 100644
--- a/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js
+++ b/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js
@@ -1,4 +1,5 @@
// META: title=Cookie Store API: cookieStore.set() arguments
+// META: script=resources/cookie-test-helpers.js
// META: global=window,serviceworker
'use strict';
@@ -8,7 +9,7 @@ promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
@@ -21,7 +22,7 @@ promise_test(async testCase => {
await cookieStore.set({ name: 'cookie-name', value: 'cookie-value' });
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -42,7 +43,7 @@ promise_test(async testCase => {
await cookieStore.delete('cookie-name');
cookieStore.set('cookie-name', 'suspicious-value=resembles-name-and-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -81,7 +82,7 @@ promise_test(async testCase => {
value: 'cookie-value',
expires: new Date(tenYearsFromNow) });
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -98,7 +99,7 @@ promise_test(async testCase => {
value: 'cookie-value',
expires: new Date(tenYearsAgo) });
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
@@ -112,7 +113,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', expires: tenYearsFromNow });
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -127,7 +128,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', expires: tenYearsAgo });
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
@@ -156,7 +157,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', domain: currentDomain });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', domain: currentDomain });
+ await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Path=/; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -195,12 +196,12 @@ promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-value1');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Path=/; Max-Age=0`);
});
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value2', domain: currentDomain });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', domain: currentDomain });
+ await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Path=/; Max-Age=0`);
});
const cookies = await cookieStore.getAll('cookie-name');
@@ -224,7 +225,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', path: currentDirectory });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie.name, 'cookie-name');
@@ -243,7 +244,7 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', path: subDirectory });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: subDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${subDirectory}; Max-Age=0`);
});
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
@@ -254,12 +255,13 @@ promise_test(async testCase => {
await cookieStore.set('cookie-name', 'cookie-old-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
+
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-new-value', path: '/' });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: '/' });
+ await setCookieStringHttp(`cookie-name=deleted; Path=/; Max-Age=0`);
});
const cookies = await cookieStore.getAll('cookie-name');
@@ -277,13 +279,34 @@ promise_test(async testCase => {
await cookieStore.set(
{ name: 'cookie-name', value: 'cookie-value', path: currentDirectory });
testCase.add_cleanup(async () => {
- await cookieStore.delete({ name: 'cookie-name', path: currentDirectory });
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
});
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
const cookie = await cookieStore.get('cookie-name');
- assert_equals(cookie.name, 'cookie-name');
- assert_equals(cookie.value, 'cookie-value');
- assert_equals(cookie.path, currentDirectory + '/');
-}, 'cookieStore.set adds / to path that does not end with /');
+ assert_equals(cookie, null);
+}, 'cookieStore.set does not add / to path that does not end with /');
+
+promise_test(async testCase => {
+ if (typeof self.document === 'undefined') {
+ // The test is being run from a service worker context where document is undefined
+ testCase.done();
+ return;
+ }
+ const currentUrl = new URL(self.location.href);
+ const currentPath = currentUrl.pathname;
+ const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/'));
+ await setCookieStringDocument('cookie-name=cookie-value; path=' + currentDirectory);
+ await cookieStore.set(
+ { name: 'cookie-name', value: 'new-cookie-value', path: currentDirectory });
+ testCase.add_cleanup(async () => {
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`);
+ await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`);
+ });
+ const cookies = await cookieStore.getAll('cookie-name');
+ assert_equals(cookies.length, 1);
+ assert_equals(cookies[0].name, 'cookie-name');
+ assert_equals(cookies[0].value, 'cookie-new-value');
+}, 'cookieStore.set can modify a cookie set by document.cookie if document is defined');
promise_test(async testCase => {
const currentUrl = new URL(self.location.href);
@@ -299,7 +322,7 @@ promise_test(async testCase => {
promise_test(async testCase => {
await cookieStore.set('cookie-name', 'old-cookie-value');
testCase.add_cleanup(async () => {
- await cookieStore.delete('cookie-name');
+ await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`);
});
const cookie_attributes = await cookieStore.get('cookie-name');
@@ -336,3 +359,57 @@ promise_test(async testCase => {
const cookie = await cookieStore.get('cookie-name');
assert_equals(cookie, null);
}, 'cookieStore.set checks if the domain is too long');
+
+promise_test(async testCase => {
+ // Cookies having a __Host- prefix are not allowed to specify a domain
+ await cookieStore.delete('cookie-name');
+
+ const currentUrl = new URL(self.location.href);
+ const currentDomain = currentUrl.hostname;
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: '__Host-cookie-name',
+ value: 'cookie-value',
+ domain: currentDomain }));
+ const cookie = await cookieStore.get('cookie-name');
+ assert_equals(cookie, null);
+}, 'cookieStore.set with a __Host- prefix should not have a domain');
+
+promise_test(async testCase => {
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: '',
+ value: ' ' }));
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: ' ',
+ value: '' }));
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: ' ',
+ value: ' ' }));
+}, 'cookieStore.set with whitespace only name and value');
+
+promise_test(async testCase => {
+ testCase.add_cleanup(async () => {
+ await cookieStore.delete('a b');
+ });
+ await cookieStore.set('a b', 'x y');
+ const cookie = await cookieStore.get('a b');
+ assert_equals(cookie.value, "x y");
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: 'a ',
+ value: 'x' }));
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: ' a',
+ value: 'x' }));
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: 'a',
+ value: 'x ' }));
+
+ await promise_rejects_js(testCase, TypeError, cookieStore.set(
+ { name: 'a',
+ value: 'x ' }));
+}, 'cookieStore.set with whitespace at begining or end');
diff --git a/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html b/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html
index 3bd1843d574..d5cae23d160 100644
--- a/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html
+++ b/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html
@@ -40,6 +40,17 @@
} else if (opname === 'push-state') {
history.pushState("foo", null, "some/path");
event.source.postMessage('pushState called');
+ } else if (opname === "set-host-cookie") {
+ const { name, value } = event.data
+ await cookieStore.set({
+ name,
+ value,
+ });
+ event.source.postMessage('Cookie has been set', event.origin);
+ } else if (opname === "delete-host-cookie") {
+ const { name} = event.data
+ await cookieStore.delete({ name: name});
+ event.source.postMessage('Cookie has been deleted', event.origin);
}
});
</script>
diff --git a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html
index 4eaa9d2f3a6..347005204e3 100644
--- a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html
+++ b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html
@@ -11,14 +11,14 @@
}
.abspos {
position: absolute;
- inset: 10px auto 10px 50px;
+ inset: 50px auto 50px 50px;
margin: auto 0 auto 0;
align-self: stretch;
background: green;
}
.abspos::before {
content: '';
- min-width: 100px;
+ min-width: 50px;
height: 100%;
aspect-ratio: 1;
display: block;
diff --git a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html
index 9d1b6454c84..9d6eb230653 100644
--- a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html
+++ b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html
@@ -11,15 +11,15 @@
}
.abspos {
position: absolute;
- inset: 10px 50px 10px 50px;
+ inset: 50px;
margin: auto 0 auto 0;
align-self: stretch;
background: green;
}
.abspos::before {
content: '';
- width: 100px;
- height: 100px;
+ width: 50px;
+ height: 50px;
display: block;
}
</style>
diff --git a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html
index c50b32f089b..bc6120584c2 100644
--- a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html
+++ b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html
@@ -11,7 +11,7 @@
}
.abspos {
position: absolute;
- inset: 50px 10px auto 10px;
+ inset: 50px 50px auto 50px;
margin: 0 auto 0 auto;
justify-self: stretch;
background: green;
@@ -19,7 +19,7 @@
.abspos::before {
content: '';
width: 100%;
- min-height: 100px;
+ min-height: 50px;
aspect-ratio: 1;
display: block;
}
diff --git a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html
index 7d7b4bfc857..675321fc2b1 100644
--- a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html
+++ b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html
@@ -11,15 +11,15 @@
}
.abspos {
position: absolute;
- inset: 50px 10px 50px 10px;
+ inset: 50px;
margin: 0 auto 0 auto;
justify-self: stretch;
background: green;
}
.abspos::before {
content: '';
- width: 100px;
- height: 100px;
+ width: 50px;
+ height: 50px;
display: block;
}
</style>
diff --git a/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.tentative.html b/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.html
index 641dea1f54b..641dea1f54b 100644
--- a/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.tentative.html
+++ b/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.html
diff --git a/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html b/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html
index 33c98d6c1df..e81c4bba6f4 100644
--- a/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html
+++ b/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html
@@ -1,8 +1,7 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-align-3/#justify-abspos">
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
-<meta name="assert"
- content="auto margins are calculated correctly when justify-self is specified but should have no effect" />
+<meta name="assert" content="auto margins do not disable fit-content sizing when justify-self is specified">
<style>
#reference-overlapped-red {
position: absolute;
@@ -18,9 +17,8 @@
<div id=reference-overlapped-red></div>
-<div style="width: 100px;">
- <div
- style="height:100px; margin: auto; justify-self: right; background: green;">
- <div style="width: 50px;"></div>
+<div style="width: 200px; margin-left: -50px;">
+ <div style="height:100px; margin: auto; justify-self: right; background: green;">
+ <div style="width: 100px;"></div>
</div>
</div>
diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change-ref.html b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
index 66bf9083c3a..bc9872a9093 100644
--- a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
+++ b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
@@ -17,16 +17,43 @@
background: lime;
}
+.target-inner {
+ width: 30px;
+ height: 20px;
+}
+
.target {
- position: fixed;
+ position: absolute;
+}
+
+#target-1 {
background: cyan;
- left: 111px;
+ left: 50px;
+}
+
+#target-2 {
+ top: 20px;
+ left: 0;
+ background: blue;
}
+
+#target-3 {
+ top: 20px;
+ left: 50px;
+ background: magenta;
+}
+
</style>
<div class="container">
<div class="anchor"></div>
- <div class="target">
- <div style="width:30px;height:20px;"></div>
+ <div id="target-1" class="target">
+ <div class="target-inner"></div>
+ </div>
+ <div id="target-2" class="target">
+ <div class="target-inner"></div>
+ </div>
+ <div id="target-3" class="target">
+ <div class="target-inner"></div>
</div>
</div>
diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html
index 0f7d805844f..e5559433206 100644
--- a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html
+++ b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html
@@ -1,8 +1,9 @@
<!DOCTYPE html>
<html class=reftest-wait>
-<title>Tests 'anchor-center' value when target visibility changes</title>
+<title>Tests 'anchor-center' value when target visibility changes (by changing 'display', 'visibility', or popover trigger)</title>
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#valdef-justify-self-anchor-center">
<link rel="author" href="mailto:plampe@igalia.com">
+<link rel="author" href="mailto:kiet.ho@apple.com">
<link rel="match" href="anchor-center-visibility-change-ref.html">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
@@ -27,27 +28,61 @@
.target {
position-anchor: --anchor;
- position: fixed;
- background: cyan;
+ position: absolute;
+}
+
+.target-inner {
+ width: 30px;
+ height: 20px;
+}
+
+#target-1 {
justify-self: anchor-center;
+ background: cyan;
display: none;
}
+
+#target-2 {
+ align-self: anchor-center;
+ background: blue;
+ visibility: hidden;
+}
+
+#target-3 {
+ align-self: anchor-center;
+ justify-self: anchor-center;
+ background: magenta;
+
+ /* Override default popover style */
+ margin: 0;
+ padding: 0;
+ border: none;
+}
</style>
<div class="container">
<div class="anchor"></div>
- <div id="target" class="target">
- <div style="width:30px;height:20px;"></div>
+ <div id="target-1" class="target">
+ <div class="target-inner"></div>
+ </div>
+ <div id="target-2" class="target">
+ <div class="target-inner"></div>
+ </div>
+ <div id="target-3" class="target" popover>
+ <div class="target-inner"></div>
</div>
</div>
<script>
- // #target should be invisible initially.
+ // Targets should be invisible initially.
waitForAtLeastOneFrame().then(() => {
- // Change #target to be visible.
- document.getElementById('target').style.display = 'flow';
+ // Change targets to be visible.
+ document.getElementById('target-1').style.display = 'flow';
+ document.getElementById('target-2').style.visibility = 'visible';
+ document.getElementById('target-3').showPopover();
+
waitForAtLeastOneFrame().then(() => {
- // #target should be visible and anchor-centered now.
+ // Targets should be visible now.
takeScreenshot();
});
});
diff --git a/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html b/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html
new file mode 100644
index 00000000000..61d8ab50284
--- /dev/null
+++ b/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+
+<html class="reftest-wait">
+
+<head>
+ <title>Tests that an element positioned using position-area renders when it's initially hidden, then shown</title>
+
+ <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#position-area">
+ <link rel="author" href="mailto:kiet.ho@apple.com">
+ <link rel="match" href="reference/position-area-visibility-change-ref.html">
+
+ <script src="/common/reftest-wait.js"></script>
+ <script src="/common/rendering-utils.js"></script>
+
+ <style>
+ .containing-block {
+ position: relative;
+ width: 150px;
+ height: 150px;
+ outline: 2px black solid;
+ }
+
+ .cell {
+ width: 50px;
+ height: 50px;
+ }
+
+ #anchor-cell {
+ position: absolute;
+ top: 50px;
+ left: 50px;
+
+ anchor-name: --anchor;
+
+ background: green;
+ }
+
+ .anchor-positioned-cell {
+ position: absolute;
+ position-anchor: --anchor;
+ }
+
+ #target-1 {
+ position-area: top right;
+
+ /* Will be changed to 'block' */
+ display: none;
+ }
+
+ #target-2 {
+ position-area: bottom left;
+
+ /* Will be changed to 'visible' */
+ visibility: hidden;
+ }
+
+ #target-3 {
+ position-area: bottom right;
+
+ /* Override default popover style */
+ margin: 0;
+ padding: 0;
+ border: none;
+ }
+
+ .blue-background {
+ background: blue;
+ }
+
+ .magenta-background {
+ background: magenta;
+ }
+
+ .cyan-background {
+ background: cyan;
+ }
+ </style>
+</head>
+
+<body>
+ <div class="containing-block">
+ <div class="cell" id="anchor-cell"></div>
+
+ <div class="cell anchor-positioned-cell" id="target-1">
+ <div class="cell blue-background"></div>
+ </div>
+
+ <div class="cell anchor-positioned-cell" id="target-2">
+ <div class="cell magenta-background"></div>
+ </div>
+
+ <div class="cell anchor-positioned-cell" id="target-3" popover>
+ <div class="cell cyan-background"></div>
+ </div>
+ </div>
+
+ <script>
+ // All targets should initially be hidden.
+ waitForAtLeastOneFrame().then(() => {
+ // Change targets to be visible.
+ document.getElementById('target-1').style.display = 'block';
+ document.getElementById('target-2').style.visibility = 'visible';
+ document.getElementById('target-3').showPopover();
+
+ waitForAtLeastOneFrame().then(() => {
+ // All targets should be visible now.
+ takeScreenshot();
+ });
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html b/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html
new file mode 100644
index 00000000000..01f4d97947b
--- /dev/null
+++ b/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Anchor Positioning Test: position-visibility: no-overflow without an anchor</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#position-visibility">
+<link rel="match" href="position-visibility-no-overflow-ref.html">
+<style>
+ #scroll-container {
+ position: relative;
+ overflow: hidden scroll;
+ width: 400px;
+ height: 100px;
+ }
+
+ .anchor {
+ width: 100px;
+ height: 100px;
+ background: orange;
+ display: inline-block;
+ }
+
+ .target {
+ position: absolute;
+ position-visibility: no-overflow;
+ width: 100px;
+ height: 200px;
+ background: red;
+ top: 0;
+ left: 0;
+ }
+</style>
+
+<div id="scroll-container">
+ <div class="anchor">anchor1</div>
+ <!-- #target1 should not be visible because it overflows the containing block. -->
+ <div id="target1" class="target">target1</div>
+</div>
diff --git a/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html b/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html
new file mode 100644
index 00000000000..87e18049409
--- /dev/null
+++ b/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+<style>
+ .containing-block {
+ position: relative;
+ width: 150px;
+ height: 150px;
+ outline: 2px black solid;
+ }
+
+ .cell {
+ width: 50px;
+ height: 50px;
+ }
+
+ #anchor-cell {
+ position: absolute;
+ top: 50px;
+ left: 50px;
+
+ background: green;
+ }
+
+ .anchor-positioned-cell {
+ position: absolute;
+ }
+
+ #target-1 {
+ top: 0;
+ right: 0;
+ }
+
+ #target-2 {
+ bottom: 0;
+ left: 0;
+ }
+
+ #target-3 {
+ bottom: 0;
+ right: 0;
+ }
+
+ .blue-background {
+ background: blue;
+ }
+
+ .magenta-background {
+ background: magenta;
+ }
+
+ .cyan-background {
+ background: cyan;
+ }
+</style>
+
+<body>
+ <div class="containing-block">
+ <div class="cell" id="anchor-cell"></div>
+
+ <div class="cell anchor-positioned-cell" id="target-1">
+ <div class="cell blue-background"></div>
+ </div>
+
+ <div class="cell anchor-positioned-cell" id="target-2">
+ <div class="cell magenta-background"></div>
+ </div>
+
+ <div class="cell anchor-positioned-cell" id="target-3">
+ <div class="cell cyan-background"></div>
+ </div>
+ </div>
+</body> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html
new file mode 100644
index 00000000000..b38b7f3f278
--- /dev/null
+++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>shape-outside with corner-shape: notch</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#shapes-from-box-values">
+<link rel="help" href="https://drafts.csswg.org/css-borders-4/#corner-shape">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+body {
+ margin: 0;
+}
+.container {
+ width: 200px;
+ line-height: 0;
+}
+
+.shape {
+ float: left;
+ shape-outside: border-box;
+ border-radius: 48%;
+ box-sizing: content-box;
+ height: 40px;
+ width: 40px;
+ padding: 20px;
+ border: 20px solid lightgreen;
+ margin: 20px;
+ background-color: orange;
+}
+
+.box {
+ display: inline-block;
+ width: 60px;
+ background-color: blue;
+}
+
+.longbox {
+ display: inline-block;
+ width: 200px;
+ height: 20px;
+ background-color: blue;
+}
+</style>
+
+<main class="container">
+ <div class="shape"></div>
+ <div class="longbox"></div> <!-- Saturate the margin space -->
+ <div class="box" style="height: 24px;"></div> <!-- Box at corner -->
+ <div class="box" style="height: 36px;"></div>
+ <div class="box" style="height: 36px;"></div>
+ <div class="box" style="height: 24px;"></div> <!-- Box at corner -->
+ <div class="longbox"></div> <!-- Saturate the margin space -->
+</main>
+
+<script>
+function shape_outside_corner_shape_test(corner_shape, expected) {
+ test(() => {
+ const shape = document.querySelector(".shape");
+ shape.style.setProperty("corner-shape", corner_shape);
+ const actual = Array.from(document.querySelectorAll(".container .box")).map(b => b.getBoundingClientRect().x);
+ assert_array_approx_equals(actual, expected, 2);
+ }, `corner-shape: ${corner_shape} with shape-outside`);
+}
+
+shape_outside_corner_shape_test("notch", [82, 140, 140, 82]);
+shape_outside_corner_shape_test("bevel", [106, 140, 140, 106]);
+shape_outside_corner_shape_test("notch bevel", [106, 140, 140, 82]);
+shape_outside_corner_shape_test("round", [130, 140, 140, 130]);
+shape_outside_corner_shape_test("square", [140, 140, 140, 140]);
+shape_outside_corner_shape_test("scoop", [88, 140, 140, 88]);
+shape_outside_corner_shape_test("superellipse(1.5)", [135, 140, 140, 135]);
+shape_outside_corner_shape_test("superellipse(-.8)", [88, 140, 140, 88]);
+</script> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html
new file mode 100644
index 00000000000..96a297230bb
--- /dev/null
+++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>shape-outside with corner-shape: notch</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#shapes-from-box-values">
+<link rel="help" href="https://drafts.csswg.org/css-borders-4/#corner-shape">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+body {
+ margin: 0;
+}
+.container {
+ direction: rtl;
+ width: 200px;
+ line-height: 0;
+}
+
+.shape {
+ float: right;
+ shape-outside: border-box;
+ border-radius: 50%;
+ box-sizing: content-box;
+ height: 40px;
+ width: 40px;
+ padding: 20px;
+ border: 20px solid lightgreen;
+ margin: 20px;
+ background-color: orange;
+}
+
+.box {
+ display: inline-block;
+ width: 60px;
+ background-color: blue;
+}
+
+.longbox {
+ display: inline-block;
+ width: 200px;
+ height: 20px;
+ background-color: blue;
+}
+</style>
+
+<main class="container">
+ <div class="shape"></div>
+ <div class="longbox"></div> <!-- Saturate the margin space -->
+ <div class="box" style="height: 24px;"></div> <!-- Box at corner -->
+ <div class="box" style="height: 36px;"></div>
+ <div class="box" style="height: 36px;"></div>
+ <div class="box" style="height: 24px;"></div> <!-- Box at corner -->
+ <div class="longbox"></div> <!-- Saturate the margin space -->
+</main>
+
+<script>
+ function shape_outside_corner_shape_test(corner_shape, expected) {
+ test(() => {
+ const shape = document.querySelector(".shape");
+ shape.style.setProperty("corner-shape", corner_shape);
+ const actual = Array.from(document.querySelectorAll(".container .box")).map(b => b.getBoundingClientRect().right);
+ assert_array_approx_equals(actual, expected, 2);
+ }, `corner-shape: ${corner_shape} with shape-outside`);
+ }
+ shape_outside_corner_shape_test("notch", [120, 60, 60, 120]);
+ shape_outside_corner_shape_test("bevel", [96, 60, 60, 96]);
+ shape_outside_corner_shape_test("notch bevel", [120, 60, 60, 96]);
+ shape_outside_corner_shape_test("round", [72, 60, 60, 72]);
+ shape_outside_corner_shape_test("square", [60, 60, 60, 60]);
+ shape_outside_corner_shape_test("scoop", [114, 60, 60, 114]);
+ shape_outside_corner_shape_test("superellipse(1.5)", [65, 60, 60, 65]);
+ shape_outside_corner_shape_test("superellipse(-.8)", [112, 60, 60, 112]);
+</script> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html
new file mode 100644
index 00000000000..2c1ccf86cc6
--- /dev/null
+++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>overflow-clip-margin with border-radius & corner-shape</title>
+<style>
+#outer {
+ width: 50px;
+ height: 50px;
+ border-radius: 25px;
+ box-shadow: black 0 0 0 100px;
+ corner-shape: bevel scoop notch squircle;
+ margin: 125px;
+ background: black;
+}
+</style>
+<div id="outer">
+</div>
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html
new file mode 100644
index 00000000000..97371aa6c3f
--- /dev/null
+++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>overflow-clip-margin with border-radius & corner-shape</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#overflow-clip-margin">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#shadow-shape">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-radius">
+<link rel="help" href="https://drafts.csswg.org/css-borders-4/#corner-shape">
+<link rel="match" href="corner-shape-overflow-clip-margin-ref.html">
+<meta name="fuzzy" content="maxDifference=0-64;totalPixels=0-180">
+<style>
+#outer {
+ width: 50px;
+ height: 50px;
+ overflow: clip;
+ border-radius: 25px;
+ overflow-clip-margin: 100px;
+ corner-shape: bevel scoop notch squircle;
+ margin: 125px;
+}
+#inner {
+ width: 50px;
+ height: 50px;
+ box-shadow: black 0 0 0 100px;
+ background: black;
+}
+</style>
+<div id="outer">
+ <div id="inner"></div>
+</div>
diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html b/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html
index 5bdc33b521a..cc49f339de7 100644
--- a/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html
+++ b/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html
@@ -19,11 +19,11 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
- test(()=> { assert_equals(table.offsetHeight, 120); }, "table");
- test(()=> { assert_equals(colgroup.offsetHeight, 100); }, "colgroup");
- test(()=> { assert_equals(col.offsetHeight, 100); }, "col");
- test(()=> { assert_equals(rowgroup.offsetHeight, 100); }, "rowgroup");
- test(()=> { assert_equals(row.offsetHeight, 100); }, "row");
- test(()=> { assert_equals(cell.offsetHeight, 100); }, "cell");
- test(()=> { assert_equals(content.offsetHeight, 100); }, "content");
+ test(()=> { assert_equals(table.offsetHeight, 70); }, "table");
+ test(()=> { assert_equals(colgroup.offsetHeight, 70); }, "colgroup");
+ test(()=> { assert_equals(col.offsetHeight, 70); }, "col");
+ test(()=> { assert_equals(rowgroup.offsetHeight, 70); }, "rowgroup");
+ test(()=> { assert_equals(row.offsetHeight, 70); }, "row");
+ test(()=> { assert_equals(cell.offsetHeight, 70); }, "cell");
+ test(()=> { assert_equals(content.offsetHeight, 70); }, "content");
</script>
diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html
index bdac1f40607..77516a6146f 100644
--- a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html
+++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html
@@ -39,103 +39,103 @@
test(() => {
assert_equals(table.offsetTop, 8, "offsetTop");
assert_equals(table.offsetLeft, 8, "offsetLeft");
- assert_equals(table.offsetWidth, 177, "offsetWidth");
- assert_equals(table.offsetHeight, 184, "offsetHeight");
+ assert_equals(table.offsetWidth, 70, "offsetWidth");
+ assert_equals(table.offsetHeight, 584, "offsetHeight");
}, "table");
test(() => {
assert_equals(colgroup.offsetTop, 18, "offsetTop");
assert_equals(colgroup.offsetLeft, 18, "offsetLeft");
- assert_equals(colgroup.offsetWidth, 157, "offsetWidth");
- assert_equals(colgroup.offsetHeight, 107, "offsetHeight");
+ assert_equals(colgroup.offsetWidth, 70, "offsetWidth");
+ assert_equals(colgroup.offsetHeight, 507, "offsetHeight");
}, "colgroup");
test(() => {
assert_equals(col.offsetTop, 18, "offsetTop");
assert_equals(col.offsetLeft, 18, "offsetLeft");
- assert_equals(col.offsetWidth, 157, "offsetWidth");
- assert_equals(col.offsetHeight, 50, "offsetHeight");
+ assert_equals(col.offsetWidth, 70, "offsetWidth");
+ assert_equals(col.offsetHeight, 450, "offsetHeight");
}, "col");
test(() => {
assert_equals(col2.offsetTop, 75, "offsetTop");
assert_equals(col2.offsetLeft, 18, "offsetLeft");
- assert_equals(col2.offsetWidth, 157, "offsetWidth");
- assert_equals(col2.offsetHeight, 50, "offsetHeight");
+ assert_equals(col2.offsetWidth, 70, "offsetWidth");
+ assert_equals(col2.offsetHeight, 450, "offsetHeight");
}, "col2");
test(() => {
assert_equals(colgroup2.offsetTop, 132, "offsetTop");
assert_equals(colgroup2.offsetLeft, 18, "offsetLeft");
- assert_equals(colgroup2.offsetWidth, 157, "offsetWidth");
- assert_equals(colgroup2.offsetHeight, 50, "offsetHeight");
+ assert_equals(colgroup2.offsetWidth, 70, "offsetWidth");
+ assert_equals(colgroup2.offsetHeight, 450, "offsetHeight");
}, "colgroup2");
test(() => {
assert_equals(col3.offsetTop, 132, "offsetTop");
assert_equals(col3.offsetLeft, 18, "offsetLeft");
- assert_equals(col3.offsetWidth, 157, "offsetWidth");
- assert_equals(col3.offsetHeight, 50, "offsetHeight");
+ assert_equals(col3.offsetWidth, 70, "offsetWidth");
+ assert_equals(col3.offsetHeight, 450, "offsetHeight");
}, "col3");
test(() => {
assert_equals(rowgroup.offsetTop, 18, "offsetTop");
assert_equals(rowgroup.offsetLeft, 18, "offsetLeft");
- assert_equals(rowgroup.offsetWidth, 157, "offsetWidth");
- assert_equals(rowgroup.offsetHeight, 164, "offsetHeight");
+ assert_equals(rowgroup.offsetWidth, 70, "offsetWidth");
+ assert_equals(rowgroup.offsetHeight, 564, "offsetHeight");
}, "rowgroup");
test(() => {
assert_equals(row.offsetTop, 18, "offsetTop");
assert_equals(row.offsetLeft, 18, "offsetLeft");
- assert_equals(row.offsetWidth, 100, "offsetWidth");
- assert_equals(row.offsetHeight, 164, "offsetHeight");
+ assert_equals(row.offsetWidth, 70, "offsetWidth");
+ assert_equals(row.offsetHeight, 364, "offsetHeight");
}, "row");
test(() => {
assert_equals(cell.offsetTop, 18, "offsetTop");
assert_equals(cell.offsetLeft, 18, "offsetLeft");
- assert_equals(cell.offsetWidth, 100, "offsetWidth");
- assert_equals(cell.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell.offsetHeight, 250, "offsetHeight");
}, "cell");
test(() => {
assert_equals(content.offsetTop, 18, "offsetTop");
assert_equals(content.offsetLeft, 18, "offsetLeft");
- assert_equals(content.offsetWidth, 100, "offsetWidth");
- assert_equals(content.offsetHeight, 50, "offsetHeight");
+ assert_equals(content.offsetWidth, 70, "offsetWidth");
+ assert_equals(content.offsetHeight, 250, "offsetHeight");
}, "content");
test(() => {
assert_equals(cell2.offsetTop, 75, "offsetTop");
assert_equals(cell2.offsetLeft, 18, "offsetLeft");
- assert_equals(cell2.offsetWidth, 100, "offsetWidth");
- assert_equals(cell2.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell2.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell2.offsetHeight, 250, "offsetHeight");
}, "cell2");
test(() => {
assert_equals(content2.offsetTop, 75, "offsetTop");
assert_equals(content2.offsetLeft, 18, "offsetLeft");
- assert_equals(content2.offsetWidth, 100, "offsetWidth");
- assert_equals(content2.offsetHeight, 50, "offsetHeight");
+ assert_equals(content2.offsetWidth, 70, "offsetWidth");
+ assert_equals(content2.offsetHeight, 250, "offsetHeight");
}, "content2");
test(() => {
assert_equals(cell3.offsetTop, 132, "offsetTop");
assert_equals(cell3.offsetLeft, 18, "offsetLeft");
- assert_equals(cell3.offsetWidth, 100, "offsetWidth");
- assert_equals(cell3.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell3.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell3.offsetHeight, 250, "offsetHeight");
}, "cell3");
test(() => {
assert_equals(content3.offsetTop, 132, "offsetTop");
assert_equals(content3.offsetLeft, 18, "offsetLeft");
- assert_equals(content3.offsetWidth, 100, "offsetWidth");
- assert_equals(content3.offsetHeight, 50, "offsetHeight");
+ assert_equals(content3.offsetWidth, 70, "offsetWidth");
+ assert_equals(content3.offsetHeight, 250, "offsetHeight");
}, "content3");
test(() => {
assert_equals(row2.offsetTop, 218, "offsetTop");
assert_equals(row2.offsetLeft, 55, "offsetLeft");
- assert_equals(row2.offsetWidth, 50, "offsetWidth");
- assert_equals(row2.offsetHeight, 164, "offsetHeight");
+ assert_equals(row2.offsetWidth, 70, "offsetWidth");
+ assert_equals(row2.offsetHeight, 364, "offsetHeight");
}, "row2");
test(() => {
assert_equals(cell4.offsetTop, 218, "offsetTop");
assert_equals(cell4.offsetLeft, 55, "offsetLeft");
- assert_equals(cell4.offsetWidth, 50, "offsetWidth");
- assert_equals(cell4.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell4.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell4.offsetHeight, 250, "offsetHeight");
}, "cell4");
test(() => {
assert_equals(content4.offsetTop, 218, "offsetTop");
assert_equals(content4.offsetLeft, 55, "offsetLeft");
- assert_equals(content4.offsetWidth, 50, "offsetWidth");
- assert_equals(content4.offsetHeight, 50, "offsetHeight");
+ assert_equals(content4.offsetWidth, 70, "offsetWidth");
+ assert_equals(content4.offsetHeight, 250, "offsetHeight");
}, "content4");
</script>
diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html
index 1eb751032ca..ea58b145738 100644
--- a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html
+++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html
@@ -39,103 +39,103 @@
test(() => {
assert_equals(table.offsetTop, 8, "offsetTop");
assert_equals(table.offsetLeft, 8, "offsetLeft");
- assert_equals(table.offsetWidth, 177, "offsetWidth");
- assert_equals(table.offsetHeight, 184, "offsetHeight");
+ assert_equals(table.offsetWidth, 70, "offsetWidth");
+ assert_equals(table.offsetHeight, 584, "offsetHeight");
}, "table");
test(() => {
assert_equals(colgroup.offsetTop, 18, "offsetTop");
assert_equals(colgroup.offsetLeft, 8, "offsetLeft");
- assert_equals(colgroup.offsetWidth, 157, "offsetWidth");
- assert_equals(colgroup.offsetHeight, 107, "offsetHeight");
+ assert_equals(colgroup.offsetWidth, 70, "offsetWidth");
+ assert_equals(colgroup.offsetHeight, 507, "offsetHeight");
}, "colgroup");
test(() => {
assert_equals(col.offsetTop, 18, "offsetTop");
assert_equals(col.offsetLeft, 8, "offsetLeft");
- assert_equals(col.offsetWidth, 157, "offsetWidth");
- assert_equals(col.offsetHeight, 50, "offsetHeight");
+ assert_equals(col.offsetWidth, 70, "offsetWidth");
+ assert_equals(col.offsetHeight, 450, "offsetHeight");
}, "col");
test(() => {
assert_equals(col2.offsetTop, 75, "offsetTop");
assert_equals(col2.offsetLeft, 8, "offsetLeft");
- assert_equals(col2.offsetWidth, 157, "offsetWidth");
- assert_equals(col2.offsetHeight, 50, "offsetHeight");
+ assert_equals(col2.offsetWidth, 70, "offsetWidth");
+ assert_equals(col2.offsetHeight, 450, "offsetHeight");
}, "col2");
test(() => {
assert_equals(colgroup2.offsetTop, 132, "offsetTop");
assert_equals(colgroup2.offsetLeft, 8, "offsetLeft");
- assert_equals(colgroup2.offsetWidth, 157, "offsetWidth");
- assert_equals(colgroup2.offsetHeight, 50, "offsetHeight");
+ assert_equals(colgroup2.offsetWidth, 70, "offsetWidth");
+ assert_equals(colgroup2.offsetHeight, 450, "offsetHeight");
}, "colgroup2");
test(() => {
assert_equals(col3.offsetTop, 132, "offsetTop");
assert_equals(col3.offsetLeft, 8, "offsetLeft");
- assert_equals(col3.offsetWidth, 157, "offsetWidth");
- assert_equals(col3.offsetHeight, 50, "offsetHeight");
+ assert_equals(col3.offsetWidth, 70, "offsetWidth");
+ assert_equals(col3.offsetHeight, 450, "offsetHeight");
}, "col3");
test(() => {
assert_equals(rowgroup.offsetTop, 18, "offsetTop");
assert_equals(rowgroup.offsetLeft, 8, "offsetLeft");
- assert_equals(rowgroup.offsetWidth, 157, "offsetWidth");
- assert_equals(rowgroup.offsetHeight, 164, "offsetHeight");
+ assert_equals(rowgroup.offsetWidth, 70, "offsetWidth");
+ assert_equals(rowgroup.offsetHeight, 564, "offsetHeight");
}, "rowgroup");
test(() => {
assert_equals(row.offsetTop, 18, "offsetTop");
assert_equals(row.offsetLeft, 8, "offsetLeft");
- assert_equals(row.offsetWidth, 100, "offsetWidth");
- assert_equals(row.offsetHeight, 164, "offsetHeight");
+ assert_equals(row.offsetWidth, 70, "offsetWidth");
+ assert_equals(row.offsetHeight, 364, "offsetHeight");
}, "row");
test(() => {
assert_equals(cell.offsetTop, 18, "offsetTop");
assert_equals(cell.offsetLeft, 8, "offsetLeft");
- assert_equals(cell.offsetWidth, 100, "offsetWidth");
- assert_equals(cell.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell.offsetHeight, 250, "offsetHeight");
}, "cell");
test(() => {
assert_equals(content.offsetTop, 18, "offsetTop");
assert_equals(content.offsetLeft, 8, "offsetLeft");
- assert_equals(content.offsetWidth, 100, "offsetWidth");
- assert_equals(content.offsetHeight, 50, "offsetHeight");
+ assert_equals(content.offsetWidth, 70, "offsetWidth");
+ assert_equals(content.offsetHeight, 250, "offsetHeight");
}, "content");
test(() => {
assert_equals(cell2.offsetTop, 75, "offsetTop");
assert_equals(cell2.offsetLeft, 8, "offsetLeft");
- assert_equals(cell2.offsetWidth, 100, "offsetWidth");
- assert_equals(cell2.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell2.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell2.offsetHeight, 250, "offsetHeight");
}, "cell2");
test(() => {
assert_equals(content2.offsetTop, 75, "offsetTop");
assert_equals(content2.offsetLeft, 8, "offsetLeft");
- assert_equals(content2.offsetWidth, 100, "offsetWidth");
- assert_equals(content2.offsetHeight, 50, "offsetHeight");
+ assert_equals(content2.offsetWidth, 70, "offsetWidth");
+ assert_equals(content2.offsetHeight, 250, "offsetHeight");
}, "content2");
test(() => {
assert_equals(cell3.offsetTop, 132, "offsetTop");
assert_equals(cell3.offsetLeft, 8, "offsetLeft");
- assert_equals(cell3.offsetWidth, 100, "offsetWidth");
- assert_equals(cell3.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell3.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell3.offsetHeight, 250, "offsetHeight");
}, "cell3");
test(() => {
assert_equals(content3.offsetTop, 132, "offsetTop");
assert_equals(content3.offsetLeft, 8, "offsetLeft");
- assert_equals(content3.offsetWidth, 100, "offsetWidth");
- assert_equals(content3.offsetHeight, 50, "offsetHeight");
+ assert_equals(content3.offsetWidth, 70, "offsetWidth");
+ assert_equals(content3.offsetHeight, 250, "offsetHeight");
}, "content3");
test(() => {
assert_equals(row2.offsetTop, 218, "offsetTop");
assert_equals(row2.offsetLeft, 8, "offsetLeft");
- assert_equals(row2.offsetWidth, 50, "offsetWidth");
- assert_equals(row2.offsetHeight, 164, "offsetHeight");
+ assert_equals(row2.offsetWidth, 70, "offsetWidth");
+ assert_equals(row2.offsetHeight, 364, "offsetHeight");
}, "row2");
test(() => {
assert_equals(cell4.offsetTop, 218, "offsetTop");
assert_equals(cell4.offsetLeft, 8, "offsetLeft");
- assert_equals(cell4.offsetWidth, 50, "offsetWidth");
- assert_equals(cell4.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell4.offsetWidth, 70, "offsetWidth");
+ assert_equals(cell4.offsetHeight, 250, "offsetHeight");
}, "cell4");
test(() => {
assert_equals(content4.offsetTop, 218, "offsetTop");
assert_equals(content4.offsetLeft, 8, "offsetLeft");
- assert_equals(content4.offsetWidth, 50, "offsetWidth");
- assert_equals(content4.offsetHeight, 50, "offsetHeight");
+ assert_equals(content4.offsetWidth, 70, "offsetWidth");
+ assert_equals(content4.offsetHeight, 250, "offsetHeight");
}, "content4");
</script>
diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html
index 265d761ffb3..4bed47b6a4d 100644
--- a/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html
+++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html
@@ -38,103 +38,103 @@
test(() => {
assert_equals(table.offsetTop, 8, "offsetTop");
assert_equals(table.offsetLeft, 8, "offsetLeft");
- assert_equals(table.offsetWidth, 184, "offsetWidth");
- assert_equals(table.offsetHeight, 177, "offsetHeight");
+ assert_equals(table.offsetWidth, 584, "offsetWidth");
+ assert_equals(table.offsetHeight, 70, "offsetHeight");
}, "table");
test(() => {
assert_equals(colgroup.offsetTop, 18, "offsetTop");
assert_equals(colgroup.offsetLeft, 18, "offsetLeft");
- assert_equals(colgroup.offsetWidth, 107, "offsetWidth");
- assert_equals(colgroup.offsetHeight, 157, "offsetHeight");
+ assert_equals(colgroup.offsetWidth, 507, "offsetWidth");
+ assert_equals(colgroup.offsetHeight, 70, "offsetHeight");
}, "colgroup");
test(() => {
assert_equals(col.offsetTop, 18, "offsetTop");
assert_equals(col.offsetLeft, 18, "offsetLeft");
- assert_equals(col.offsetWidth, 50, "offsetWidth");
- assert_equals(col.offsetHeight, 157, "offsetHeight");
+ assert_equals(col.offsetWidth, 450, "offsetWidth");
+ assert_equals(col.offsetHeight, 70, "offsetHeight");
}, "col");
test(() => {
assert_equals(col2.offsetTop, 18, "offsetTop");
assert_equals(col2.offsetLeft, 75, "offsetLeft");
- assert_equals(col2.offsetWidth, 50, "offsetWidth");
- assert_equals(col2.offsetHeight, 157, "offsetHeight");
+ assert_equals(col2.offsetWidth, 450, "offsetWidth");
+ assert_equals(col2.offsetHeight, 70, "offsetHeight");
}, "col2");
test(() => {
assert_equals(colgroup2.offsetTop, 18, "offsetTop");
assert_equals(colgroup2.offsetLeft, 132, "offsetLeft");
- assert_equals(colgroup2.offsetWidth, 50, "offsetWidth");
- assert_equals(colgroup2.offsetHeight, 157, "offsetHeight");
+ assert_equals(colgroup2.offsetWidth, 450, "offsetWidth");
+ assert_equals(colgroup2.offsetHeight, 70, "offsetHeight");
}, "colgroup2");
test(() => {
assert_equals(col3.offsetTop, 18, "offsetTop");
assert_equals(col3.offsetLeft, 132, "offsetLeft");
- assert_equals(col3.offsetWidth, 50, "offsetWidth");
- assert_equals(col3.offsetHeight, 157, "offsetHeight");
+ assert_equals(col3.offsetWidth, 450, "offsetWidth");
+ assert_equals(col3.offsetHeight, 70, "offsetHeight");
}, "col3");
test(() => {
assert_equals(rowgroup.offsetTop, 18, "offsetTop");
assert_equals(rowgroup.offsetLeft, 18, "offsetLeft");
- assert_equals(rowgroup.offsetWidth, 164, "offsetWidth");
- assert_equals(rowgroup.offsetHeight, 157, "offsetHeight");
+ assert_equals(rowgroup.offsetWidth, 564, "offsetWidth");
+ assert_equals(rowgroup.offsetHeight, 70, "offsetHeight");
}, "rowgroup");
test(() => {
assert_equals(row.offsetTop, 18, "offsetTop");
assert_equals(row.offsetLeft, 18, "offsetLeft");
- assert_equals(row.offsetWidth, 164, "offsetWidth");
- assert_equals(row.offsetHeight, 100, "offsetHeight");
+ assert_equals(row.offsetWidth, 364, "offsetWidth");
+ assert_equals(row.offsetHeight, 70, "offsetHeight");
}, "row");
test(() => {
assert_equals(cell.offsetTop, 18, "offsetTop");
assert_equals(cell.offsetLeft, 18, "offsetLeft");
- assert_equals(cell.offsetWidth, 50, "offsetWidth");
- assert_equals(cell.offsetHeight, 100, "offsetHeight");
+ assert_equals(cell.offsetWidth, 250, "offsetWidth");
+ assert_equals(cell.offsetHeight, 70, "offsetHeight");
}, "cell");
test(() => {
assert_equals(content.offsetTop, 18, "offsetTop");
assert_equals(content.offsetLeft, 18, "offsetLeft");
- assert_equals(content.offsetWidth, 50, "offsetWidth");
- assert_equals(content.offsetHeight, 100, "offsetHeight");
+ assert_equals(content.offsetWidth, 250, "offsetWidth");
+ assert_equals(content.offsetHeight, 70, "offsetHeight");
}, "content");
test(() => {
assert_equals(cell2.offsetTop, 18, "offsetTop");
assert_equals(cell2.offsetLeft, 75, "offsetLeft");
- assert_equals(cell2.offsetWidth, 50, "offsetWidth");
- assert_equals(cell2.offsetHeight, 100, "offsetHeight");
+ assert_equals(cell2.offsetWidth, 250, "offsetWidth");
+ assert_equals(cell2.offsetHeight, 70, "offsetHeight");
}, "cell2");
test(() => {
assert_equals(content2.offsetTop, 18, "offsetTop");
assert_equals(content2.offsetLeft, 75, "offsetLeft");
- assert_equals(content2.offsetWidth, 50, "offsetWidth");
- assert_equals(content2.offsetHeight, 100, "offsetHeight");
+ assert_equals(content2.offsetWidth, 250, "offsetWidth");
+ assert_equals(content2.offsetHeight, 70, "offsetHeight");
}, "content2");
test(() => {
assert_equals(cell3.offsetTop, 18, "offsetTop");
assert_equals(cell3.offsetLeft, 132, "offsetLeft");
- assert_equals(cell3.offsetWidth, 50, "offsetWidth");
- assert_equals(cell3.offsetHeight, 100, "offsetHeight");
+ assert_equals(cell3.offsetWidth, 250, "offsetWidth");
+ assert_equals(cell3.offsetHeight, 70, "offsetHeight");
}, "cell3");
test(() => {
assert_equals(content3.offsetTop, 18, "offsetTop");
assert_equals(content3.offsetLeft, 132, "offsetLeft");
- assert_equals(content3.offsetWidth, 50, "offsetWidth");
- assert_equals(content3.offsetHeight, 100, "offsetHeight");
+ assert_equals(content3.offsetWidth, 250, "offsetWidth");
+ assert_equals(content3.offsetHeight, 70, "offsetHeight");
}, "content3");
test(() => {
assert_equals(row2.offsetTop, 55, "offsetTop");
assert_equals(row2.offsetLeft, 218, "offsetLeft");
- assert_equals(row2.offsetWidth, 164, "offsetWidth");
- assert_equals(row2.offsetHeight, 50, "offsetHeight");
+ assert_equals(row2.offsetWidth, 364, "offsetWidth");
+ assert_equals(row2.offsetHeight, 70, "offsetHeight");
}, "row2");
test(() => {
assert_equals(cell4.offsetTop, 55, "offsetTop");
assert_equals(cell4.offsetLeft, 218, "offsetLeft");
- assert_equals(cell4.offsetWidth, 50, "offsetWidth");
- assert_equals(cell4.offsetHeight, 50, "offsetHeight");
+ assert_equals(cell4.offsetWidth, 250, "offsetWidth");
+ assert_equals(cell4.offsetHeight, 70, "offsetHeight");
}, "cell4");
test(() => {
assert_equals(content4.offsetTop, 55, "offsetTop");
assert_equals(content4.offsetLeft, 218, "offsetLeft");
- assert_equals(content4.offsetWidth, 50, "offsetWidth");
- assert_equals(content4.offsetHeight, 50, "offsetHeight");
+ assert_equals(content4.offsetWidth, 250, "offsetWidth");
+ assert_equals(content4.offsetHeight, 70, "offsetHeight");
}, "content4");
</script>
diff --git a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
index 9bb87459623..a5c489e40a6 100644
--- a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
+++ b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html
@@ -871,6 +871,7 @@
fuzzy_test_computed_color(`lch(from var(--mycolor) l 0 h)`, `lch(62.75 0 326.96)`, 0.02);
fuzzy_test_computed_color(`var(--mygray)`, `lch(62.75 0 326.96)`, 0.02);
fuzzy_test_computed_color(`lch(from var(--mygray) l 30 h)`, `lch(62.75 30 326.96)`, 0.02);
+ fuzzy_test_computed_color(`LCH(from var(--accent) l c calc(h + 180 * sibling-index()))`, `lch(65.49 39.45 10.11)`, 0.02);
</script>
</body>
</html>
diff --git a/tests/wpt/tests/css/css-contain/contain-inline-size-grid-auto-fit.html b/tests/wpt/tests/css/css-contain/contain-inline-size-grid-auto-fit.html
new file mode 100644
index 00000000000..b6401ac6640
--- /dev/null
+++ b/tests/wpt/tests/css/css-contain/contain-inline-size-grid-auto-fit.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="author" title="Sammy Gill" href="mailto:sammy.gill@apple.com">
+<link rel="help" href="https://www.w3.org/TR/css-contain-2/#containment-size">
+<link rel="help" href="https://drafts.csswg.org/css-grid-2/#auto-repeat">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<style>
+.container {
+ width: 100px;
+}
+.grid {
+ display: grid;
+ height: 100px;
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ contain: inline-size;
+}
+.grid-item {
+ background-color: green;
+}
+</style>
+</head>
+<body>
+<p>Test passes if there is a filled green square.</p>
+<div class="container">
+ <div class="grid">
+ <div class="grid-item">
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html b/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html
new file mode 100644
index 00000000000..6de60c9f1d8
--- /dev/null
+++ b/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Content Test: counter() in alt text parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-content-3/#content-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<div id="target"></div>
+<script>
+ test_valid_value("content", `"" / counter(cnt)`);
+ test_valid_value("content", `"regular text" / "alt text 1" counter(cnt) "alt text 2"`);
+ test_valid_value("content", `"regular text" / counter(cnt) "alt text"`);
+</script>
diff --git a/tests/wpt/tests/css/css-fonts/font-family-name-000.xht b/tests/wpt/tests/css/css-fonts/font-family-name-000.xht
index 2afa0bafc04..4eee0d23233 100644
--- a/tests/wpt/tests/css/css-fonts/font-family-name-000.xht
+++ b/tests/wpt/tests/css/css-fonts/font-family-name-000.xht
@@ -1,26 +1,27 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
- <title>CSS Test: Test for prescense of test fonts</title>
+ <title>CSS Test: Test for presence of test fonts</title>
<link rel="author" title="Mozilla" href="http://www.mozilla.com/" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#propdef-font-family" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#font-family-prop" />
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-family-prop"/>
+ <link rel="match" href="font-family-name-ref.xht"/>
<meta name="assert" content="Test will fail if CSSTest fonts are not installed" />
<style type="text/css">
- div#test1 {
+ body { font-size: 36px; }
+ span#verify { font-family: CSSTest Verify; }
+ p#test1 {
font-family: CSSTest Verify;
}
- div#test2 {
+ p#test2 {
font-family: CSSTest Unknown, CSSTest Fallback; /* should be no 'CSSTest Unknown' font installed */
}
</style>
</head>
<body>
<div><a href="http://www.w3.org/Style/CSS/Test/Fonts/">Test fonts</a> must be installed for this test: <span id="verify">FAIL</span></div>
- <p>Test passes if FAIL does not appear below.</p>
- <p>Prerequisites: these tests require that CSSTest fonts be installed.</p>
- <div id="test1">FAIL</div>
- <div id="test2">FAIL</div>
+ <p id="test1">FAIL</p>
+ <p id="test2">FAIL</p>
</body>
</html>
diff --git a/tests/wpt/tests/css/css-fonts/font-family-name-024.xht b/tests/wpt/tests/css/css-fonts/font-family-name-024.xht
index 20aec304fa4..6630cfd6090 100644
--- a/tests/wpt/tests/css/css-fonts/font-family-name-024.xht
+++ b/tests/wpt/tests/css/css-fonts/font-family-name-024.xht
@@ -9,7 +9,11 @@
<link rel="match" href="font-family-name-024-ref.xht"/>
<meta name="assert" content="System font names are only allowed with the font shorthand, not in font-family rules" />
<style type="text/css">
- body { font-size: 36px; }
+ body {
+ font-size: 36px;
+ /* prevent scrollbar because of visually empty paragraph elements */
+ overflow: hidden;
+ }
span#verify { font-family: CSSTest Verify; }
div.test { font-family: CSSTest Fallback; }
p {
diff --git a/tests/wpt/tests/css/css-fonts/font-palette-relative-color-crash.html b/tests/wpt/tests/css/css-fonts/font-palette-relative-color-crash.html
new file mode 100644
index 00000000000..1dc973a00b9
--- /dev/null
+++ b/tests/wpt/tests/css/css-fonts/font-palette-relative-color-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>CSS Fonts: override-colors with relative color crashing Chrome</title>
+<link rel="help" href="https://crbug.com/417172068">
+<style>
+ @font-face {
+ font-family: Foo;
+ src: url(notfound.ttf);
+ }
+ @font-palette-values --foo {
+ font-family: Foo;
+ override-colors: 0 lch(from blue calc(0.5 * l) c h);
+ }
+ #target {
+ font-family: Foo;
+ font-palette: --foo;
+ }
+</style>
+<div id="target">Foo</div>
diff --git a/tests/wpt/tests/css/css-fonts/test-synthetic-bold-notref.html b/tests/wpt/tests/css/css-fonts/test-synthetic-bold-notref.html
new file mode 100644
index 00000000000..4a952acb46f
--- /dev/null
+++ b/tests/wpt/tests/css/css-fonts/test-synthetic-bold-notref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Test: Test for synthetic bold rendering</title>
+ <style type="text/css">
+ div {
+ font-size: 36px;
+ font-family: "CSSTest Verify";
+ }
+ </style>
+ </head>
+ <body>
+ <div><a href="http://www.w3.org/Style/CSS/Test/Fonts/">Test fonts</a> must be installed for this test: PASS</div>
+ <p>Browser supports synthetic bolding if PASS appears on both lines and the second line appears bolder:</p>
+ <div>PASS</div>
+ <div>PASS</div>
+ </body>
+</html>
diff --git a/tests/wpt/tests/css/css-fonts/test-synthetic-bold.xht b/tests/wpt/tests/css/css-fonts/test-synthetic-bold.html
index 2d34f02a92a..c2337c0a3ce 100644
--- a/tests/wpt/tests/css/css-fonts/test-synthetic-bold.xht
+++ b/tests/wpt/tests/css/css-fonts/test-synthetic-bold.html
@@ -1,15 +1,16 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+<!DOCTYPE html>
+<html>
<head>
<title>CSS Test: Test for synthetic bold rendering</title>
<link rel="author" title="Mozilla" href="http://www.mozilla.com/" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#propdef-font-weight" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#font-boldness" />
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-weight-prop" />
+ <link rel="mismatch" href="test-synthetic-bold-notref.html" />
<meta name="assert" content="Synthetic bold text should render differently than normal text" />
<style type="text/css">
div { font-size: 36px; }
- span#verify {font-family: "CSSTest Verify";}
+ span#verify { font-family: "CSSTest Verify"; }
div#test1 {
font-family: CSSTest Verify;
}
@@ -25,4 +26,4 @@
<div id="test1">FAIL</div>
<div id="test2">FAIL</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/tests/wpt/tests/css/css-fonts/test-synthetic-italic-notref.html b/tests/wpt/tests/css/css-fonts/test-synthetic-italic-notref.html
new file mode 100644
index 00000000000..3684f3ae804
--- /dev/null
+++ b/tests/wpt/tests/css/css-fonts/test-synthetic-italic-notref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Test: Test for synthetic italic rendering</title>
+ <style type="text/css">
+ div { font-size: 36px; }
+ span#verify { font-family: "CSSTest Verify"; }
+ div#test1, div#test2 {
+ font-family: CSSTest Verify;
+ }
+ </style>
+ </head>
+ <body>
+ <div><a href="http://www.w3.org/Style/CSS/Test/Fonts/">Test fonts</a> must be installed for this test: <span id="verify">FAIL</span></div>
+ <p>Browser supports synthetic italics if PASS appears on both lines and the second line is slanted right:</p>
+ <div id="test1">FAIL</div>
+ <div id="test2">FAIL</div>
+ </body>
+</html>
diff --git a/tests/wpt/tests/css/css-fonts/test-synthetic-italic.xht b/tests/wpt/tests/css/css-fonts/test-synthetic-italic.html
index 05b9cf67984..3f6764ecfa3 100644
--- a/tests/wpt/tests/css/css-fonts/test-synthetic-italic.xht
+++ b/tests/wpt/tests/css/css-fonts/test-synthetic-italic.html
@@ -1,11 +1,12 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
+<!DOCTYPE html>
+<html>
+ <head>
<title>CSS Test: Test for synthetic italic rendering</title>
<link rel="author" title="Mozilla" href="http://www.mozilla.com/" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#propdef-font-style" />
<link rel="help" href="http://www.w3.org/TR/CSS21/fonts.html#font-styling" />
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-style-prop"/>
+ <link rel="mismatch" href="test-synthetic-italic-notref.html" />
<meta name="assert" content="Synthetic italic text should render differently than normal text" />
<style type="text/css">
div { font-size: 36px; }
@@ -25,4 +26,4 @@
<div id="test1">FAIL</div>
<div id="test2">FAIL</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html b/tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html
index 5eb9a99f874..2788039a2d4 100644
--- a/tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html
+++ b/tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html
@@ -18,43 +18,43 @@
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 900'), url('./resources/csstest-weights-900-kerned.ttf');
+ src: url('./resources/csstest-weights-900-kerned.ttf');
font-weight: 100;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 800'), url('./resources/csstest-weights-800-kerned.ttf');
+ src: url('./resources/csstest-weights-800-kerned.ttf');
font-weight: 250;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 700'), url('./resources/csstest-weights-700-kerned.ttf');
+ src: url('./resources/csstest-weights-700-kerned.ttf');
font-weight: 400;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 600'), url('./resources/csstest-weights-600-kerned.ttf');
+ src: url('./resources/csstest-weights-600-kerned.ttf');
font-weight: 450;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 300'), url('./resources/csstest-weights-300-kerned.ttf');
+ src: url('./resources/csstest-weights-300-kerned.ttf');
font-weight: 500;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 200'), url('./resources/csstest-weights-200-kerned.ttf');
+ src: url('./resources/csstest-weights-200-kerned.ttf');
font-weight: 750;
}
@font-face {
font-family: fontMatch;
- src: local('CSSTest Weights 100'), url('./resources/csstest-weights-100-kerned.ttf');
+ src: url('./resources/csstest-weights-100-kerned.ttf');
font-weight: 900;
}
diff --git a/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003-ref.html b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003-ref.html
new file mode 100644
index 00000000000..52e45c4f65f
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<style>
+ body {
+ margin: 0px;
+ }
+ #current {
+ columns: 6;
+ column-gap: 2px;
+ column-rule-style: solid;
+ column-rule-width: 2px;
+ column-fill: auto;
+ height: 20px;
+ column-rule-color: hotpink;
+ width: 72px;
+ height: 20px;
+ }
+ .items {
+ background-color: lightgreen;
+ height: 20px
+ }
+</style>
+<body>
+ <div id="current">
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ </div>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003.html b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003.html
new file mode 100644
index 00000000000..2ec4a45beb7
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-003.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title>column-rule-color invalidates and paints correctly on multi-col</title>
+ <link rel="match" href="gap-decorations-003-ref.html">
+ <link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-other-colors">
+ <link rel="author" href="mailto:javiercon@microsoft.com">
+</head>
+<style>
+ body {
+ margin: 0px;
+ }
+ #current {
+ color: firebrick;
+ columns: 6;
+ column-gap: 2px;
+ column-rule-style: solid;
+ column-rule-width: 2px;
+ column-fill: auto;
+ height: 20px;
+ column-rule-color: gold;
+ width: 72px;
+ height: 20px;
+ }
+ .items {
+ background-color: lightgreen;
+ height: 20px
+ }
+</style>
+<body>
+ <div id="current">
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ <div class="items"></div>
+ </div>
+</body>
+<script>
+ // Use double requestAnimationFrame to remove need of setTimeout.
+ // Wait for the first frame to ensure that the style is computed.
+ requestAnimationFrame(() => {
+ // Wait for the second frame to ensure that the style is painted.
+ requestAnimationFrame(() => {
+ document.getElementById("current").style.columnRuleColor = "hotpink";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ });
+</script>
+</html>
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html
new file mode 100644
index 00000000000..b708a78a347
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .container {
+ display: flex;
+ width: 110px;
+ height: 110px;
+ column-gap: 10px;
+ row-gap: 10px;
+ flex-wrap: wrap;
+ }
+ .item {
+ background: skyblue;
+ height: 50px;
+ width: 50px;
+ margin: 0;
+ }
+ .row-gap {
+ position: absolute;
+ top: 50px;
+ background: gold;
+ width: 110px;
+ height: 10px;
+ }
+ .column-gap {
+ position: absolute;
+ top: 0px;
+ left: 50px;
+ background: blue;
+ height: 110px;
+ width: 10px;
+ }
+ .overflow {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ overflow: scroll;
+ height: 80px;
+ width: 80px;
+ }
+</style>
+<div class="overflow">
+ <div class="container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="column-gap"></div>
+ <div class="row-gap"></div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html
new file mode 100644
index 00000000000..6c07493d14d
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: flex gaps are painted when container scrolls.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="flex-gap-decorations-020-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .flex-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 110px;
+ width: 110px;
+ display: flex;
+ column-gap: 10px;
+ row-gap: 10px;
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 10px;
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 10px;
+ flex-wrap: wrap;
+ }
+ .flex-item {
+ background: skyblue;
+ width: 50px;
+ }
+ .overflow {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: scroll;
+ height: 80px;
+ width: 80px;
+ }
+</style>
+<div class="overflow">
+ <div class="flex-container">
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html
new file mode 100644
index 00000000000..1e28d73b4e2
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .container {
+ display: flex;
+ width: 110px;
+ height: 110px;
+ column-gap: 10px;
+ row-gap: 10px;
+ flex-wrap: wrap;
+ }
+ .item {
+ background: skyblue;
+ height: 50px;
+ width: 50px;
+ margin: 0;
+ }
+ .row-gap {
+ position: absolute;
+ top: 50px;
+ background: gold;
+ width: 110px;
+ height: 10px;
+ }
+ .column-gap {
+ position: absolute;
+ top: 0px;
+ left: 50px;
+ background: blue;
+ height: 110px;
+ width: 10px;
+ }
+ .overflow {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ overflow: hidden;
+ height: 80px;
+ width: 80px;
+ }
+</style>
+<div class="overflow">
+ <div class="container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="column-gap"></div>
+ <div class="row-gap"></div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html
new file mode 100644
index 00000000000..c59db4f635b
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: flex gaps are painted with overflow hidden.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="flex-gap-decorations-021-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .flex-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 110px;
+ width: 110px;
+ display: flex;
+ column-gap: 10px;
+ row-gap: 10px;
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 10px;
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 10px;
+ flex-wrap: wrap;
+ }
+ .flex-item {
+ background: skyblue;
+ width: 50px;
+ }
+ .overflow {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ height: 80px;
+ width: 80px;
+ }
+</style>
+<div class="overflow">
+ <div class="flex-container">
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html
new file mode 100644
index 00000000000..4e964879e79
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 90px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+ .row-gap {
+ position: absolute;
+ width: 320px;
+ height: 0px;
+ border-bottom: solid 5px gold;
+ }
+ .row-gap1 {
+ top: 92.5px;
+ }
+ .row-gap2 {
+ top: 222.5px;
+ }
+ .col-gap {
+ position: absolute;
+ top: 0px;
+ width: 0px;
+ height: 320px;
+ border-left: solid 5px blue;
+ }
+ .col-gap1 {
+ left: 102.5px;
+ }
+ .col-gap2 {
+ left: 212.5px;
+ }
+ .container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ }
+</style>
+<div class="container">
+ <div class="grid-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="col-gap col-gap1"> </div>
+ <div class="col-gap col-gap2"> </div>
+ <div class="row-gap row-gap1"> </div>
+ <div class="row-gap row-gap2"> </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html
new file mode 100644
index 00000000000..afe20ef5117
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: Gaps are painted with container with overflow hidden, with JS scroll
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-034-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 5px;
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 5px;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+</style>
+<body>
+ <div class="grid-container" id="hidden-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
+
+<script>
+ document.getElementById('hidden-container').scrollBy({top: 10, left: 0});
+</script>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html
new file mode 100644
index 00000000000..851360a99a4
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+ .row-gap {
+ position: absolute;
+ width: 320px;
+ height: 0px;
+ border-bottom: solid 5px gold;
+ }
+ .row-gap1 {
+ top: 102.5px;
+ }
+ .row-gap2 {
+ top: 212.5px;
+ }
+ .col-gap {
+ position: absolute;
+ top: 0px;
+ width: 0px;
+ height: 320px;
+ border-left: solid 5px blue;
+ }
+ .col-gap1 {
+ left: 102.5px;
+ }
+ .col-gap2 {
+ left: 212.5px;
+ }
+ .container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 130px;
+ height: 130px;
+ overflow: scroll;
+ }
+</style>
+<div class="container">
+ <div class="grid-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="col-gap col-gap1"> </div>
+ <div class="col-gap col-gap2"> </div>
+ <div class="row-gap row-gap1"> </div>
+ <div class="row-gap row-gap2"> </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html
new file mode 100644
index 00000000000..d2fa76094a9
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: Gaps are painted when container scrolls.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-035-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: scroll;
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 5px;
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 5px;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+</style>
+<body>
+ <div class="grid-container" id="scroll-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html
new file mode 100644
index 00000000000..29ed684d85f
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+ .row-gap {
+ position: absolute;
+ width: 320px;
+ height: 0px;
+ border-bottom: solid 5px gold;
+ }
+ .row-gap1 {
+ top: 102.5px;
+ }
+ .row-gap2 {
+ top: 212.5px;
+ }
+ .col-gap {
+ position: absolute;
+ top: 0px;
+ width: 0px;
+ height: 320px;
+ border-left: solid 5px blue;
+ }
+ .col-gap1 {
+ left: 102.5px;
+ }
+ .col-gap2 {
+ left: 212.5px;
+ }
+ .container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ }
+</style>
+<div class="container">
+ <div class="grid-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="col-gap col-gap1"> </div>
+ <div class="col-gap col-gap2"> </div>
+ <div class="row-gap row-gap1"> </div>
+ <div class="row-gap row-gap2"> </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html
new file mode 100644
index 00000000000..8b1e1e2e1c2
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: Gaps are painted with container with overflow hidden.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-036-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: hidden;
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 5px;
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 5px;
+ background: pink;
+ }
+ .item {
+ background: gray;
+ }
+</style>
+<body>
+ <div class="grid-container" id="hidden-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html
new file mode 100644
index 00000000000..4a2ee5bd5c6
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: scroll;
+ }
+ .item {
+ background: gray;
+ }
+ .row-gap {
+ position: absolute;
+ width: 320px;
+ height: 0px;
+ border-bottom: solid 5px gold;
+ }
+ .row-gap1 {
+ top: 102.5px;
+ }
+ .row-gap2 {
+ top: 212.5px;
+ }
+ .col-gap {
+ position: absolute;
+ top: 0px;
+ width: 0px;
+ height: 320px;
+ border-left: solid 5px blue;
+ }
+ .col-gap1 {
+ left: 102.5px;
+ }
+ .col-gap2 {
+ left: 212.5px;
+ }
+ .container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 130px;
+ height: 130px;
+ overflow: scroll;
+ }
+</style>
+<div class="container">
+ <div class="grid-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="col-gap col-gap1"> </div>
+ <div class="col-gap col-gap2"> </div>
+ <div class="row-gap row-gap1"> </div>
+ <div class="row-gap row-gap2"> </div>
+</div>
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html
new file mode 100644
index 00000000000..656bfee7dfc
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>
+ CSS Gap Decorations: Gaps are painted with container with overflow scroll and no background.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="grid-gap-decorations-037-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+ body {
+ margin: 0px;
+ }
+
+ .grid-container {
+ display: grid;
+ grid-gap: 10px;
+ grid-template-columns: 100px 100px 100px;
+ grid-template-rows: 100px 100px 100px;
+ width: 130px;
+ height: 130px;
+ overflow: scroll;
+
+ column-rule-color: blue;
+ column-rule-style: solid;
+ column-rule-width: 5px;
+
+ row-rule-color: gold;
+ row-rule-style: solid;
+ row-rule-width: 5px;
+ }
+
+ .item {
+ background: gray;
+ }
+</style>
+
+<body>
+ <div class="grid-container">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html
new file mode 100644
index 00000000000..562c166e90b
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed-from-longhands.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Gap Decorations: individual separate longhands form shorthand</title>
+ <link rel="help" href="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
+ <meta name="assert" content="Setting *-rule-width, *-rule-style, and *-rule-color results in the misaligned column-rule shorthand.">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+ <div id="target"></div>
+<script>
+const testCases = [
+ {
+ width: '5px',
+ style: 'solid',
+ color: 'rgb(0, 128, 0)',
+ expected: '5px solid rgb(0, 128, 0)'
+ },
+ {
+ width: 'repeat(auto, 5px)',
+ style: 'repeat(auto, solid)',
+ color: 'repeat(auto, rgb(255, 0, 0))',
+ expected: 'repeat(auto, 5px solid rgb(255, 0, 0))'
+ },
+
+ // The following test cases return an empty string because the longhands do not
+ // line up.
+ {
+ width: 'repeat(auto, thin medium)',
+ style: 'solid',
+ color: 'repeat(8, red blue)',
+ expected: ''
+ },
+ {
+ width: 'repeat(6, 15px thick)',
+ style: 'repeat(auto, solid)',
+ color: 'repeat(auto, red)',
+ expected: ''
+ },
+ {
+ width: '15px 25px 35px',
+ style: 'solid dotted',
+ color: 'green',
+ expected: ''
+ },
+ {
+ width: 'repeat(auto, 5px)',
+ style: 'solid double',
+ color: 'repeat(7, red)',
+ expected: ''
+ },
+ {
+ width: 'repeat(auto, 5px 8px 10px)',
+ style: 'repeat(auto, solid double)',
+ color: 'repeat(auto, red green blue)',
+ expected: ''
+ },
+ {
+ width: 'repeat(2, 1px 3px 5px)',
+ style: 'repeat(2, solid double)',
+ color: 'repeat(2, red)',
+ expected: ''
+ },
+];
+
+for (const {width, style, color, expected} of testCases) {
+ let div = document.querySelector('#target');
+
+ div.style.columnRuleWidth = width;
+ div.style.columnRuleStyle = style;
+ div.style.columnRuleColor = color;
+ test(() => {
+ assert_equals(window.getComputedStyle(div).columnRule, expected);
+ }, `column-rule computed from width: ${width}, style: ${style}, color: ${color}`);
+}
+</script>
diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html
new file mode 100644
index 00000000000..7bb3e1858dd
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Gap Decoration: *rule getComputedStyle()</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/#propdef-column-rule">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<meta name="assert" content="*rule computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="reference"></div>
+<div id="target"></div>
+<style>
+ #reference {
+ column-rule-style: dotted;
+ column-rule-width: medium;
+ }
+ #target {
+ color: lime;
+ }
+</style>
+<script>
+// TODO(samomekarajr): Add `row-rule` to this test when implemented.
+const properties = ["column-rule",];
+for (let property of properties) {
+ const currentcolor = "rgb(0, 255, 0)";
+ const mediumWidth = getComputedStyle(document.getElementById('reference')).columnRuleWidth; // e.g. 3px.
+
+ // <gap-rule> = [<line-width> || <line-style> || <line-color>]
+ test_computed_value(property, "5px solid currentcolor", "5px solid " + currentcolor);
+ test_computed_value(property, "rgb(0, 0, 255) 10px solid", "10px solid rgb(0, 0, 255)");
+ test_computed_value(property, "dotted", mediumWidth + " dotted " + currentcolor);
+
+ // <gap-auto-repeat-rule> = repeat( auto , <gap-rule># )
+ test_computed_value(property, "repeat(auto, 5px solid rgb(0, 0, 255))");
+ test_computed_value(property, "repeat(auto, 5px solid rgb(255, 255, 0), 10px dotted rgb(0, 128, 0))");
+
+
+ // <gap-repeat-rule> = repeat( <integer [1,∞]> , <gap-rule># )
+ test_computed_value(property, "repeat(4, 15px dotted rgb(0, 255, 255))");
+ test_computed_value(property, "repeat(1, 15px ridge rgb(255, 0, 0), 10px dotted rgb(0, 255, 0), 15px double rgb(0, 0, 255))");
+
+
+ // <gap-rule-list> = <gap-rule-or-repeat>#
+ // <gap-rule-or-repeat> = <gap-rule> | <gap-repeat-rule>
+ test_computed_value(property, "5px double rgb(58, 58, 16), repeat(4, 5px ridge rgb(18, 18, 18))");
+ test_computed_value(property, "15px dashed rgb(0, 255, 0), repeat(3, 3px double rgb(255, 0, 0), 10px dotted rgb(0, 0, 255))");
+ test_computed_value(property, "repeat(4, 5px solid rgb(255, 0, 255)), repeat(3, 5px solid rgb(0, 0, 255), 10px dotted rgb(0, 128, 128))");
+
+ // <gap-auto-rule-list> = <gap-rule-or-repeat>#? ,
+ // <gap-auto-repeat-rule> ,
+ // <gap-rule-or-repeat>#?
+ test_computed_value(property, "repeat(auto, 5px solid rgb(255, 0, 255)), 13px dotted rgb(0, 0, 128), 10px dotted rgb(0, 128, 128), 15px double rgb(0, 0, 128)");
+ test_computed_value(property, "5px solid rgb(255, 0, 255), repeat(auto, 5px solid rgb(255, 0, 255)), 10px dotted rgb(0, 128, 128)");
+ test_computed_value(property, "10px dotted rgb(0, 128, 128), repeat(4, 20px hidden rgb(0, 128, 128), 30px ridge rgb(255, 0, 255)), repeat(auto, 5px solid rgb(255, 0, 255))");
+}
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html
new file mode 100644
index 00000000000..f7c6b45b16d
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Gap Decorations: *-rule parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/#propdef-column-rule">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<meta name="assert" content="*-rule supports the full grammar '[ <gap-rule-list> | <gap-auto-rule-list> ]'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// TODO(samomekarajr): Add `row-rule` and `rule` to this test.
+const properties = ["column-rule",];
+for (let property of properties) {
+ test_invalid_value(property, "auto");
+
+ test_invalid_value(property, "red 5px solid red");
+ test_invalid_value(property, "repeat(auto, red 5px green ridge)");
+ test_invalid_value(property, "repeat(auto, 5px solid red), 5px solid red, repeat(auto, 5px solid red)");
+ test_invalid_value(property, "repeat(0, 5px red)");
+ test_invalid_value(property, "repeat(-1, thin green red)");
+ test_invalid_value(property, "repeat(auto, )");
+ test_invalid_value(property, "repeat()");
+ test_invalid_value(property, "");
+}
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html
new file mode 100644
index 00000000000..420b6757e7f
--- /dev/null
+++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Gap Decorations: *-rule sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
+<meta name="assert" content="column-rule supports the full grammar '<gap-rule-list> | <gap-auto-rule-list>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+// TODO(samomekarajr): Add `row-rule` to this test.
+const rule_properties = {
+ 'column-rule': ['column-rule-width',
+ 'column-rule-style',
+ 'column-rule-color'],
+};
+
+for(rule_property in rule_properties) {
+ const [width, style, color] = rule_properties[rule_property];
+ // <gap-rule> = [<line-width> || <line-style> || <line-color>].
+ test_shorthand_value(rule_property, '5px solid red', {
+ [width]: '5px',
+ [style]: 'solid',
+ [color]: 'red'
+ });
+
+ test_shorthand_value(rule_property, 'double', {
+ [width]: 'medium',
+ [style]: 'double',
+ [color]: 'currentcolor'
+ });
+
+ test_shorthand_value(rule_property, 'blue 10px', {
+ [width]: '10px',
+ [style]: 'none',
+ [color]: 'blue'
+ });
+
+ // <gap-auto-repeat-rule> = repeat( auto , <gap-rule># ).
+ test_shorthand_value(rule_property, 'repeat(auto, 5px solid green)', {
+ [width]: 'repeat(auto, 5px)',
+ [style]: 'repeat(auto, solid)',
+ [color]: 'repeat(auto, green)'
+ });
+
+ test_shorthand_value(rule_property, 'repeat(auto, 5px solid yellow, 10px dotted blue)', {
+ [width]: 'repeat(auto, 5px 10px)',
+ [style]: 'repeat(auto, solid dotted)',
+ [color]: 'repeat(auto, yellow blue)'
+ });
+
+ test_shorthand_value(rule_property, 'repeat(auto, blue 6px, 5px solid red)', {
+ [width]: 'repeat(auto, 6px 5px)',
+ [style]: 'repeat(auto, none solid)',
+ [color]: 'repeat(auto, blue red)'
+ });
+
+ // <gap-repeat-rule> = repeat( <integer [1,∞]> , <gap-rule># ).
+ test_shorthand_value(rule_property, 'repeat(4, 15px dotted pink)', {
+ [width]: 'repeat(4, 15px)',
+ [style]: 'repeat(4, dotted)',
+ [color]: 'repeat(4, pink)'
+ });
+ test_shorthand_value(rule_property, 'repeat(1, 15px ridge yellow, 10px dotted blue, 15px double green)', {
+ [width]: 'repeat(1, 15px 10px 15px)',
+ [style]: 'repeat(1, ridge dotted double)',
+ [color]: 'repeat(1, yellow blue green)'
+ });
+ test_shorthand_value(rule_property, 'repeat(3, lime 16px, dashed purple, 10px dotted)', {
+ [width]: 'repeat(3, 16px medium 10px)',
+ [style]: 'repeat(3, none dashed dotted)',
+ [color]: 'repeat(3, lime purple currentcolor)'
+ });
+
+ // <gap-rule-list> = <gap-rule-or-repeat>#.
+ // <gap-rule-or-repeat> = <gap-rule> | <gap-repeat-rule>.
+ test_shorthand_value(rule_property, 'thin, dashed, hotpink', {
+ [width]: 'thin medium medium',
+ [style]: 'none dashed none',
+ [color]: 'currentcolor currentcolor hotpink'
+ });
+ test_shorthand_value(rule_property, '5px double salmon, repeat(4, 5px ridge red)', {
+ [width]: '5px repeat(4, 5px)',
+ [style]: 'double repeat(4, ridge)',
+ [color]: 'salmon repeat(4, red)'
+ });
+ test_shorthand_value(rule_property,
+ 'repeat(2, dashed gray, 10px blue dotted, 20px double), 5px solid red, repeat(4, blue 6px, 5px solid white)', {
+ [width]: 'repeat(2, medium 10px 20px) 5px repeat(4, 6px 5px)',
+ [style]: 'repeat(2, dashed dotted double) solid repeat(4, none solid)',
+ [color]: 'repeat(2, gray blue currentcolor) red repeat(4, blue white)'
+ });
+ test_shorthand_value(rule_property, 'repeat(4, thick hidden skyblue), repeat(3, 5px solid red, 10px dotted)', {
+ [width]: 'repeat(4, thick) repeat(3, 5px 10px)',
+ [style]: 'repeat(4, hidden) repeat(3, solid dotted)',
+ [color]: 'repeat(4, skyblue) repeat(3, red currentcolor)'
+ });
+
+ // <gap-auto-rule-list> = <gap-rule-or-repeat>#? ,
+ // <gap-auto-repeat-rule> ,
+ // <gap-rule-or-repeat>#?.
+ test_shorthand_value(rule_property,
+ 'repeat(auto, 10px solid red), medium dotted green, repeat(3, thick dashed blue, 15px double green)', {
+ [width]: 'repeat(auto, 10px) medium repeat(3, thick 15px)',
+ [style]: 'repeat(auto, solid) dotted repeat(3, dashed double)',
+ [color]: 'repeat(auto, red) green repeat(3, blue green)'
+ });
+
+ test_shorthand_value(rule_property, 'ridge red, repeat(auto, 5px solid green), 10px dotted blue', {
+ [width]: 'medium repeat(auto, 5px) 10px',
+ [style]: 'ridge repeat(auto, solid) dotted',
+ [color]: 'red repeat(auto, green) blue'
+ });
+
+ test_shorthand_value(rule_property,
+ '10px dotted salmon, repeat(4, thin blue, hidden 5px purple), repeat(auto, 5px solid red, teal)', {
+ [width]: '10px repeat(4, thin 5px) repeat(auto, 5px medium)',
+ [style]: 'dotted repeat(4, none hidden) repeat(auto, solid none)',
+ [color]: 'salmon repeat(4, blue purple) repeat(auto, red teal)'
+ });
+}
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html b/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html
deleted file mode 100644
index 4985b5550f2..00000000000
--- a/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html
+++ /dev/null
@@ -1,300 +0,0 @@
-<!DOCTYPE HTML>
-<html lang="en">
-
-<head>
- <meta charset="UTF-8">
- <title>CSS Test: Gap Decorations - Properties exist</title>
- <link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
- <link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
- <meta name="flags" content="ahem dom">
- <meta name="assert" content="Test checks that css properties of gap decorations exist.">
- <script src="/resources/testharness.js"></script>
- <script src="/resources/testharnessreport.js"></script>
- <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
- <style>
- #container {
- width: 800px;
- height: 600px;
- }
-
- #myDiv {
- font: 50px/1 Ahem;
- justify-content: start;
- align-content: start;
- }
- </style>
-</head>
-
-<body>
- <div id="log"></div>
- <div id="container">
- <div id="myDiv">
- <div>I T</div>
- <div>IT</div>
- <div>I</div>
- </div>
- </div>
-
- <script>
- setup({ explicit_done: true });
- document.fonts.ready.then(() => {
- var myDiv = document.getElementById('myDiv')
-
- void function (data) {
-
- myDiv.style.display = 'grid'
-
- Object.keys(data).forEach(function (prop) {
- test(function () {
- assert_true(prop in myDiv.style)
- }, prop)
-
- var syntaxTests = data[prop]
- Object.keys(syntaxTests).forEach(function (testcase) {
- test(function () {
- assert_true(prop in myDiv.style)
- myDiv.style[prop] = syntaxTests[testcase][0]
- assert_equals(myDiv.style[prop], syntaxTests[testcase][0], testcase)
- assert_equals(getComputedStyle(myDiv)[prop], syntaxTests[testcase][1], testcase)
- }, prop + '.' + testcase)
- })
- })
-
- }({
- 'gap-rule-paint-order': {
- 'row-over-column': [
- 'row-over-column',
- 'row-over-column'
- ],
- 'column-over-row': [
- 'column-over-row',
- 'column-over-row'
- ],
- },
- 'column-rule-break': {
- 'none': [
- 'none',
- 'none'
- ],
- 'spanning-item': [
- 'spanning-item',
- 'spanning-item'
- ],
- 'intersection': [
- 'intersection',
- 'intersection'
- ],
- },
- 'column-rule-color': {
- 'red': [
- 'red',
- 'rgb(255, 0, 0)'
- ],
- 'blue': [
- 'blue',
- 'rgb(0, 0, 255)'
- ],
- 'repeat(4, blue red green) repeat(auto, red)': [
- 'repeat(4, blue red green) repeat(auto, red)',
- 'repeat(4, rgb(0, 0, 255) rgb(255, 0, 0) rgb(0, 128, 0)) repeat(auto, rgb(255, 0, 0))'
- ],
- 'blue red': [
- 'blue red',
- 'rgb(0, 0, 255) rgb(255, 0, 0)'
- ],
- },
- 'column-rule-outset': {
- '10px': [
- '10px',
- '10px'
- ],
- '50%': [
- '50%',
- '50%'
- ],
- },
- 'column-rule-style': {
- 'none': [
- 'none',
- 'none'
- ],
- 'hidden': [
- 'hidden',
- 'hidden'
- ],
- 'dotted': [
- 'dotted',
- 'dotted'
- ],
- 'dashed': [
- 'dashed',
- 'dashed'
- ],
- 'solid': [
- 'solid',
- 'solid'
- ],
- 'double': [
- 'double',
- 'double'
- ],
- 'groove': [
- 'groove',
- 'groove'
- ],
- 'ridge': [
- 'ridge',
- 'ridge'
- ],
- 'inset': [
- 'inset',
- 'inset'
- ],
- 'outset': [
- 'outset',
- 'outset'
- ],
- 'dotted dashed': [
- 'dotted dashed',
- 'dotted dashed'
- ],
- 'repeat(3, dotted)': [
- 'repeat(3, dotted)',
- 'repeat(3, dotted)'
- ],
- },
- 'column-rule-width': {
- '10px': [
- '10px',
- '10px'
- ],
- 'thin': [
- 'thin',
- '1px'
- ],
- 'medium': [
- 'medium',
- '3px'
- ],
- 'thick': [
- 'thick',
- '5px'
- ],
- },
- 'row-rule-break': {
- 'none': [
- 'none',
- 'none'
- ],
- 'spanning-item': [
- 'spanning-item',
- 'spanning-item'
- ],
- 'intersection': [
- 'intersection',
- 'intersection'
- ],
- },
- 'row-rule-color': {
- 'red': [
- 'red',
- 'rgb(255, 0, 0)'
- ],
- 'blue': [
- 'blue',
- 'rgb(0, 0, 255)'
- ],
- 'repeat(4, blue red green) repeat(auto, red)': [
- 'repeat(4, blue red green) repeat(auto, red)',
- 'repeat(4, rgb(0, 0, 255) rgb(255, 0, 0) rgb(0, 128, 0)) repeat(auto, rgb(255, 0, 0))'
- ],
- 'blue red': [
- 'blue red',
- 'rgb(0, 0, 255) rgb(255, 0, 0)'
- ],
- },
- 'row-rule-outset': {
- '10px': [
- '10px',
- '10px'
- ],
- '50%': [
- '50%',
- '50%'
- ],
- },
- 'row-rule-style': {
- 'none': [
- 'none',
- 'none'
- ],
- 'hidden': [
- 'hidden',
- 'hidden'
- ],
- 'dotted': [
- 'dotted',
- 'dotted'
- ],
- 'dashed': [
- 'dashed',
- 'dashed'
- ],
- 'solid': [
- 'solid',
- 'solid'
- ],
- 'double': [
- 'double',
- 'double'
- ],
- 'groove': [
- 'groove',
- 'groove'
- ],
- 'ridge': [
- 'ridge',
- 'ridge'
- ],
- 'inset': [
- 'inset',
- 'inset'
- ],
- 'outset': [
- 'outset',
- 'outset'
- ],
- 'dotted dashed': [
- 'dotted dashed',
- 'dotted dashed'
- ],
- 'repeat(3, dotted)': [
- 'repeat(3, dotted)',
- 'repeat(3, dotted)'
- ],
- },
- 'row-rule-width': {
- '10px': [
- '10px',
- '10px'
- ],
- 'thin': [
- 'thin',
- '1px'
- ],
- 'medium': [
- 'medium',
- '3px'
- ],
- 'thick': [
- 'thick',
- '5px'
- ],
- },
- })
- done();
- });
- </script>
-</body>
-
-</html>
diff --git a/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html b/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html
index 37e41094fb2..949f955e552 100644
--- a/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html
+++ b/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html
@@ -1,10 +1,10 @@
<!DOCTYPE html>
-<meta charset="UTF-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="utf-8">
<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
<link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
<link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
<link rel="match" href="conic-gradient-001-ref.html">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<title>Tests the maximum value of color stops in conic-gradient().</title>
<style>
body {
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-001.html b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-001.html
index 0bfd7bb615f..53f14e857c7 100644
--- a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-001.html
+++ b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-001.html
@@ -1,43 +1,43 @@
<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>Gradient analogous missing components carry forward logic tests</title>
- <link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
- <link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
- <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
- <meta name="assert" content="Tests that analogous missing components logic works.">
- <link rel="match" href="gradient-analogous-missing-components-001-ref.html">
- <style>
- .test {
- margin: 50px;
- width: 200px;
- height: 50px;
- border: 1px solid black;
- }
+<meta charset="utf-8">
+<title>Gradient analogous missing components carry forward logic tests</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
+<meta name="assert" content="Tests that analogous missing components logic works.">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
+<link rel="match" href="gradient-analogous-missing-components-001-ref.html">
+<style>
+ .test {
+ margin: 50px;
+ width: 200px;
+ height: 50px;
+ border: 1px solid black;
+ }
- .test1 {
- background: linear-gradient(90deg in srgb, hsl(60deg 0 50%), yellow);
- }
- .test2 {
- background: linear-gradient(90deg in srgb, hsl(20deg 0 50%), yellow);
- }
- .test3 {
- background: linear-gradient(90deg in srgb, hsl(60deg none 50%), yellow);
- }
- .test4 {
- background: linear-gradient(90deg in srgb, hsl(none 0 50%), yellow);
- }
- .test5 {
- background: linear-gradient(90deg in srgb, hsl(none none 50%), yellow);
- }
- </style>
-</head>
-<body>
- <div class="test test1"></div>
- <div class="test test2"></div>
- <div class="test test3"></div>
- <div class="test test4"></div>
- <div class="test test5"></div>
-</body>
-</html>
+ .test1 {
+ background: linear-gradient(90deg in srgb, hsl(60deg 0 50%), yellow);
+ }
+
+ .test2 {
+ background: linear-gradient(90deg in srgb, hsl(20deg 0 50%), yellow);
+ }
+
+ .test3 {
+ background: linear-gradient(90deg in srgb, hsl(60deg none 50%), yellow);
+ }
+
+ .test4 {
+ background: linear-gradient(90deg in srgb, hsl(none 0 50%), yellow);
+ }
+
+ .test5 {
+ background: linear-gradient(90deg in srgb, hsl(none none 50%), yellow);
+ }
+</style>
+
+<div class="test test1"></div>
+<div class="test test2"></div>
+<div class="test test3"></div>
+<div class="test test4"></div>
+<div class="test test5"></div>
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html
index 96038650136..881ba723f91 100644
--- a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html
+++ b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html
@@ -1,40 +1,39 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>Gradient analogous missing components carry forward logic tests</title>
- <link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
- <link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
- <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
- <link rel="match" href="gradient-analogous-missing-components-002-ref.html">
- <meta name="assert" content="Tests that analogous missing components logic works.">
- <style>
- .test {
- margin: 10px 50px;
- width: 200px;
- height: 50px;
- border: 1px solid black;
- --stop2: rgb(0 255 0); /* lime */
- }
- .test1 {
- background: linear-gradient(to right, color(srgb none 1 none), var(--stop2));
- }
- .test2 {
- background: linear-gradient(to right in srgb, color(srgb none 1 none), var(--stop2));
- }
- .test3 {
- background: linear-gradient(to right in oklab, color(srgb none 1 none), var(--stop2));
- }
- .test4 {
- background: linear-gradient(to right in display-p3, color(srgb none 1 none), var(--stop2));
- }
- </style>
-</head>
-<body>
- <p>They should be equivalent to `background: color-mix(in srgb, color(srgb none 1 none), lime)`</p>
- <div class="test test1">This should be a lime background.</div>
- <div class="test test2">This should be a lime background.</div>
- <div class="test test3">This should be a lime background.</div>
- <div class="test test4">This should be a lime background.</div>
-</body>
-</html>
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Gradient analogous missing components carry forward logic tests</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
+<link rel="match" href="gradient-analogous-missing-components-002-ref.html">
+<meta name="assert" content="Tests that analogous missing components logic works.">
+<style>
+ .test {
+ margin: 10px 50px;
+ width: 200px;
+ height: 50px;
+ border: 1px solid black;
+ --stop2: rgb(0 255 0);
+ /* lime */
+ }
+
+ .test1 {
+ background: linear-gradient(to right, color(srgb none 1 none), var(--stop2));
+ }
+
+ .test2 {
+ background: linear-gradient(to right in srgb, color(srgb none 1 none), var(--stop2));
+ }
+
+ .test3 {
+ background: linear-gradient(to right in oklab, color(srgb none 1 none), var(--stop2));
+ }
+
+ .test4 {
+ background: linear-gradient(to right in display-p3, color(srgb none 1 none), var(--stop2));
+ }
+</style>
+<p>They should be equivalent to `background: color-mix(in srgb, color(srgb none 1 none), lime)`</p>
+<div class="test test1">This should be a lime background.</div>
+<div class="test test2">This should be a lime background.</div>
+<div class="test test3">This should be a lime background.</div>
+<div class="test test4">This should be a lime background.</div>
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html
index c4c8995c1ef..c97571f54b9 100644
--- a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html
+++ b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html
@@ -1,35 +1,33 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>Gradient analogous missing components carry forward logic tests</title>
- <link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
- <link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
- <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
- <meta name="assert" content="Tests that analogous missing components logic works.">
- <link rel="match" href="gradient-analogous-missing-components-003-ref.html">
- <style>
- .test {
- margin: 10px 50px;
- width: 200px;
- height: 50px;
- border: 1px solid black;
- --stop2: rgb(0 255 0); /* lime */
- }
- .test1 {
- background: linear-gradient(to right in hsl shorter hue, color(srgb none 1 none), var(--stop2));
- }
- .test2 {
- background: linear-gradient(to right in hsl increasing hue, color(srgb none 1 none), var(--stop2));
- }
- .test3 {
- background: linear-gradient(to right in hsl decreasing hue, color(srgb none 1 none), var(--stop2));
- }
- </style>
-</head>
-<body>
- <div class="test test1">This should be a lime background.</div>
- <div class="test test2">This should be a lime background.</div>
- <div class="test test3">This should be a lime background.</div>
-</body>
-</html>
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Gradient analogous missing components carry forward logic tests</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="author" title="一丝" href="mailto:yiorsi@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
+<meta name="assert" content="Tests that analogous missing components logic works.">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
+<link rel="match" href="gradient-analogous-missing-components-003-ref.html">
+<style>
+ .test {
+ margin: 10px 50px;
+ width: 200px;
+ height: 50px;
+ border: 1px solid black;
+ --stop2: rgb(0 255 0); /* lime */
+ }
+
+ .test1 {
+ background: linear-gradient(to right in hsl shorter hue, color(srgb none 1 none), var(--stop2));
+ }
+
+ .test2 {
+ background: linear-gradient(to right in hsl increasing hue, color(srgb none 1 none), var(--stop2));
+ }
+
+ .test3 {
+ background: linear-gradient(to right in hsl decreasing hue, color(srgb none 1 none), var(--stop2));
+ }
+</style>
+<div class="test test1">This should be a lime background.</div>
+<div class="test test2">This should be a lime background.</div>
+<div class="test test3">This should be a lime background.</div>
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html b/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html
index 14cd9d76302..449bde6e25a 100644
--- a/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html
+++ b/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html
@@ -1,40 +1,40 @@
<!DOCTYPE html>
-<html>
- <head>
- <title>Gradient interpolation with single stop that has missing components</title>
- <link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
- <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
- <meta name="assert" content="Gradients with single color stop that having missing components should resolve to zero.">
- <link rel="match" href="gradient-single-stop-none-interpolation-ref.html">
- <style>
- div {
- height: 100px;
- }
- #basic {
- /* "none" should resolve to zero when we only have one single stop. */
- background: linear-gradient(to right in srgb, color(srgb none 0.5 0.5));
- }
- #multipleNone {
- /* "none" and "none" gives zero. */
- background: linear-gradient(to right in srgb, color(srgb none 0 none));
- }
- #allNone {
- /* "none" and "none" gives zero. */
- background: linear-gradient(to right in srgb, color(srgb none none none));
- }
- #noneHue {
- background: linear-gradient(to right in oklch, oklch(0.8 0.4 none));
- }
- #noneHueLonger {
- background: linear-gradient(to right in oklch longer hue, oklch(0.5 0.3 none));
- }
- </style>
- </head>
- <body>
- <div id="basic"></div>
- <div id="multipleNone"></div>
- <div id="allNone"></div>
- <div id="noneHue"></div>
- <div id="noneHueLonger"></div>
- </body>
-</html>
+<meta charset="utf-8">
+<title>Gradient interpolation with single stop that has missing components</title>
+<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
+<meta name="assert" content="Gradients with single color stop that having missing components should resolve to zero.">
+<link rel="match" href="gradient-single-stop-none-interpolation-ref.html">
+<style>
+ div {
+ height: 100px;
+ }
+
+ #basic {
+ /* "none" should resolve to zero when we only have one single stop. */
+ background: linear-gradient(to right in srgb, color(srgb none 0.5 0.5));
+ }
+
+ #multipleNone {
+ /* "none" and "none" gives zero. */
+ background: linear-gradient(to right in srgb, color(srgb none 0 none));
+ }
+
+ #allNone {
+ /* "none" and "none" gives zero. */
+ background: linear-gradient(to right in srgb, color(srgb none none none));
+ }
+
+ #noneHue {
+ background: linear-gradient(to right in oklch, oklch(0.8 0.4 none));
+ }
+
+ #noneHueLonger {
+ background: linear-gradient(to right in oklch longer hue, oklch(0.5 0.3 none));
+ }
+</style>
+<div id="basic"></div>
+<div id="multipleNone"></div>
+<div id="allNone"></div>
+<div id="noneHue"></div>
+<div id="noneHueLonger"></div>
diff --git a/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html b/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html
index a3a1e7fb069..a150b619116 100644
--- a/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html
+++ b/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html
@@ -2,6 +2,7 @@
<title>CSS Images Test: repeating-radial-gradient with huge size crashes Chrome</title>
<link rel="help" href="https://crbug.com/1009307">
<link rel="match" href="infinite-radial-gradient-crash-ref.html">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<style>
#crash {
background-image: repeating-radial-gradient(closest-corner circle at 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%, green, green);
diff --git a/tests/wpt/tests/css/css-images/multiple-position-color-stop-radial.html b/tests/wpt/tests/css/css-images/multiple-position-color-stop-radial.html
index 4b4fd95c4ec..1cb8c5ce039 100644
--- a/tests/wpt/tests/css/css-images/multiple-position-color-stop-radial.html
+++ b/tests/wpt/tests/css/css-images/multiple-position-color-stop-radial.html
@@ -2,6 +2,7 @@
<title>Radial gradient with a two position color stop</title>
<link rel="help" href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">
<meta name="assert" content="A color stop with two positions create a hard transition">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue-green.html">
<style>
#target {
diff --git a/tests/wpt/tests/css/css-images/normalization-linear-2.html b/tests/wpt/tests/css/css-images/normalization-linear-2.html
index e3feeeb49a6..9f914cd1240 100644
--- a/tests/wpt/tests/css/css-images/normalization-linear-2.html
+++ b/tests/wpt/tests/css/css-images/normalization-linear-2.html
@@ -3,6 +3,7 @@
<title>Linear gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#linear-gradients">
<meta name="assert" content="Rendering of linear-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-linear-degenerate.html b/tests/wpt/tests/css/css-images/normalization-linear-degenerate.html
index 26647290fb4..c485f111a1f 100644
--- a/tests/wpt/tests/css/css-images/normalization-linear-degenerate.html
+++ b/tests/wpt/tests/css/css-images/normalization-linear-degenerate.html
@@ -3,6 +3,7 @@
<title>Linear gradient stop normalization</title>
<link rel="help" href="https://www.w3.org/TR/css-images-3/#repeating-gradients">
<meta name="assert" content="Rendering of repeating-linear-gradient w/ stops at the same place">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-linear.html b/tests/wpt/tests/css/css-images/normalization-linear.html
index e46645631af..8a4e74ddab3 100644
--- a/tests/wpt/tests/css/css-images/normalization-linear.html
+++ b/tests/wpt/tests/css/css-images/normalization-linear.html
@@ -3,6 +3,7 @@
<title>Linear gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#linear-gradients">
<meta name="assert" content="Rendering of linear-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-radial-2.html b/tests/wpt/tests/css/css-images/normalization-radial-2.html
index 5ea50a5e035..a7ae26865f8 100644
--- a/tests/wpt/tests/css/css-images/normalization-radial-2.html
+++ b/tests/wpt/tests/css/css-images/normalization-radial-2.html
@@ -3,6 +3,7 @@
<title>Radial gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#radial-gradients">
<meta name="assert" content="Rendering of radial-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-radial-3.html b/tests/wpt/tests/css/css-images/normalization-radial-3.html
index 927917ced60..c6fcfa8888c 100644
--- a/tests/wpt/tests/css/css-images/normalization-radial-3.html
+++ b/tests/wpt/tests/css/css-images/normalization-radial-3.html
@@ -3,6 +3,7 @@
<title>Radial gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#radial-gradients">
<meta name="assert" content="Rendering of radial-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-radial-4.html b/tests/wpt/tests/css/css-images/normalization-radial-4.html
index e9d948f062e..49a6dbf6a96 100644
--- a/tests/wpt/tests/css/css-images/normalization-radial-4.html
+++ b/tests/wpt/tests/css/css-images/normalization-radial-4.html
@@ -3,6 +3,7 @@
<title>Radial gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#repeating-gradients">
<meta name="assert" content="Rendering of repeating-radial-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-radial-degenerate.html b/tests/wpt/tests/css/css-images/normalization-radial-degenerate.html
index 4fff3ac909a..04f04c40bb5 100644
--- a/tests/wpt/tests/css/css-images/normalization-radial-degenerate.html
+++ b/tests/wpt/tests/css/css-images/normalization-radial-degenerate.html
@@ -3,6 +3,7 @@
<title>Radial gradient stop normalization</title>
<link rel="help" href="https://www.w3.org/TR/css-images-3/#repeating-gradients">
<meta name="assert" content="Rendering of repeating-radial-gradient w/ stops at the same place">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/normalization-radial.html b/tests/wpt/tests/css/css-images/normalization-radial.html
index 6a510aa52f3..e8bab92afb4 100644
--- a/tests/wpt/tests/css/css-images/normalization-radial.html
+++ b/tests/wpt/tests/css/css-images/normalization-radial.html
@@ -3,6 +3,7 @@
<title>Radial gradient stop normalization</title>
<link rel="help" href="https://drafts.csswg.org/css-images-3/#radial-gradients">
<meta name="assert" content="Rendering of radial-gradient with normalized color stops">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
<link rel="match" href="reference/100x100-blue.html">
<style>
#gradient {
diff --git a/tests/wpt/tests/css/css-images/tiled-gradients.html b/tests/wpt/tests/css/css-images/tiled-gradients.html
index fdafa1fe99f..46cc8426481 100644
--- a/tests/wpt/tests/css/css-images/tiled-gradients.html
+++ b/tests/wpt/tests/css/css-images/tiled-gradients.html
@@ -1,23 +1,17 @@
<!doctype html>
-<html>
- <head>
- <meta charset="utf-8">
- <title>Eight Red Triangles on White Ground (with gradients)</title>
- <link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#propdef-background-size">
- <meta name="assert" content="Gradients are correctly repeated.">
- <meta name="fuzzy" content="0-255; 0-564">
- <link rel="match" href="tiled-gradients-ref.html">
- <style>
- #gradient {
- width: 400px;
- height: 200px;
- background-size: 25% 50%;
- background-image: linear-gradient(to bottom left, red 50%, transparent 50%);
- }
- </style>
- </head>
- <body>
- <div id="gradient"></div>
- </body>
-</html>
+<meta charset="utf-8">
+<title>Eight Red Triangles on White Ground (with gradients)</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#propdef-background-size">
+<meta name="assert" content="Gradients are correctly repeated.">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-40000">
+<link rel="match" href="tiled-gradients-ref.html">
+<style>
+ #gradient {
+ width: 400px;
+ height: 200px;
+ background-size: 25% 50%;
+ background-image: linear-gradient(to bottom left, red 50%, transparent 50%);
+ }
+</style>
+<div id="gradient"></div> \ No newline at end of file
diff --git a/tests/wpt/tests/css/css-mixins/dashed-function-cycles.html b/tests/wpt/tests/css/css-mixins/dashed-function-cycles.html
index 15305be2b28..e711c9ed367 100644
--- a/tests/wpt/tests/css/css-mixins/dashed-function-cycles.html
+++ b/tests/wpt/tests/css/css-mixins/dashed-function-cycles.html
@@ -40,12 +40,12 @@
</style>
</template>
-<template data-name="Local with self-cycle in fallback">
+<template data-name="Local with self-cycle in unused fallback">
<style>
@function --f() {
- --y: FAIL;
+ --y: PASS;
--x: var(--y, var(--x));
- result: var(--x, PASS);
+ result: var(--x, FAIL);
}
#target {
--actual: --f();
diff --git a/tests/wpt/tests/css/css-mixins/local-attr-substitution.html b/tests/wpt/tests/css/css-mixins/local-attr-substitution.html
index 575372a9669..de2a20fa470 100644
--- a/tests/wpt/tests/css/css-mixins/local-attr-substitution.html
+++ b/tests/wpt/tests/css/css-mixins/local-attr-substitution.html
@@ -82,13 +82,13 @@
</style>
</template>
-<template data-name="attr() cycle through fallback in local">
+<template data-name="attr() cycle through unused fallback in local">
<style>
@function --f() {
- --valid: valid;
+ --valid: PASS;
--x: var(--valid, attr(data-x type(*)));
- --y: attr(data-x type(*), PASS);
- result: var(--y, PASS);
+ --y: attr(data-x type(*), FAIL);
+ result: var(--y, FAIL);
}
#target {
--x: FAIL1;
diff --git a/tests/wpt/tests/css/css-multicol/crashtests/float-cannot-be-spanner.html b/tests/wpt/tests/css/css-multicol/crashtests/float-cannot-be-spanner.html
new file mode 100644
index 00000000000..f366e79ae8d
--- /dev/null
+++ b/tests/wpt/tests/css/css-multicol/crashtests/float-cannot-be-spanner.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://issues.chromium.org/issues/417256483">
+<div style="columns:2;">
+ <div id="e59" style="float:left; width:100px; column-span:all;"></div>
+ m
+</div>
+<script>
+ document.body.offsetTop;
+ e59.style.width = "101px";
+</script>
diff --git a/tests/wpt/tests/css/css-multicol/multicol-fill-balance-030.html b/tests/wpt/tests/css/css-multicol/multicol-fill-balance-030.html
new file mode 100644
index 00000000000..9fc1f4e859a
--- /dev/null
+++ b/tests/wpt/tests/css/css-multicol/multicol-fill-balance-030.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Nested balanced multicol with forced break inside overflowed container</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://issues.chromium.org/issues/396176635">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; gap:0; column-fill:auto; width:80px; border-right:20px solid green; height:100px; background:red;">
+ <div style="columns:2; gap:0;">
+ <div style="height:40px; background:green;"></div>
+ <div style="height:10px; background:red;">
+ <div style="margin-left:auto; width:50%; height:180px; background:green;">
+ <div style="height:10px; width:100%; margin-left:-100%; background:green;"></div>
+ </div>
+ <div style="break-before:column; height:10px; background:red;"></div>
+ </div>
+ <div style="width:50%; height:250px;">
+ <div style="height:170px; background:green;"></div>
+ <div style="width:200%; height:80px; background:green;"></div>
+ </div>
+ <div style="height:100px; background:green;"></div>
+ </div>
+</div>
diff --git a/tests/wpt/tests/css/css-multicol/offsetProps-001.html b/tests/wpt/tests/css/css-multicol/offsetProps-001.html
new file mode 100644
index 00000000000..a592c5a88d7
--- /dev/null
+++ b/tests/wpt/tests/css/css-multicol/offsetProps-001.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>offsetWidth and offsetHeight of fragmented inline</title>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div style="columns:3; column-fill:auto; column-gap:10px; width:320px; height:50px; font:8px/16px Ahem; orphans:1; widows:1; background:lightgray;">
+ p<br>
+ ppp
+ <span id="outer" style="background:cyan;">
+ <span id="middle" style="background:yellow;">
+ <span id="inner1" style="color:blue;">
+ pppp pppp
+ </span>
+ <span id="inner2" style="color:green;">
+ pppp pppp
+ </span>
+ </span>
+ pppp pppp pppp pppp pppp pppp pppp pppp
+ </span>
+ </span>
+</div>
+<script>
+ test(()=> {
+ assert_equals(outer.offsetWidth, 292);
+ assert_equals(outer.offsetHeight, 40);
+ }, "outer");
+ test(()=> {
+ assert_equals(middle.offsetWidth, 150);
+ assert_equals(middle.offsetHeight, 40);
+ }, "middle");
+ test(()=> {
+ assert_equals(inner1.offsetWidth, 64);
+ assert_equals(inner1.offsetHeight, 24);
+ }, "inner1");
+ test(()=> {
+ assert_equals(inner2.offsetWidth, 110);
+ assert_equals(inner2.offsetHeight, 40);
+ }, "inner2");
+</script>
diff --git a/tests/wpt/tests/css/css-properties-values-api/registered-property-computation-color-005.html b/tests/wpt/tests/css/css-properties-values-api/registered-property-computation-color-005.html
new file mode 100644
index 00000000000..9660c934a85
--- /dev/null
+++ b/tests/wpt/tests/css/css-properties-values-api/registered-property-computation-color-005.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-properties-values-api/#calculation-of-computed-values" />
+<link rel="match" href="registered-property-computation-color-001-ref.html">
+<style>
+@property --x {
+ inherits: true;
+ initial-value: black;
+ syntax: "<color>";
+}
+div {
+ --x: color(srgb 0 calc(0.5 * sibling-index()) 0);
+ background-color: var(--x);
+ width: 100px;
+ height: 100px;
+}
+</style>
+<div></div>
diff --git a/tests/wpt/tests/css/css-properties-values-api/resolved-color-value.html b/tests/wpt/tests/css/css-properties-values-api/resolved-color-value.html
new file mode 100644
index 00000000000..2515726fd70
--- /dev/null
+++ b/tests/wpt/tests/css/css-properties-values-api/resolved-color-value.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>CSS Properties and Values API Test: resolved registered &lt;color&gt; values</title>
+<link rel="help" href="https://drafts.csswg.org/css-properties-values-api/#calculation-of-computed-values">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @property --color {
+ inherits: false;
+ initial-value: black;
+ syntax: "<color>";
+ }
+ #target {
+ --color: color(srgb 0 sibling-index() 0);
+ }
+</style>
+<div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--color"), "color(srgb 0 1 0)");
+ }, "Resolved <color> value with sibling-index()");
+</script>
diff --git a/tests/wpt/tests/css/css-scroll-snap/resnap-on-snap-alignment-change.html b/tests/wpt/tests/css/css-scroll-snap/resnap-on-snap-alignment-change.html
index e4648b1d798..760d9afbe2e 100644
--- a/tests/wpt/tests/css/css-scroll-snap/resnap-on-snap-alignment-change.html
+++ b/tests/wpt/tests/css/css-scroll-snap/resnap-on-snap-alignment-change.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
+<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<title>
Resnap when the current snap position is no longer a valid snap target.
</title>
diff --git a/tests/wpt/tests/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html b/tests/wpt/tests/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
index aea8e120c15..8b3c168af8a 100644
--- a/tests/wpt/tests/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
+++ b/tests/wpt/tests/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
@@ -57,11 +57,12 @@
const expected_scroll_top = document.scrollingElement.scrollHeight -
document.scrollingElement.clientHeight;
- const scroll_start_target_top = top_box.getBoundingClientRect().height;
+ const scroll_start_target_top = Math.round(top_box.getBoundingClientRect().height);
- if (document.scrollingElement.scrollTop == scroll_start_target_top) {
+ const actual_scroll_top = Math.round(document.scrollingElement.scrollTop);
+ if (actual_scroll_top == scroll_start_target_top) {
scroll_position = "AT_SCROLL_START_TARGET";
- } else if (document.scrollingElement.scrollTop == expected_scroll_top) {
+ } else if (actual_scroll_top == expected_scroll_top) {
scroll_position = "AT_TEXT_FRAGMENT";
}
diff --git a/tests/wpt/tests/css/css-scroll-snap/smooth-anchor-scroll-in-snap-container.html b/tests/wpt/tests/css/css-scroll-snap/smooth-anchor-scroll-in-snap-container.html
index c01420b2ee4..4892ae3efb5 100644
--- a/tests/wpt/tests/css/css-scroll-snap/smooth-anchor-scroll-in-snap-container.html
+++ b/tests/wpt/tests/css/css-scroll-snap/smooth-anchor-scroll-in-snap-container.html
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<title>Smooth anchor scroll in snap container works</title>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/"/>
<script src="/resources/testharness.js"></script>
diff --git a/tests/wpt/tests/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align-nested.tentative.html b/tests/wpt/tests/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align-nested.tentative.html
index ddea5705517..d945d00ca18 100644
--- a/tests/wpt/tests/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align-nested.tentative.html
+++ b/tests/wpt/tests/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-align-nested.tentative.html
@@ -104,16 +104,16 @@ test(t => {
// scroll (and snap) to top left of other target.
scroller.scrollTo(other_target.offsetTop,
other_target.offsetLeft);
- assert_equals(scroller.scrollTop, other_target.offsetTop,);
+ assert_equals(scroller.scrollTop, other_target.offsetTop);
assert_equals(scroller.scrollLeft, other_target.offsetLeft);
other_target.style.setProperty("scroll-snap-align", "end");
// should be scrolled so as to align scroller's bottom-right with
// other_target's bottom-right.
- assert_equals(scroller.scrollTop,
- other_target.offsetTop + other_target.offsetHeight - scroller.clientHeight);
- assert_equals(scroller.scrollLeft,
- other_target.offsetLeft + other_target.offsetWidth - scroller.clientWidth);
+ assert_approx_equals(scroller.scrollTop,
+ other_target.offsetTop + other_target.offsetHeight - scroller.clientHeight, 1.0);
+ assert_approx_equals(scroller.scrollLeft,
+ other_target.offsetLeft + other_target.offsetWidth - scroller.clientWidth, 1.0);
}, "Changing the current (non-covering) target's snap alignment should make " +
"the scroller snap according to the new alignment.");
</script>
diff --git a/tests/wpt/tests/css/css-scroll-snap/snapevent-constructor.html b/tests/wpt/tests/css/css-scroll-snap/snapevent-constructor.html
new file mode 100644
index 00000000000..a5257d77e3d
--- /dev/null
+++ b/tests/wpt/tests/css/css-scroll-snap/snapevent-constructor.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel=help href="https://drafts.csswg.org/css-scroll-snap-2/#snapevent-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script>
+ test(function() {
+ assert_throws_js(TypeError, function() {
+ new SnapEvent();
+ }, 'First argument (type) is required, so was expecting a TypeError.');
+ }, 'Missing type argument');
+
+ test(function() {
+ let event = new SnapEvent("");
+ assert_true(event instanceof window.SnapEvent);
+ }, "the event is an instance of SnapEvent");
+
+ test(function() {
+ let event = new SnapEvent("customsnapevent");
+ assert_equals(event.type, "customsnapevent",
+ "event constructor type is honored");
+ assert_equals(event.snapTargetBlock, null, "null snapTrgetBlock");
+ assert_equals(event.snapTargetInline, null, "null snapTargetInline");
+ }, "default init dict");
+
+ test(function() {
+ const div_element = document.createElement("div");
+ let event = new SnapEvent("scrollsnapchange", {
+ snapTargetBlock: document,
+ snapTargetInline: div_element
+ });
+ assert_equals(event.type, "scrollsnapchange");
+ assert_equals(event.snapTargetBlock, document);
+ assert_equals(event.snapTargetInline, div_element);
+ }, "event constructor type is honored");
+ </script>
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-text-decor/crashtests/text-decoration-first-line-layer-crash.html b/tests/wpt/tests/css/css-text-decor/crashtests/text-decoration-first-line-layer-crash.html
new file mode 100644
index 00000000000..5f5b7e7b9e4
--- /dev/null
+++ b/tests/wpt/tests/css/css-text-decor/crashtests/text-decoration-first-line-layer-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<link rel="help" href="http://crbug.com/406109047">
+<style type="text/css">
+.c2 {
+ float: right;
+ text-decoration: overline;
+}
+
+.c2::first-letter {
+ vertical-align: super;
+ opacity: 0.1;
+}
+
+.c2::first-line {
+ text-decoration: overline;
+}
+</style>
+<script>
+let element = document.createElement('q');
+element.setAttribute('class', 'c2');
+document.documentElement.appendChild(element);
+let text_node = document.createTextNode('appxgrxebpwykansiejjshzsznwgqyelwkrlpjsmtdhhfnywteevgcricqxp');
+window.requestAnimationFrame(function() {
+ element.appendChild(text_node);
+});
+</script>
diff --git a/tests/wpt/tests/css/css-text/bidi/empty-span-001-ref.html b/tests/wpt/tests/css/css-text/bidi/empty-span-001-ref.html
new file mode 100644
index 00000000000..ce987d65bf4
--- /dev/null
+++ b/tests/wpt/tests/css/css-text/bidi/empty-span-001-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text: bidi reordering reference</title>
+
+<style>
+span { unicode-bidi: bidi-override; }
+</style>
+
+<p>All the following lines should match:</p>
+
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
+<span>;א56;234;1</span><br>
diff --git a/tests/wpt/tests/css/css-text/bidi/empty-span-001.html b/tests/wpt/tests/css/css-text/bidi/empty-span-001.html
new file mode 100644
index 00000000000..4709f34abd5
--- /dev/null
+++ b/tests/wpt/tests/css/css-text/bidi/empty-span-001.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text: bidi reordering testcase</title>
+
+<link rel="author" href="mailto:jkew@mozilla.com">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1966313">
+<link rel="match" href="empty-span-001-ref.html">
+<meta name="assert" content="empty spans should not disrupt bidi reordering">
+
+<p>All the following lines should match:</p>
+
+<span dir="auto">1;234;56א;</span><br>
+<span dir="auto"><span></span>1;234;56א;</span><br>
+<span dir="auto">1<span></span>;234;56א;</span><br>
+<span dir="auto">1;<span></span>234;56א;</span><br>
+<span dir="auto">1;2<span></span>34;56א;</span><br>
+<span dir="auto">1;23<span></span>4;56א;</span><br>
+<span dir="auto">1;234<span></span>;56א;</span><br>
+<span dir="auto">1;234;<span></span>56א;</span><br>
+<span dir="auto">1;234;5<span></span>6א;</span><br>
+<span dir="auto">1;234;56<span></span>א;</span><br>
+<span dir="auto">1;234;56א<span></span>;</span><br>
+<span dir="auto">1;234;56א;<span></span></span><br>
diff --git a/tests/wpt/tests/css/css-ui/WEB_FEATURES.yml b/tests/wpt/tests/css/css-ui/WEB_FEATURES.yml
index a10f7029791..e699a40acdd 100644
--- a/tests/wpt/tests/css/css-ui/WEB_FEATURES.yml
+++ b/tests/wpt/tests/css/css-ui/WEB_FEATURES.yml
@@ -8,3 +8,6 @@ features:
- name: outline
files:
- outline-*
+- name: user-select
+ files:
+ - user-select-*
diff --git a/tests/wpt/tests/css/css-ui/parsing/WEB_FEATURES.yml b/tests/wpt/tests/css/css-ui/parsing/WEB_FEATURES.yml
index b4ae339c2f3..3be770b3a51 100644
--- a/tests/wpt/tests/css/css-ui/parsing/WEB_FEATURES.yml
+++ b/tests/wpt/tests/css/css-ui/parsing/WEB_FEATURES.yml
@@ -2,3 +2,6 @@ features:
- name: field-sizing
files:
- field-sizing-*
+- name: user-select
+ files:
+ - user-select-*
diff --git a/tests/wpt/tests/css/css-values/attr-cycle.html b/tests/wpt/tests/css/css-values/attr-cycle.html
index 1db82c4cad2..c876f77a835 100644
--- a/tests/wpt/tests/css/css-values/attr-cycle.html
+++ b/tests/wpt/tests/css/css-values/attr-cycle.html
@@ -96,18 +96,21 @@
attrElem.style.setProperty('--x', null);
attrElem.removeAttribute('data-bar');
- /* Cycle in fallback */
- test_attr_cycle('--y', 'attr(data-foo type(*), var(--y))', '3');
- test_attr_cycle('--y', 'attr(data-foo type(*), attr(data-foo))', '3');
+ /* Cycle in unused fallbacks */
+ test_attr_no_cycle('--y', 'attr(data-foo type(*), var(--y))', '3', '3');
+ test_attr_no_cycle('--y', 'attr(data-foo type(*), attr(data-foo))', '3', '3');
attrElem.style.setProperty('--x', 'var(--y)');
- test_attr_cycle('--y', 'attr(data-foo type(*), var(--x))', '3');
+ test_attr_no_cycle('--y', 'attr(data-foo type(*), var(--x))', '3', '3');
attrElem.style.setProperty('--x', null);
attrElem.setAttribute('data-bar', 'attr(data-foo type(*))');
- test_attr_cycle('--y', 'attr(data-foo type(*), attr(data-bar type(*)))', '3');
+ test_attr_no_cycle('--y', 'attr(data-foo type(*), attr(data-bar type(*)))', '3', '3');
attrElem.removeAttribute('data-bar');
+ /* Cycle in fallback */
+ test_attr_cycle('--y', 'attr(data-unknown type(*), var(--y))', '3');
+
/* No cycle, use raw CSS string without substitution */
attrElem.setAttribute('data-bar', 'var(--y)');
test_attr_no_cycle('--y', 'attr(data-foo type(<string>))', 'attr(data-bar type(<string>))', '');
diff --git a/tests/wpt/tests/css/css-values/if-cycle.html b/tests/wpt/tests/css/css-values/if-cycle.html
index 74d56dc9ed7..ac3ff7df4ee 100644
--- a/tests/wpt/tests/css/css-values/if-cycle.html
+++ b/tests/wpt/tests/css/css-values/if-cycle.html
@@ -182,7 +182,7 @@
test_if(`if(style(--x: attr(data-foo, var(--y))): true_value;
else: false_value)`,
[['--x', '"30px"'], ['--y', 'var(--y)']],
- 'false_value');
+ 'true_value');
// self cycle in unused condition
test_if(`if(style(--x: 0): value1; style(--prop): value2)`,
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-function-descriptors.tentative.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-function-descriptors.tentative.html
index 76d2ff8ee4d..8f597aa92e4 100644
--- a/tests/wpt/tests/css/css-values/tree-counting/sibling-function-descriptors.tentative.html
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-function-descriptors.tentative.html
@@ -83,6 +83,16 @@
symbols: linear-gradient(red calc(20px * sibling-count()), pink);
}
</style>
+<style id="font_features_sheet">
+ @font-feature-values foo {
+ @swash { pretty: 1; }
+ @swash { pretty: calc(max(sibling-index(), 2)); }
+ }
+ @font-feature-values bar {
+ @swash { pretty: 1; }
+ @swash { pretty: calc(max(sibling-count(), 2)); }
+ }
+</style>
<script>
const page_rules = page_sheet.sheet.cssRules;
@@ -140,4 +150,17 @@
assert_equals(counter_style_rules[1].symbols, "--pass");
}, "sibling-count() should not be allowed in @counter-style descriptors");
+
+ const font_features_rules = font_features_sheet.sheet.cssRules;
+
+ test(() => {
+ const swash = font_features_rules[0].swash;
+ assert_equals(swash.get("pretty")[0], 1);
+ }, "sibling-index() should not be allowed in @font-feature-values descriptors");
+
+ test(() => {
+ const swash = font_features_rules[1].swash;
+ assert_equals(swash.get("pretty")[0], 1);
+ }, "sibling-count() should not be allowed in @font-feature-values descriptors");
+
</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html
new file mode 100644
index 00000000000..d98a72a2fb2
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-variation-settings-dynamic.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing font-variation-settings during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @keyframes --anim {
+ from {
+ font-variation-settings: "wght" sibling-index();
+ }
+ to {
+ font-variation-settings: "wght" 10;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).fontVariationSettings, '"wght" 3');
+ }, "Initially, the sibling-index() is 3 for #target");
+
+ test(() => {
+ rm.remove();
+ assert_equals(getComputedStyle(target).fontVariationSettings, '"wght" 2');
+ }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html
new file mode 100644
index 00000000000..99fe0b3b2e1
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-font-weight-dynamic.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing font-weight during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @keyframes --anim {
+ from {
+ font-weight: calc(100 * sibling-index());
+ }
+ to {
+ font-weight: 600;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).fontWeight, "300");
+ }, "Initially, the sibling-index() is 3 for #target");
+
+ test(() => {
+ rm.remove();
+ assert_equals(getComputedStyle(target).fontWeight, "200");
+ }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html
new file mode 100644
index 00000000000..58d1e7990d3
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing percentage during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @keyframes --anim {
+ from {
+ text-size-adjust: calc(50% * sibling-index());
+ }
+ to {
+ text-size-adjust: 90%;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).textSizeAdjust, "150%");
+ }, "Initially, the sibling-index() is 3 for #target");
+
+ test(() => {
+ rm.remove();
+ assert_equals(getComputedStyle(target).textSizeAdjust, "100%");
+ }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html
new file mode 100644
index 00000000000..77af5434a1c
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-registered-properties-dynamic.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing registered custom property values during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @property --time { syntax: "<time>"; initial-value: 0s; inherits: false; }
+ @property --angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
+ @property --resolution { syntax: "<resolution>"; initial-value: 1dppx; inherits: false; }
+ @property --percentage { syntax: "<percentage>"; initial-value: 0%; inherits: false; }
+ @property --number { syntax: "<number>"; initial-value: 0; inherits: false; }
+ @property --integer { syntax: "<integer>"; initial-value: 0; inherits: false; }
+ @property --length { syntax: "<length>"; initial-value: 0px; inherits: false; }
+ @property --length-percentage { syntax: "<length-percentage>"; initial-value: 0px; inherits: false; }
+ @property --color { syntax: "<color>"; initial-value: black; inherits: false; }
+
+ @keyframes --anim {
+ from {
+ --time: calc(2s * sibling-index());
+ --angle: calc(30deg * sibling-index());
+ --resolution: calc(1dppx * sibling-index());
+ --percentage: calc(50% * sibling-index());
+ --number: sibling-index();
+ --integer: sibling-index();
+ --length: calc(sibling-index() * 7px);
+ --length-percentage: calc((sibling-index() * 8px) + (sibling-count() * 5%));
+ --color: color(srgb 0 calc(0.2 * sibling-index()) 0);
+ }
+ to {
+ --time: 13s;
+ --angle: 13deg;
+ --resolution: 1dppx;
+ --percentage: 13%;
+ --number: 13;
+ --integer: 13;
+ --length: 13px;
+ --length-percentage: calc(13px + 7%);
+ --color: red;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--time"), "6s");
+ }, "Initially, the sibling-index() is 3 for --time");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--angle"), "90deg");
+ }, "Initially, the sibling-index() is 3 for --angle");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--resolution"), "3dppx");
+ }, "Initially, the sibling-index() is 3 for --resolution");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--percentage"), "150%");
+ }, "Initially, the sibling-index() is 3 for --percentage");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--number"), "3");
+ }, "Initially, the sibling-index() is 3 for --number");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--integer"), "3");
+ }, "Initially, the sibling-index() is 3 for --integer");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--length"), "21px");
+ }, "Initially, the sibling-index() is 3 for --length");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--length-percentage"), "calc(15% + 24px)");
+ }, "Initially, the sibling-index() is 3 for --length-percentage");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--color"), "color(srgb 0 0.6 0)");
+ }, "Initially, the sibling-index() is 3 for --color");
+
+ rm.remove();
+
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--time"), "4s");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --time");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--angle"), "60deg");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --angle");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--resolution"), "2dppx");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --resolution");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--percentage"), "100%");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --percentage");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--number"), "2");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --number");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--integer"), "2");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --integer");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--length"), "14px");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --length");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--length-percentage"), "calc(10% + 16px)");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --length-percentage");
+ test(() => {
+ assert_equals(getComputedStyle(target).getPropertyValue("--color"), "color(srgb 0 0.4 0)");
+ }, "Removing a preceding sibling of #target reduces the sibling-index() for --color");
+
+</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html
new file mode 100644
index 00000000000..67df9c01d19
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-rotate-dynamic.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing rotate during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @keyframes --anim {
+ from {
+ rotate: x calc(10deg * sibling-index());
+ }
+ to {
+ rotate: x 90deg;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).rotate, "x 30deg");
+ }, "Initially, the sibling-index() is 3 for #target");
+
+ test(() => {
+ rm.remove();
+ assert_equals(getComputedStyle(target).rotate, "x 20deg");
+ }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html
new file mode 100644
index 00000000000..8b3fe6f7532
--- /dev/null
+++ b/tests/wpt/tests/css/css-values/tree-counting/sibling-index-keyframe-scale-dynamic.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Values and Units Test: sibling-index() changing scale during @keyframes animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @keyframes --anim {
+ from {
+ scale: 0.7 calc(0.2 * sibling-index());
+ }
+ to {
+ scale: 0.3 2;
+ }
+ }
+ #target {
+ animation: --anim 1000s step-end;
+ }
+</style>
+<div>
+ <div id="rm"></div>
+ <div></div>
+ <div id="target"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(target).scale, "0.7 0.6");
+ }, "Initially, the sibling-index() is 3 for #target");
+
+ test(() => {
+ rm.remove();
+ assert_equals(getComputedStyle(target).scale, "0.7 0.4");
+ }, "Removing a preceding sibling of #target reduces the sibling-index()");
+
+</script>
diff --git a/tests/wpt/tests/css/css-variables/variable-cycles.html b/tests/wpt/tests/css/css-variables/variable-cycles.html
index 950cffb2ab5..06b270d3b66 100644
--- a/tests/wpt/tests/css/css-variables/variable-cycles.html
+++ b/tests/wpt/tests/css/css-variables/variable-cycles.html
@@ -377,6 +377,9 @@
'Cycle with deeper secondary cycle');
+ // If we cared about cycles in unused fallbacks,
+ // then --a/--b/--c would be in a cycle in this case:
+ //
// ┌───┐
// │ x │
// └───┘
@@ -404,6 +407,9 @@
// │ ┌───┐ │
// └▶ │ y │ ◀┘
// └───┘
+ //
+ // However, as of https://github.com/w3c/csswg-drafts/issues/11500,
+ // we no longer care about such cycles.
test_cycles(
[
'--x:var(--a, valid)',
@@ -412,8 +418,8 @@
'--c:var(--y, var(--a, cycle))',
'--y:valid'
],
- ['--a', '--b', '--c'],
- ['--x', '--y'],
- 'Cycle via fallback');
+ [], // Nothing is invalid.
+ ['--a', '--b', '--c', '--x', '--y'],
+ 'Cycle in unused fallback');
</script>
diff --git a/tests/wpt/tests/css/css-variables/variable-substitution-variable-declaration.html b/tests/wpt/tests/css/css-variables/variable-substitution-variable-declaration.html
index 5239a05c304..28ca7ca4810 100644
--- a/tests/wpt/tests/css/css-variables/variable-substitution-variable-declaration.html
+++ b/tests/wpt/tests/css/css-variables/variable-substitution-variable-declaration.html
@@ -125,18 +125,18 @@
{ element: "target6", propertyName: "--varA", expectedPropertyValue: "" },
{ element: "target6", propertyName: "--varB", expectedPropertyValue: "" },
- { element: "target6", propertyName: "--varC", expectedPropertyValue: "" },
+ { element: "target6", propertyName: "--varC", expectedPropertyValue: "13px" },
{ element: "target7", propertyName: "--varA", expectedPropertyValue: "" },
{ element: "target7", propertyName: "--varB", expectedPropertyValue: "" },
- { element: "target7", propertyName: "--varC", expectedPropertyValue: "" },
+ { element: "target7", propertyName: "--varC", expectedPropertyValue: "13px" },
{ element: "target8", propertyName: "--varA", expectedPropertyValue: "" },
{ element: "target8", propertyName: "--varB", expectedPropertyValue: "7px" },
{ element: "target9", propertyName: "--varA", expectedPropertyValue: "good" },
- { element: "target9", propertyName: "--varB", expectedPropertyValue: "" },
- { element: "target9", propertyName: "--varC", expectedPropertyValue: "" },
+ { element: "target9", propertyName: "--varB", expectedPropertyValue: "very good" },
+ { element: "target9", propertyName: "--varC", expectedPropertyValue: "very good" },
{ element: "target10", propertyName: "--varA", expectedPropertyValue: "" },
{ element: "target10", propertyName: "--varB", expectedPropertyValue: "" },
diff --git a/tests/wpt/tests/css/css-view-transitions/content-with-transform-ref.html b/tests/wpt/tests/css/css-view-transitions/content-with-transform-ref.html
index 8c2b65e63e7..10166b16a8c 100644
--- a/tests/wpt/tests/css/css-view-transitions/content-with-transform-ref.html
+++ b/tests/wpt/tests/css/css-view-transitions/content-with-transform-ref.html
@@ -7,7 +7,7 @@
contain: paint;
width: 100px;
height: 100px;
- transform: scale(2.0, 3.0);
+ transform: scale3d(2.0, 3.0, 1.0);
}
.embedded {
diff --git a/tests/wpt/tests/css/css-view-transitions/dynamic-stylesheet-animations-timing-function.html b/tests/wpt/tests/css/css-view-transitions/dynamic-stylesheet-animations-timing-function.html
new file mode 100644
index 00000000000..4e43cc0375b
--- /dev/null
+++ b/tests/wpt/tests/css/css-view-transitions/dynamic-stylesheet-animations-timing-function.html
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: Dynamic stylesheet sets correct animations with proper timing function</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions/#setup-transition-pseudo-elements-algorithm">
+<link rel="help" href="https://drafts.csswg.org/css-animations-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/web-animations/testcommon.js"></script>
+
+<style>
+body { margin: 0; }
+:root { view-transition-name: none; }
+html::view-transition-group(*),
+html::view-transition-old(*),
+html::view-transition-new(*) {
+ animation-duration: 10s;
+ animation-delay: -5s;
+ animation-play-state: paused;
+}
+#target { view-transition-name: target; }
+.init {
+ width: 100px;
+ height: 100px;
+}
+.large {
+ width: 300px;
+ height: 300px;
+}
+.left {
+ margin-left: 100px;
+}
+.right {
+ margin-left: 300px;
+}
+/* For generating the transform with ease, as reference */
+@keyframes anim {
+ from { transform: translate(100px); }
+ to { transform: translate(300px); }
+}
+</style>
+<div id="target"></div>
+
+<script>
+promise_test(async t => {
+ const ref = createDiv(t);
+ ref.style.animation = "anim 10s -5s paused ease";
+ target.classList.add("init", "left");
+
+ const vt = document.startViewTransition(() => {
+ target.classList.remove("left");
+ target.classList.add("right");
+ });
+ await vt.ready;
+
+ assert_equals(
+ getComputedStyle(document.documentElement,
+ "::view-transition-group(target)").animationTimingFunction,
+ "ease",
+ "The default timing function"
+ );
+
+ assert_equals(
+ getComputedStyle(document.documentElement,
+ "::view-transition-group(target)").transform,
+ getComputedStyle(ref).transform,
+ "transform with ease at 50%"
+ );
+
+ await vt.skipTransition();
+ target.className = "";
+}, "The transform property with ease on ::view-transition-group()");
+
+promise_test(async t => {
+ document.styleSheets[0].insertRule(
+ "::view-transition-group(target) { animation-timing-function: linear; }",
+ document.styleSheets[0].cssRules.length
+ );
+ t.add_cleanup(() => {
+ document.styleSheets[0].deleteRule(
+ document.styleSheets[0].cssRules.length - 1
+ );
+ });
+ target.classList.add("init");
+
+ let vt = document.startViewTransition(() => {
+ target.classList.remove("init");
+ target.classList.add("large");
+ });
+ await vt.ready;
+
+ assert_equals(
+ getComputedStyle(document.documentElement,
+ "::view-transition-group(target)").width,
+ "200px",
+ "width at 50%"
+ );
+ assert_equals(
+ getComputedStyle(document.documentElement,
+ "::view-transition-group(target)").height,
+ "200px",
+ "height at 50%"
+ );
+
+ await vt.skipTransition();
+ target.className = "";
+}, "The sizing properties with linear on ::view-transition-group()");
+
+promise_test(async t => {
+ target.classList.add("init", "left");
+
+ let vt = document.startViewTransition(() => {
+ target.classList.remove("left");
+ target.classList.add("right");
+ });
+ await vt.ready;
+
+ document.styleSheets[0].insertRule(
+ "::view-transition-group(target) { animation-timing-function: linear; }",
+ document.styleSheets[0].cssRules.length
+ );
+ t.add_cleanup(() => {
+ document.styleSheets[0].deleteRule(
+ document.styleSheets[0].cssRules.length - 1
+ );
+ });
+
+ assert_equals(
+ getComputedStyle(document.documentElement,
+ "::view-transition-group(target)").transform,
+ "matrix(1, 0, 0, 1, 200, 0)",
+ "transform at 50% with linear"
+ );
+
+ await vt.skipTransition();
+ target.className = "";
+}, "Changing the timing function of ::view-transition-group() when animating");
+</script>
+
+</body>
+</html>
diff --git a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html
index 4a66af4ece2..2eebf8cf596 100644
--- a/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html
+++ b/tests/wpt/tests/css/css-view-transitions/inline-with-offset-from-containing-block-ref.html
@@ -6,7 +6,7 @@
<style>
.outer {
- transform: scale(2);
+ transform: scale3d(2, 2, 1);
width: 100vw;
text-align: center;
}
diff --git a/tests/wpt/tests/css/css-view-transitions/pseudo-get-computed-style.html b/tests/wpt/tests/css/css-view-transitions/pseudo-get-computed-style.html
index 60e032b1d98..274e946b825 100644
--- a/tests/wpt/tests/css/css-view-transitions/pseudo-get-computed-style.html
+++ b/tests/wpt/tests/css/css-view-transitions/pseudo-get-computed-style.html
@@ -47,24 +47,25 @@ promise_test(async () => {
assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").colorScheme, "normal", "container(target)");
assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").mixBlendMode, "normal", "container(target)");
assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").mixBlendMode, "normal", "container(root)");
-
- // After one frame, the activation of the view transition should be done, so
- // we have updated the pseudo-element styles.
- requestAnimationFrame(() => {
- assert_equals(getComputedStyle(document.documentElement, "::view-transition").position, "fixed", "raf ::view-transition");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").position, "absolute", "raf container(target)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").mixBlendMode, "multiply", "raf container(target)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").textOrientation, "upright", "raf container(target)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").colorScheme, "dark light", "raf container(target)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(target)").position, "fixed", "raf wrapper(target)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(target)").position, "absolute", "raf outgoing(target)");
-
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").position, "absolute", "raf container(root)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").mixBlendMode, "normal", "raf container(root)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(root)").position, "absolute", "raf wrapper(root)");
- assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(root)").position, "absolute", "raf outgoing(root)");
- });
});
+
+ // When transition is ready, the activation of the view transition should be done, so
+ // we have updated the pseudo-element styles.
+ await transition.ready;
+
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition").position, "fixed", "raf ::view-transition");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").position, "absolute", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").mixBlendMode, "multiply", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").textOrientation, "upright", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(target)").colorScheme, "dark light", "raf container(target)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(target)").position, "fixed", "raf wrapper(target)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(target)").position, "absolute", "raf outgoing(target)");
+
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").position, "absolute", "raf container(root)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-group(root)").mixBlendMode, "normal", "raf container(root)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-image-pair(root)").position, "absolute", "raf wrapper(root)");
+ assert_equals(getComputedStyle(document.documentElement, "::view-transition-old(root)").position, "absolute", "raf outgoing(root)");
+
await transition.finished;
}, "properties of pseudo elements in update callback");
diff --git a/tests/wpt/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html b/tests/wpt/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html
index e8d14f1bb08..6743ae8aff6 100644
--- a/tests/wpt/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html
+++ b/tests/wpt/tests/css/css-view-transitions/web-animation-pseudo-incorrect-name.html
@@ -3,6 +3,7 @@
<title>View transitions: creating animation for non-existant view transition pseudo</title>
<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
<link rel="author" href="mailto:khushalsagar@chromium.org">
+<script src="/dom/events/scrolling/scroll_support.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -22,18 +23,16 @@ div {
<script>
promise_test(async t => {
assert_implements(document.startViewTransition, "Missing document.startViewTransition");
- return new Promise(async (resolve, reject) => {
+ await waitForCompositorReady();
+ return new Promise(async (resolve) => {
let transition = document.startViewTransition();
await transition.ready;
let animation = document.documentElement.animate(
{ transform: ['translate(100px)', 'translate(200px)'] },
{duration: 100, pseudoElement: '::view-transition-group(bad-target)', fill: "forwards"});
-
- requestAnimationFrame(() => {
- animation.currentTime = 200;
- requestAnimationFrame(() => requestAnimationFrame(resolve));
- });
+ assert_true(!!animation, "animation is created");
+ resolve();
});
}, "animation created with incorrect name");
</script>
diff --git a/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background-ref.html b/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background-ref.html
new file mode 100644
index 00000000000..ea823309771
--- /dev/null
+++ b/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Reference: Inverted background on HiDPI</title>
+<style>
+ html {
+ background-color: black; /* The expected result after inversion of white body background */
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ }
+ body {
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ }
+</style>
+</html>
diff --git a/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background.html b/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background.html
new file mode 100644
index 00000000000..1091a3b56a4
--- /dev/null
+++ b/tests/wpt/tests/css/filter-effects/hidpi-invert-filter-background.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Inverted background on HiDPI</title>
+<link rel="help" href="https://crbug.com/412115607">
+<meta name="assert" content="The background should be inverted.">
+<link rel="match" href="hidpi-invert-filter-background-ref.html">
+<style>
+ html {
+ filter: invert(100%);
+ /* Ensure there's some content area for html/body to paint */
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ }
+ body {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ width: 100%;
+ /* A 1x1 white PNG. When html is inverted, this should make the effective background black. */
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC");
+ background-attachment: fixed;
+ background-repeat: repeat;
+ }
+</style>
+<!-- No visible content needed, we are checking the background color via pixel matching the -ref file. -->
+</html>
diff --git a/tests/wpt/tests/css/selectors/invalidation/has-with-nth-child-sibling-remove.html b/tests/wpt/tests/css/selectors/invalidation/has-with-nth-child-sibling-remove.html
new file mode 100644
index 00000000000..2c3e83f2bd9
--- /dev/null
+++ b/tests/wpt/tests/css/selectors/invalidation/has-with-nth-child-sibling-remove.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1964745">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#relational">
+<style>
+.square {
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+.item:not(:has(~ .item > :nth-child(2))) {
+ background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=container>
+ <div class="item square">
+ <div></div>
+ <div></div>
+ </div>
+ <div id=td class=item>
+ <div></div>
+ <div></div>
+ </div>
+</div>
+<script>
+window.onload = () => {
+ td.remove();
+};
+</script>
diff --git a/tests/wpt/tests/css/selectors/invalidation/negated-last-of-type-invalidation.html b/tests/wpt/tests/css/selectors/invalidation/negated-last-of-type-invalidation.html
new file mode 100644
index 00000000000..40bf8a8f0f4
--- /dev/null
+++ b/tests/wpt/tests/css/selectors/invalidation/negated-last-of-type-invalidation.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<html class="reftest-wait">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1964575">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-last-of-type-pseudo">
+<style>
+#dut {
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+.foo:not(:last-of-type ~ .bar) > #dut.baz {
+ background-color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div>
+ <span></span>
+ <div class="foo bar">
+ <div id=dut></div>
+ </div>
+ <span></span>
+</div>
+<script>
+window.onload = () => {
+ dut.classList.add("baz");
+ document.documentElement.classList.remove('reftest-wait');
+};
+</script>
+</html>
diff --git a/tests/wpt/tests/css/selectors/quirks-mode-import.html b/tests/wpt/tests/css/selectors/quirks-mode-import.html
new file mode 100644
index 00000000000..515f8d86e46
--- /dev/null
+++ b/tests/wpt/tests/css/selectors/quirks-mode-import.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Importing quirks mode element into standards mode document</title>
+ <link rel="help" href="https://crbug.com/416619318">
+ <style>
+ div { color: green; }
+ :not(.Foo) { color: red; }
+ </style>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <div id="elem1" class="Foo">This text should be green</div>
+ <div id="container"></div>
+ <script>
+ test(() => {
+ let doc = (new DOMParser()).parseFromString('<div><div id="elem2" class="Foo">This text should be green</div></div>', 'text/html');
+ let subdiv = doc.documentElement.firstChild.nextSibling.firstChild;
+ document.querySelector('#container').appendChild(document.importNode(subdiv, true));
+
+ assert_equals(getComputedStyle(document.querySelector('#elem1')).color, 'rgb(0, 128, 0)');
+ assert_equals(getComputedStyle(document.querySelector('#elem2')).color, 'rgb(0, 128, 0)');
+ });
+ </script>
+</html>
diff --git a/tests/wpt/tests/digital-credentials/allow-attribute-with-get.https.html b/tests/wpt/tests/digital-credentials/allow-attribute-with-get.https.html
index 15601d891f2..a13a188c9da 100644
--- a/tests/wpt/tests/digital-credentials/allow-attribute-with-get.https.html
+++ b/tests/wpt/tests/digital-credentials/allow-attribute-with-get.https.html
@@ -105,10 +105,11 @@
const options = {
digital: {
// Results in TypeError when allowed, NotAllowedError when disallowed
- requests: [],
+ requests: [{ data: {}, protocol: "openid4vp" }],
},
mediation: "required",
};
+ await test_driver.bless("User activation");
const { data } = await new Promise((resolve) => {
window.addEventListener("message", resolve, {
once: true,
diff --git a/tests/wpt/tests/digital-credentials/get.tentative.https.html b/tests/wpt/tests/digital-credentials/get.tentative.https.html
index b04a6e3a713..8c0c33c2fa1 100644
--- a/tests/wpt/tests/digital-credentials/get.tentative.https.html
+++ b/tests/wpt/tests/digital-credentials/get.tentative.https.html
@@ -29,6 +29,27 @@
});
promise_test(async (t) => {
+ const invalidData = [null, undefined, "", 123, true, false];
+ for (const data of invalidData) {
+ const options = {
+ digital: {
+ requests: [
+ {
+ data,
+ protocol: "openid4vp",
+ },
+ ],
+ },
+ };
+ await promise_rejects_js(
+ t,
+ TypeError,
+ navigator.credentials.get(options)
+ );
+ }
+ }, "Type conversion happens on the data member of the DigitalCredentialGetRequest object.");
+
+ promise_test(async (t) => {
iframeSameOrigin.focus();
for (const global of [window, iframeSameOrigin.contentWindow]) {
await promise_rejects_dom(
@@ -89,7 +110,11 @@
for (const request of [undefined, []]) {
const options = makeGetOptions(request);
await test_driver.bless("user activation");
- await promise_rejects_js(t, TypeError, navigator.credentials.get(options));
+ await promise_rejects_js(
+ t,
+ TypeError,
+ navigator.credentials.get(options)
+ );
}
}, "navigator.credentials.get() API rejects if there are no credential request.");
@@ -196,10 +221,14 @@
promise_test(async (t) => {
/** @type sequence<CredentialMediationRequirement> */
- const disallowedMediations = [ "conditional", "optional", "silent"];
+ const disallowedMediations = ["conditional", "optional", "silent"];
for (const mediation of disallowedMediations) {
const options = makeGetOptions("default", mediation);
- await promise_rejects_js(t, TypeError, navigator.credentials.get(options));
+ await promise_rejects_js(
+ t,
+ TypeError,
+ navigator.credentials.get(options)
+ );
}
}, "Mediation is required to get a DigitalCredential.");
</script>
diff --git a/tests/wpt/tests/digital-credentials/non-fully-active.https.html b/tests/wpt/tests/digital-credentials/non-fully-active.https.html
index 3c09b132daf..8d8f889f6ac 100644
--- a/tests/wpt/tests/digital-credentials/non-fully-active.https.html
+++ b/tests/wpt/tests/digital-credentials/non-fully-active.https.html
@@ -33,7 +33,7 @@
controller.abort();
// Steal all the needed references.
- const navigator = iframe.contentWindow.navigator;
+ const { credentials } = iframe.contentWindow.navigator;
const DOMExceptionCtor = iframe.contentWindow.DOMException;
// No longer fully active.
@@ -44,7 +44,7 @@
t,
"InvalidStateError",
DOMExceptionCtor,
- navigator.credentials.get({ signal }),
+ credentials.get({ signal }),
"Expected InvalidStateError for get() on non-fully-active document"
);
@@ -53,7 +53,7 @@
t,
"InvalidStateError",
DOMExceptionCtor,
- navigator.credentials.create({ signal }),
+ credentials.create({ signal }),
"Expected InvalidStateError for create() on non-fully-active document"
);
@@ -62,7 +62,7 @@
t,
"InvalidStateError",
DOMExceptionCtor,
- navigator.credentials.preventSilentAccess(),
+ credentials.preventSilentAccess(),
"Expected InvalidStateError for preventSilentAccess() on non-fully-active document"
);
}, "non-fully active document behavior for CredentialsContainer");
diff --git a/tests/wpt/tests/digital-credentials/support/iframe.html b/tests/wpt/tests/digital-credentials/support/iframe.html
index 3ec761e08a6..d737dcfc091 100644
--- a/tests/wpt/tests/digital-credentials/support/iframe.html
+++ b/tests/wpt/tests/digital-credentials/support/iframe.html
@@ -27,8 +27,8 @@
}
data.options.signal = abortController.signal;
}
- if (data.needsActivation) {
- await test_driver.bless("user activation", null, window);
+ if (data.needsActivation && !navigator.userActivation.isActive) {
+ await test_driver.bless("user activation");
}
let result;
try {
diff --git a/tests/wpt/tests/digital-credentials/user-activation.https.html b/tests/wpt/tests/digital-credentials/user-activation.https.html
index facaf7bddbb..1189c32252a 100644
--- a/tests/wpt/tests/digital-credentials/user-activation.https.html
+++ b/tests/wpt/tests/digital-credentials/user-activation.https.html
@@ -14,7 +14,7 @@
navigator.userActivation.isActive,
"User activation should not be active"
);
- const options = makeGetOptions([]);
+ const options = makeGetOptions("openid4vp");
await promise_rejects_dom(
t,
"NotAllowedError",
@@ -24,12 +24,17 @@
promise_test(async (t) => {
await test_driver.bless();
+ const abort = new AbortController();
+ const options = makeGetOptions("openid4vp");
+ options.signal = abort.signal;
assert_true(
navigator.userActivation.isActive,
"User activation should be active after test_driver.bless()."
);
- const options = makeGetOptions([]);
- await promise_rejects_js(t, TypeError, navigator.credentials.get(options));
+
+ const getPromise = navigator.credentials.get(options);
+ abort.abort();
+ await promise_rejects_dom(t, "AbortError", getPromise);
assert_false(
navigator.userActivation.isActive,
"User activation should be consumed after navigator.credentials.get()."
diff --git a/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-basic.tentative.https.html b/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-basic.tentative.https.html
new file mode 100644
index 00000000000..3affa4e3a6d
--- /dev/null
+++ b/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-basic.tentative.https.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>Federated Credential Management API Accounts Push tests.</title>
+<link rel="help" href="https://fedidcg.github.io/FedCM">
+<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>
+
+<body>
+
+<script type="module">
+import {fedcm_test,
+ request_options_with_mediation_required,
+ fedcm_select_account_promise,
+ fedcm_get_dialog_type_promise,
+ select_manifest,
+ setup_accounts_push, mark_signed_out} from '../support/fedcm-helper.sub.js';
+
+fedcm_test(async t => {
+ // Opens a window that then invokes navigator.login.setStatus with two pushed
+ // accounts with different picture URLs; one successful picture response, and
+ // one uncacheable response. Register the cleanup handler, which uses the
+ // setStatus API to set the state to 'logged-out'
+ t.add_cleanup(() => {
+ mark_signed_out();
+ });
+ await setup_accounts_push();
+
+ const test_options = request_options_with_mediation_required("manifest_accounts_push.json");
+ await select_manifest(t, test_options);
+
+ const cred_promise = navigator.credentials.get(test_options);
+ const type = await fedcm_get_dialog_type_promise(t);
+ assert_equals(type, "AccountChooser");
+
+ const accounts = await window.test_driver.get_fedcm_account_list();
+ assert_equals(accounts.length, 2);
+
+ assert_equals(accounts[0].accountId , "john_doe");
+ assert_equals(accounts[0].givenName, "John");
+ assert_equals(accounts[0].name, "John Doe");
+ assert_equals(accounts[0].email, "john_doe@idp.example");
+
+ assert_equals(accounts[1].accountId , "jane_doe");
+ assert_equals(accounts[1].givenName, "Jane");
+ assert_equals(accounts[1].name, "Jane Doe");
+ assert_equals(accounts[1].email, "jane_doe@idp.example");
+
+
+ await fedcm_select_account_promise(t, 0);
+
+ const cred = await cred_promise;
+ assert_equals(cred.token, "account_id=john_doe");
+ assert_equals(cred.isAutoSelected, false);
+}, "Successfully obtaining token should resolve the promise.");
+
+</script>
diff --git a/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-caches-pictures.tentative.https.html b/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-caches-pictures.tentative.https.html
new file mode 100644
index 00000000000..5b069785f98
--- /dev/null
+++ b/tests/wpt/tests/fedcm/fedcm-accounts-push/fedcm-accounts-push-caches-pictures.tentative.https.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Federated Credential Management API Accounts Push tests.</title>
+<link rel="help" href="https://fedidcg.github.io/FedCM">
+<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>
+
+<body>
+
+<script type="module">
+import {fedcm_test,
+ request_options_with_mediation_required,
+ setup_accounts_push, mark_signed_out,
+ fedcm_get_and_select_first_account} from '../support/fedcm-helper.sub.js';
+
+const successful_picture_counter_path = `/fedcm/support/account_picture_get_count.py`;
+const uncached_picture_counter_path = `/fedcm/support/account_picture_uncached_get_count.py`;
+
+async function wait_for_fetch_count(counter_path) {
+ const counter_response = await fetch(counter_path);
+ const counter_text = await counter_response.text();
+ return counter_text === "1";
+}
+
+fedcm_test(async t => {
+ // Get and clear the count to ensure the counters start at 0.
+ await fetch(successful_picture_counter_path);
+ await fetch(uncached_picture_counter_path);
+
+ // Opens a window that then invokes navigator.login.setStatus with two pushed
+ // accounts with different picture URLs; one successful picture response, and
+ // one uncacheable response. Register the cleanup handler, which uses the
+ // setStatus API to set the state to 'logged-out'
+ t.add_cleanup(() => {
+ mark_signed_out();
+ });
+ await setup_accounts_push();
+
+ await t.step_wait(() => wait_for_fetch_count(successful_picture_counter_path),
+ "Cacheable picture should be retrieved when " +
+ "navigator.login.setStatus is called",
+ /*timeout=*/1_000, /*interval=*/200);
+ await t.step_wait(() => wait_for_fetch_count(uncached_picture_counter_path),
+ "Uncacheable picture should be retrieved when " +
+ "navigator.login.setStatus is called",
+ /*timeout=*/1_000, /*interval=*/200);
+
+ const cred = await fedcm_get_and_select_first_account(t,
+ request_options_with_mediation_required("manifest_accounts_push.json"));
+ assert_equals(cred.token, "account_id=john_doe");
+ assert_equals(cred.isAutoSelected, false);
+
+ const successful_counter_response = await fetch(successful_picture_counter_path);
+ const successful_counter_text = await successful_counter_response.text();
+ assert_equals(successful_counter_text, "0",
+ "Cacheable picture should not be requested when " +
+ "navigator.credentials.get is called");
+
+ // ... even if the response during navigator.login.setStatus was uncacheable.
+ const error_counter_response = await fetch(uncached_picture_counter_path);
+ const error_counter_text = await error_counter_response.text();
+ assert_equals(error_counter_text, "0",
+ "Picture should not be requested even on a cache miss when " +
+ "navigator.credentials.get is called");
+}, "Pictures should be retrieved when accounts are pushed, not when " +
+ "credential request is made.");
+
+</script>
diff --git a/tests/wpt/tests/fedcm/support/account_picture.py b/tests/wpt/tests/fedcm/support/account_picture.py
new file mode 100644
index 00000000000..ae453086bc0
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/account_picture.py
@@ -0,0 +1,23 @@
+import importlib
+from base64 import decodebytes
+keys = importlib.import_module("fedcm.support.keys")
+error_checker = importlib.import_module("fedcm.support.request-params-check")
+
+def main(request, response):
+ request_error = error_checker.pictureCheck(request)
+ if request_error:
+ return request_error
+
+ counter = request.server.stash.take(keys.ACCOUNT_PICTURE_COUNTER_KEY)
+ try:
+ counter = int(counter) + 1
+ except (TypeError, ValueError):
+ counter = 1
+
+ request.server.stash.put(keys.ACCOUNT_PICTURE_COUNTER_KEY, str(counter).encode())
+
+ response.headers.set(b"Content-Type", b"image/png")
+ response.headers.set(b"Cache-Control", b"max-age=3600")
+ # Return minimum valid PNG
+ png_response = decodebytes(b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==')
+ return png_response
diff --git a/tests/wpt/tests/fedcm/support/account_picture_get_count.py b/tests/wpt/tests/fedcm/support/account_picture_get_count.py
new file mode 100644
index 00000000000..91c3601fbdc
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/account_picture_get_count.py
@@ -0,0 +1,13 @@
+import importlib
+keys = importlib.import_module("fedcm.support.keys")
+
+def main(request, response):
+ account_picture_url = "/fedcm/support/account_picture.py"
+
+ counter = request.server.stash.take(keys.ACCOUNT_PICTURE_COUNTER_KEY, account_picture_url)
+ try:
+ counter = counter.decode()
+ except (UnicodeDecodeError, AttributeError):
+ counter = 0
+
+ return str(counter)
diff --git a/tests/wpt/tests/fedcm/support/account_picture_uncached.py b/tests/wpt/tests/fedcm/support/account_picture_uncached.py
new file mode 100644
index 00000000000..51289f37b7c
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/account_picture_uncached.py
@@ -0,0 +1,23 @@
+import importlib
+from base64 import decodebytes
+keys = importlib.import_module("fedcm.support.keys")
+error_checker = importlib.import_module("fedcm.support.request-params-check")
+
+def main(request, response):
+ request_error = error_checker.pictureCheck(request)
+ if request_error:
+ return request_error
+
+ counter = request.server.stash.take(keys.ACCOUNT_PICTURE_UNCACHED_COUNTER_KEY)
+ try:
+ counter = int(counter) + 1
+ except (TypeError, ValueError):
+ counter = 1
+
+ request.server.stash.put(keys.ACCOUNT_PICTURE_UNCACHED_COUNTER_KEY, str(counter).encode())
+
+ response.headers.set(b"Content-Type", b"image/png")
+ response.headers.set(b"Cache-Control", b"max-age=0")
+ # Return minimum valid PNG
+ png_response = decodebytes(b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==')
+ return png_response
diff --git a/tests/wpt/tests/fedcm/support/account_picture_uncached_get_count.py b/tests/wpt/tests/fedcm/support/account_picture_uncached_get_count.py
new file mode 100644
index 00000000000..e2adbd517b8
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/account_picture_uncached_get_count.py
@@ -0,0 +1,13 @@
+import importlib
+keys = importlib.import_module("fedcm.support.keys")
+
+def main(request, response):
+ account_picture_error_url = "/fedcm/support/account_picture_uncached.py"
+
+ counter = request.server.stash.take(keys.ACCOUNT_PICTURE_UNCACHED_COUNTER_KEY, account_picture_error_url)
+ try:
+ counter = counter.decode()
+ except (UnicodeDecodeError, AttributeError):
+ counter = 0
+
+ return str(counter)
diff --git a/tests/wpt/tests/fedcm/support/fedcm-helper.sub.js b/tests/wpt/tests/fedcm/support/fedcm-helper.sub.js
index 4337adf9f87..b6bbbc19e21 100644
--- a/tests/wpt/tests/fedcm/support/fedcm-helper.sub.js
+++ b/tests/wpt/tests/fedcm/support/fedcm-helper.sub.js
@@ -37,6 +37,10 @@ export function set_alt_fedcm_cookie() {
return set_fedcm_cookie(alt_manifest_origin);
}
+export function setup_accounts_push(origin = manifest_origin) {
+ return open_and_wait_for_popup(origin, '/fedcm/support/push_accounts');
+}
+
export function mark_signed_in(origin = manifest_origin) {
return open_and_wait_for_popup(origin, '/fedcm/support/mark_signedin');
}
diff --git a/tests/wpt/tests/fedcm/support/keys.py b/tests/wpt/tests/fedcm/support/keys.py
index 6b7d67e21e7..8ced364116b 100644
--- a/tests/wpt/tests/fedcm/support/keys.py
+++ b/tests/wpt/tests/fedcm/support/keys.py
@@ -1,2 +1,4 @@
CLIENT_METADATA_COUNTER_KEY = b"bdc14e3e-b8bc-44a1-8eec-78da5fdacbc3"
MANIFEST_URL_IN_MANIFEST_LIST_KEY = b"7f3f7478-b7f0-41c5-b357-f3ac16f5f25a"
+ACCOUNT_PICTURE_COUNTER_KEY = b"9dca7d23-149d-4a21-8eda-851329365d10"
+ACCOUNT_PICTURE_UNCACHED_COUNTER_KEY = b"ee1a8abc-f656-4f6b-a14f-d63670ff031b"
diff --git a/tests/wpt/tests/fedcm/support/manifest_accounts_push.json b/tests/wpt/tests/fedcm/support/manifest_accounts_push.json
new file mode 100644
index 00000000000..721fe05f940
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/manifest_accounts_push.json
@@ -0,0 +1,4 @@
+{
+ "id_assertion_endpoint": "token_with_account_id.py",
+ "login_url": "login.html"
+}
diff --git a/tests/wpt/tests/fedcm/support/mark_signedout.sub.headers b/tests/wpt/tests/fedcm/support/mark_signedout.sub.headers
index 69157b3a371..5ddbacf85f4 100644
--- a/tests/wpt/tests/fedcm/support/mark_signedout.sub.headers
+++ b/tests/wpt/tests/fedcm/support/mark_signedout.sub.headers
@@ -2,4 +2,5 @@ Content-Type: text/html
Set-Login: logged-out
Access-Control-Allow-Origin: https://{{host}}:{{ports[https][0]}}
Access-Control-Allow-Credentials: true
+Clear-Site-Data: "cache"
Supports-Loading-Mode: fenced-frame
diff --git a/tests/wpt/tests/fedcm/support/push_accounts b/tests/wpt/tests/fedcm/support/push_accounts
new file mode 100644
index 00000000000..ea7eb12beab
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/push_accounts
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+navigator.login.setStatus('logged-in', {
+ accounts: [{
+ "id": "john_doe",
+ "given_name": "John",
+ "name": "John Doe",
+ "email": "john_doe@idp.example",
+ "picture": "account_picture.py",
+ },
+ {
+ "id": "jane_doe",
+ "given_name": "Jane",
+ "name": "Jane Doe",
+ "email": "jane_doe@idp.example",
+ "picture": "account_picture_uncached.py",
+ }],
+ expiration: 60*60*1000 // 1 hour
+}).then(() => {
+ // If this page was opened as a popup, notify the opener.
+ if (window.opener) {
+ window.opener.postMessage("done_loading", "*");
+ }
+});
+
+</script>
+</body>
+</html>
diff --git a/tests/wpt/tests/fedcm/support/push_accounts.sub.headers b/tests/wpt/tests/fedcm/support/push_accounts.sub.headers
new file mode 100644
index 00000000000..d560fade5a0
--- /dev/null
+++ b/tests/wpt/tests/fedcm/support/push_accounts.sub.headers
@@ -0,0 +1,5 @@
+Content-Type: text/html
+Set-Login: logged-in
+Access-Control-Allow-Origin: https://{{host}}:{{ports[https][0]}}
+Access-Control-Allow-Credentials: true
+Supports-Loading-Mode: fenced-frame
diff --git a/tests/wpt/tests/fedcm/support/request-params-check.py b/tests/wpt/tests/fedcm/support/request-params-check.py
index 08c28e32b79..f5b48d9b053 100644
--- a/tests/wpt/tests/fedcm/support/request-params-check.py
+++ b/tests/wpt/tests/fedcm/support/request-params-check.py
@@ -1,6 +1,7 @@
-def commonCheck(request, mode=b"no-cors"):
- if request.headers.get(b"Accept") != b"application/json":
- return (531, [], "Wrong Accept")
+def commonCheck(request, mode=b"no-cors", accept=b"application/json"):
+ if accept:
+ if request.headers.get(b"Accept") != accept:
+ return (531, [], "Wrong Accept")
if request.headers.get(b"Sec-Fetch-Dest") != b"webidentity":
return (532, [], "Wrong Sec-Fetch-Dest header")
if request.headers.get(b"Referer"):
@@ -104,3 +105,15 @@ def revokeCheck(request):
if not request.POST.get(b"account_hint"):
return (544, [], "Missing 'account_hint' POST parameter")
+
+def pictureCheck(request):
+ common_error = commonCheck(request, accept=None)
+ if (common_error):
+ return common_error
+
+ common_uncredentialed_error = commonUncredentialedRequestCheck(request)
+ if (common_uncredentialed_error):
+ return common_uncredentialed_error
+
+ if request.headers.get(b"Origin"):
+ return (539, [], "Should not have Origin")
diff --git a/tests/wpt/tests/generic-sensor/generic-sensor-iframe-tests.sub.js b/tests/wpt/tests/generic-sensor/generic-sensor-iframe-tests.sub.js
index a63729ec2e6..764eef06c40 100644
--- a/tests/wpt/tests/generic-sensor/generic-sensor-iframe-tests.sub.js
+++ b/tests/wpt/tests/generic-sensor/generic-sensor-iframe-tests.sub.js
@@ -89,7 +89,8 @@ function run_generic_sensor_iframe_tests(sensorData, readingData) {
};
// Create main frame sensor.
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
const sensor = new sensorType();
t.add_cleanup(async () => {
@@ -192,7 +193,8 @@ function run_generic_sensor_iframe_tests(sensorData, readingData) {
sensor_test(async (t, readings) => {
// Create main frame sensor.
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
const sensor = new sensorType();
t.add_cleanup(async () => {
@@ -277,7 +279,8 @@ function run_generic_sensor_iframe_tests(sensorData, readingData) {
await iframeLoadWatcher.wait_for('load');
// Create sensor in the iframe.
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
iframe.contentWindow.focus();
const iframeSensor = new iframe.contentWindow[sensorName]();
@@ -310,7 +313,8 @@ function run_generic_sensor_iframe_tests(sensorData, readingData) {
await iframeLoadWatcher.wait_for('load');
// Create sensor in the iframe.
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
const iframeSensor = new iframe.contentWindow[sensorName]();
t.add_cleanup(async () => {
diff --git a/tests/wpt/tests/generic-sensor/generic-sensor-tests.js b/tests/wpt/tests/generic-sensor/generic-sensor-tests.js
index 970dc3314c3..894fc7d2ed0 100644
--- a/tests/wpt/tests/generic-sensor/generic-sensor-tests.js
+++ b/tests/wpt/tests/generic-sensor/generic-sensor-tests.js
@@ -43,7 +43,8 @@ function runGenericSensorTests(sensorData, readingData) {
});
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'denied');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'denied'});
await test_driver.create_virtual_sensor(testDriverName);
const sensor = new sensorType;
@@ -62,7 +63,8 @@ function runGenericSensorTests(sensorData, readingData) {
granted.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName, {connected: false});
const sensor = new sensorType;
@@ -81,7 +83,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: Test that onerror is send when start() call has failed.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -101,7 +104,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: Test that frequency is capped to allowed maximum.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
const maxSupportedFrequency = 5;
await test_driver.create_virtual_sensor(
@@ -125,7 +129,8 @@ function runGenericSensorTests(sensorData, readingData) {
frequency.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
const minSupportedFrequency = 2;
await test_driver.create_virtual_sensor(
@@ -201,7 +206,8 @@ function runGenericSensorTests(sensorData, readingData) {
allowed to use feature policy.`);
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -234,7 +240,8 @@ function runGenericSensorTests(sensorData, readingData) {
valid.`);
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -279,7 +286,8 @@ function runGenericSensorTests(sensorData, readingData) {
// Tests that readings maps to expectedReadings correctly. Due to threshold
// check and rounding some values might be discarded or changed.
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -309,7 +317,8 @@ function runGenericSensorTests(sensorData, readingData) {
correctly.`);
sensor_test(async (t, readings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -343,7 +352,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: sensor timestamp is updated when time passes.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -366,7 +376,8 @@ function runGenericSensorTests(sensorData, readingData) {
states are correct.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -385,7 +396,8 @@ function runGenericSensorTests(sensorData, readingData) {
started sensor.`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -405,7 +417,8 @@ function runGenericSensorTests(sensorData, readingData) {
stopped sensor.`);
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -454,7 +467,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: Test that fresh reading is fetched on start().`);
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -516,7 +530,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: Readings are not delivered when the page has no visibility`);
sensor_test(async t => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -567,7 +582,8 @@ function runGenericSensorTests(sensorData, readingData) {
}, `${sensorName}: frequency hint works.`);
sensor_test(async (t, readings, expectedReadings) => {
- await test_driver.set_permission({name: permissionName}, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
await test_driver.create_virtual_sensor(testDriverName);
@@ -652,7 +668,8 @@ function runGenericSensorTests(sensorData, readingData) {
// async (t, readings, expectedReadings, expectedRemappedReadings) => {
// assert_implements_optional(screen.orientation.angle == 270,
// 'Remapped values expect a specific screen rotation.');
- // await test_driver.set_permission({name: permissionName}, 'granted');
+ // await test_driver.bidi.permissions.set_permission({descriptor: {name:
+ // permissionName}, state: 'granted'});
// await test_driver.create_virtual_sensor(testDriverName);
diff --git a/tests/wpt/tests/generic-sensor/resources/iframe_sensor_handler.html b/tests/wpt/tests/generic-sensor/resources/iframe_sensor_handler.html
index 80cdcf7c0d0..f8a78aa8b09 100644
--- a/tests/wpt/tests/generic-sensor/resources/iframe_sensor_handler.html
+++ b/tests/wpt/tests/generic-sensor/resources/iframe_sensor_handler.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>cross-origin iframe sensor tester</title>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script>
@@ -31,7 +31,8 @@
// really work when permissions are granted by default. This can only
// be fixed by testdriver.js allowing set_permission() to specify a
// different origin.
- await test_driver.set_permission({ name: permissionName }, 'granted');
+ await test_driver.bidi.permissions.set_permission(
+ {descriptor: {name: permissionName}, state: 'granted'});
sensor = new self[sensorName]();
}
return Promise.resolve();
diff --git a/tests/wpt/tests/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html b/tests/wpt/tests/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html
index f3cf0bc97e1..8ce0aab3389 100644
--- a/tests/wpt/tests/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html
+++ b/tests/wpt/tests/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html
@@ -2,7 +2,7 @@
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
- <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/permissions-policy/resources/permissions-policy.js"></script>
<script>
@@ -16,7 +16,20 @@
// Grant permission to outer frame
promise_setup(async () => {
- await test_driver.set_permission({ name: "geolocation" }, "granted");
+ await test_driver.bidi.permissions.set_permission({
+ descriptor: { name: "geolocation" }, state: "granted"
+ });
+ await test_driver.bidi.emulation.set_geolocation_override({
+ coordinates: {
+ latitude: 52.51,
+ longitude: 13.39,
+ accuracy: 0.5,
+ altitude: 34,
+ altitudeAccuracy: 0.75,
+ heading: 180,
+ speed: 2.77
+ }
+ });
});
promise_test(async (test) => {
diff --git a/tests/wpt/tests/geolocation/getCurrentPosition-error.https.html b/tests/wpt/tests/geolocation/getCurrentPosition-error.https.html
new file mode 100644
index 00000000000..0ea929d161e
--- /dev/null
+++ b/tests/wpt/tests/geolocation/getCurrentPosition-error.https.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta charset="utf-8"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+ promise_setup(async () => {
+ // Ensure permission is granted before proceeding.
+ await test_driver.bidi.permissions.set_permission({
+ descriptor: {name: "geolocation"},
+ state: "granted",
+ });
+ });
+
+ promise_test(async (t) => {
+ t.add_cleanup(async () => {
+ await test_driver.bidi.emulation.set_geolocation_override(
+ {coordinates: null});
+ });
+
+ await test_driver.bidi.emulation.set_geolocation_override({
+ error: {type: "positionUnavailable"}
+ });
+
+ const error = await new Promise(
+ (resolve, reject) =>
+ window.navigator.geolocation.getCurrentPosition(
+ () => reject("Unexpected success callback"),
+ error => resolve({
+ code: error.code,
+ message: error.message,
+ PERMISSION_DENIED: error.PERMISSION_DENIED,
+ POSITION_UNAVAILABLE: error.POSITION_UNAVAILABLE,
+ TIMEOUT: error.TIMEOUT
+ }),
+ {timeout: 1000}
+ ));
+
+ assert_equals(error.code, 2);
+ // The message value is not specified.
+ assert_not_equals(error.message, undefined);
+ assert_equals(error.PERMISSION_DENIED, 1);
+ assert_equals(error.POSITION_UNAVAILABLE, 2);
+ assert_equals(error.TIMEOUT, 3);
+ }, "Tests Geolocation error callback");
+</script>
diff --git a/tests/wpt/tests/geolocation/getCurrentPosition-success.https.html b/tests/wpt/tests/geolocation/getCurrentPosition-success.https.html
new file mode 100644
index 00000000000..d601b536329
--- /dev/null
+++ b/tests/wpt/tests/geolocation/getCurrentPosition-success.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+ promise_setup(async () => {
+ // Ensure permission is granted before proceeding.
+ await test_driver.bidi.permissions.set_permission({
+ descriptor: {name: "geolocation"},
+ state: "granted",
+ });
+ });
+
+ promise_test(async (t) => {
+ t.add_cleanup(async () => {
+ await test_driver.bidi.emulation.set_geolocation_override(
+ {coordinates: null});
+ });
+
+ const latitude = 51.478;
+ const longitude = -0.166;
+ const accuracy = 100;
+
+ await test_driver.bidi.emulation.set_geolocation_override({
+ coordinates: {latitude, longitude, accuracy}
+ });
+
+ const position = await new Promise(
+ (resolve, reject) =>
+ window.navigator.geolocation.getCurrentPosition(
+ position => resolve(position.coords.toJSON()),
+ error => reject(error),
+ {timeout: 200}
+ ));
+
+ assert_equals(position.latitude, latitude);
+ assert_equals(position.longitude, longitude);
+ assert_equals(position.accuracy, accuracy);
+ }, "Tests Geolocation success callback");
+</script>
diff --git a/tests/wpt/tests/gyroscope/Gyroscope-iframe-access.https.html b/tests/wpt/tests/gyroscope/Gyroscope-iframe-access.https.html
index c94016764d5..cdabff82f10 100644
--- a/tests/wpt/tests/gyroscope/Gyroscope-iframe-access.https.html
+++ b/tests/wpt/tests/gyroscope/Gyroscope-iframe-access.https.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://www.w3.org/TR/gyroscope/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/gyroscope/Gyroscope.https.html b/tests/wpt/tests/gyroscope/Gyroscope.https.html
index 8aab94693ab..ce2c09515f1 100644
--- a/tests/wpt/tests/gyroscope/Gyroscope.https.html
+++ b/tests/wpt/tests/gyroscope/Gyroscope.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/gyroscope/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/html/canvas/canvas-sibling-index-crash.html b/tests/wpt/tests/html/canvas/canvas-sibling-index-crash.html
new file mode 100644
index 00000000000..506a77ebad5
--- /dev/null
+++ b/tests/wpt/tests/html/canvas/canvas-sibling-index-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="http://crbug.com/416454066">
+<canvas id="canvas"></canvas>
+<script>
+ const canvas = document.getElementById("canvas");
+ const ctx = canvas.getContext("2d");
+
+ ctx.fillStyle = "lch(from blue calc(l + sibling-index()) c h)";
+ ctx.fillRect(10, 10, 100, 100);
+</script>
diff --git a/tests/wpt/tests/html/cross-origin-opener-policy/resources/noopener-helper.js b/tests/wpt/tests/html/cross-origin-opener-policy/resources/noopener-helper.js
index 6dd2c9bc1c9..9a4097b21e4 100644
--- a/tests/wpt/tests/html/cross-origin-opener-policy/resources/noopener-helper.js
+++ b/tests/wpt/tests/html/cross-origin-opener-policy/resources/noopener-helper.js
@@ -121,8 +121,9 @@ const test_noopener_navigating_away = (popup_coop) => {
assert_equals(await receive(reply_token), 'Popup loaded');
t.add_cleanup(() => send(popup_token, 'window.close()'));
- // Assert that we can script the popup.
- assert_not_equals(popup.window, null, 'can script the popup');
+ // There's an open question if we should check that popup.window is null here.
+ // See https://github.com/whatwg/html/issues/10457
+ // Assert that we cannot script the popup.
assert_false(popup.closed, 'popup closed');
// Ensure that the popup has no access to its opener.
@@ -156,7 +157,8 @@ const test_noopener_navigating_away = (popup_coop) => {
`);
assert_equals(await receive(reply_token), 'popup navigated away');
- assert_equals(popup.window, null);
+ // There's an open question if we should check that popup.window is null here.
+ // See https://github.com/whatwg/html/issues/10457
assert_true(popup.closed, 'popup.closed');
},
'noopener-allow-popups ensures that the opener cannot script the openee,' +
diff --git a/tests/wpt/tests/html/dom/elements-embedded.js b/tests/wpt/tests/html/dom/elements-embedded.js
index c5b4520cc6e..c10461ed6e8 100644
--- a/tests/wpt/tests/html/dom/elements-embedded.js
+++ b/tests/wpt/tests/html/dom/elements-embedded.js
@@ -88,8 +88,8 @@ var embeddedElements = {
// HTMLMediaElement
src: "url",
crossOrigin: {type: "enum", keywords: ["anonymous", "use-credentials"], nonCanon:{"": "anonymous"}, isNullable: true, defaultVal: null, invalidVal: "anonymous"},
- // As with "keytype", we have no missing value default defined here.
- preload: {type: "enum", keywords: ["none", "metadata", "auto"], nonCanon: {"": "auto"}, defaultVal: null},
+ // Missing/Invalid value is implementation defined but must be one of the keywords
+ preload: {type: "enum", keywords: ["none", "metadata", "auto"], nonCanon: {"": "auto"}, defaultVal: ["none", "metadata", "auto"]},
autoplay: "boolean",
loop: "boolean",
controls: "boolean",
@@ -105,8 +105,8 @@ var embeddedElements = {
// HTMLMediaElement
src: "url",
crossOrigin: {type: "enum", keywords: ["anonymous", "use-credentials"], nonCanon:{"": "anonymous"}, isNullable: true, defaultVal: null, invalidVal: "anonymous"},
- // As with "keytype", we have no missing value default defined here.
- preload: {type: "enum", keywords: ["none", "metadata", "auto"], nonCanon: {"": "auto"}, defaultVal: null},
+ // Missing/Invalid value is implementation defined but must be one of the keywords
+ preload: {type: "enum", keywords: ["none", "metadata", "auto"], nonCanon: {"": "auto"}, defaultVal: ["none", "metadata", "auto"]},
autoplay: "boolean",
loop: "boolean",
controls: "boolean",
diff --git a/tests/wpt/tests/html/dom/new-harness.js b/tests/wpt/tests/html/dom/new-harness.js
index 49f8e40ad7d..ad6214fb64f 100644
--- a/tests/wpt/tests/html/dom/new-harness.js
+++ b/tests/wpt/tests/html/dom/new-harness.js
@@ -8,4 +8,6 @@ ReflectionHarness.test = function(fun, description) {
ReflectionHarness.assertEquals = assert_equals;
+ReflectionHarness.assertInArray = assert_in_array;
+
ReflectionHarness.assertThrows = assert_throws_dom;
diff --git a/tests/wpt/tests/html/dom/original-harness.js b/tests/wpt/tests/html/dom/original-harness.js
index 89a80670334..6e48a562a6d 100644
--- a/tests/wpt/tests/html/dom/original-harness.js
+++ b/tests/wpt/tests/html/dom/original-harness.js
@@ -131,6 +131,26 @@ ReflectionHarness.assertEquals = function(expected, actual, description) {
}
/**
+ * If answer.includes(question), output a success, else report a failure with the
+ * given description. Currently success and failure both increment counters,
+ * and failures output a message to a <ul>. Which <ul> is decided by the type
+ * parameter -- different attribute types are separated for readability.
+ *
+ * @public
+ */
+ReflectionHarness.assertInArray = function(expected, actual, description) {
+ if (actual.includes(expected)) {
+ this.increment(this.passed);
+ } else {
+ this.increment(this.failed);
+ this.reportFailure(this.currentTestDescription +
+ (description ? " followed by " + description : "") +
+ ' (expected one of ' + this.stringRep(actual) + ', got ' +
+ this.stringRep(expected) + ')');
+ }
+}
+
+/**
* If calling fn causes a DOMException of the type given by the string
* exceptionName (e.g., "IndexSizeError"), output a success. Otherwise, report
* a failure.
diff --git a/tests/wpt/tests/html/dom/reflection.js b/tests/wpt/tests/html/dom/reflection.js
index eeecd450fca..3423c935895 100644
--- a/tests/wpt/tests/html/dom/reflection.js
+++ b/tests/wpt/tests/html/dom/reflection.js
@@ -186,7 +186,8 @@ var maxUnsigned = 4294967295;
*
* "jsType": What typeof idlObj[idlName] is supposed to be.
* "defaultVal": The default value to be returned if the attribute is not
- * present and no default is specifically set for this attribute.
+ * present and no default is specifically set for this attribute. If
+ * it is an array then any value in the array is acceptable.
* "domTests": What values to test with setAttribute().
* "domExpected": What values to expect with IDL get after setAttribute().
* Defaults to the same as domTests.
@@ -761,7 +762,12 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) {
}
if (!data.customGetter && (defaultVal !== null || data.isNullable)) {
ReflectionHarness.test(function() {
+ // Tests can pass an array of acceptable values
+ if (Array.isArray(defaultVal)) {
+ ReflectionHarness.assertInArray(idlObj[idlName], defaultVal);
+ } else {
ReflectionHarness.assertEquals(idlObj[idlName], defaultVal);
+ }
}, "IDL get with DOM attribute unset");
}
@@ -947,8 +953,14 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) {
domObj.setAttribute(domName, domTests[i]);
ReflectionHarness.assertEquals(domObj.getAttribute(domName),
String(domTests[i]), "getAttribute()");
- ReflectionHarness.assertEquals(idlObj[idlName], domExpected[i],
- "IDL get");
+ // Tests can pass an array of acceptable values
+ if (Array.isArray(domExpected[i])) {
+ ReflectionHarness.assertInArray(idlObj[idlName], domExpected[i],
+ "IDL get");
+ } else {
+ ReflectionHarness.assertEquals(idlObj[idlName], domExpected[i],
+ "IDL get");
+ }
}, "setAttribute() to " + ReflectionHarness.stringRep(domTests[i]));
}
@@ -986,7 +998,14 @@ ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) {
ReflectionHarness.assertEquals(domObj.getAttribute(domName), expected,
"getAttribute()");
}
- if (idlIdlExpected[i] !== null || data.isNullable) {
+ // Ensure enumerated attributes never reflect in their non-canonical representations
+ if (data.type == "enum" && data.nonCanon[idlObj[idlName]]) {
+ ReflectionHarness.assertEquals(idlObj[idlName], data.nonCanon[idlObj[idlName]], "IDL get canonical");
+ }
+ // Tests can pass an array of acceptable values
+ if (Array.isArray(idlIdlExpected[i])) {
+ ReflectionHarness.assertInArray(idlObj[idlName], idlIdlExpected[i], "IDL get");
+ } else if (idlIdlExpected[i] !== null || data.isNullable) {
ReflectionHarness.assertEquals(idlObj[idlName], idlIdlExpected[i], "IDL get");
}
}
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html b/tests/wpt/tests/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html
new file mode 100644
index 00000000000..253ba213273
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>embed - javascript: URL</title>
+<link rel="help" href="https://html.spec.whatwg.org/#the-embed-element-setup-steps">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ // embed element setup steps fetches url, which results in a network error
+ // and thus "Display no plugin".
+ promise_test(async function (t) {
+ const embed = document.createElement('embed');
+ embed.src = 'javascript:"foo"';
+ embed.onload = t.unreached_func('No load event expected');
+ document.body.append(embed);
+ t.add_cleanup(() => { embed.remove(); });
+ await new Promise(resolve => { t.step_timeout(resolve, 100); });
+ }, "javascript: in src attribute should do nothing");
+
+ function insertEmbedNavigable(t) {
+ const embed = document.createElement('embed');
+ embed.src = '/resources/blank.html';
+ document.body.append(embed);
+ t.add_cleanup(() => { embed.remove(); });
+ return embed;
+ }
+
+ promise_test(async function (t) {
+ const embed = insertEmbedNavigable(t);
+ await new Promise(resolve => { embed.onload = resolve; });
+ const loaded = new Promise(resolve => { embed.onload = resolve; });
+ window[0].location.href = 'javascript:"test"';
+ await loaded;
+ }, 'location.href = \'javascript:"test"\' should fire a load event');
+
+ promise_test(async function (t) {
+ const embed = insertEmbedNavigable(t);
+ await new Promise(resolve => { embed.onload = resolve; });
+ embed.onload = t.unreached_func('No second load event expected');
+ window[0].location.href = 'javascript:1';
+ await new Promise(resolve => { t.step_timeout(resolve, 100); });
+ }, 'location.href = \'javascript:1\' should not fire a load event');
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
index 1010c540b7f..47435f4c48d 100644
--- a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
@@ -14,8 +14,8 @@ iframe.hidden = false;
<script src="/resources/testharnessreport.js"></script>
<script>
setup({single_test: true});
+assert_true("navigation" in window, "Navigation API is supported");
iframeLoaded.then(() => {
- assert_true("navigation" in window, "Navigation API is supported");
// Need a timeout to detect failure when there are two navigations.
step_timeout(() => {
assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?nav", location.href).href);
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
index aefd6c472b5..6633b710828 100644
--- a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<title>Reloading iframe loading='lazy' before it is loaded: location.reload</title>
+<title>Reloading iframe loading='lazy' before it is loaded: navigation.reload</title>
<iframe src="support/blank.htm?src" loading="lazy" hidden></iframe>
<script>
const iframe = document.querySelector('iframe');
@@ -15,10 +15,10 @@ iframe.hidden = false;
<script src="/resources/testharnessreport.js"></script>
<script>
setup({single_test: true});
+assert_true("navigation" in window, "Navigation API is supported");
iframeLoaded.then(() => {
// Need a timeout to detect failure when there are two navigations.
step_timeout(() => {
- assert_true("navigation" in window, "Navigation API is supported");
assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?src", location.href).href);
done();
}, 1000);
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm
new file mode 100644
index 00000000000..73202af1d7c
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_in_src.htm
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>javascript: URL in iframe src</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const tests = [
+ // desc, url, expected_textContent
+ ['string', 'javascript:"foo"', 'foo'],
+ ['empty string', 'javascript:""', ''],
+ ['String object', 'javascript:new String("foo")', ''],
+ ['undefined', 'javascript:void(0)', ''],
+ ['number', 'javascript:1', ''],
+ ['boolean', 'javascript:true', ''],
+ ['null', 'javascript:null', ''],
+ ['global', 'javascript:window', ''],
+ ['host object', 'javascript:document', ''],
+ ['function', 'javascript:(() => { return function() {}; })()', ''],
+ ['regexp', 'javascript:/foo/', ''],
+ ['array', 'javascript:["foo"]', ''],
+ ['object', 'javascript:{"foo": "bar"}', ''],
+ ['ArrayBuffer', 'javascript:new ArrayBuffer(8)', ''],
+ ['TypeError', 'javascript:new TypeError("foo")', ''],
+];
+for (const [desc, url, expected_textContent] of tests) {
+ async_test(t => {
+ const iframe = document.createElement('iframe');
+ iframe.src = url;
+ iframe.hidden = true;
+ let load_events = 0;
+ iframe.onload = t.step_func(() => {
+ load_events++;
+ assert_equals(iframe.contentDocument.URL, 'about:blank');
+ assert_equals(iframe.contentDocument.body.textContent, expected_textContent);
+ assert_equals(load_events, 1);
+ if (load_events === 1) {
+ t.step_timeout(() => {
+ t.done();
+ }, 100);
+ }
+ });
+ document.body.append(iframe);
+ }, `${desc}: ${url}`);
+}
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html
new file mode 100644
index 00000000000..6989172a217
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_initial_insertion.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>javascript: URL in iframe src, initial insertion check</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+setup({single_test: true});
+let iframeLoaded = false;
+window.javascriptUrlRan = 0;
+</script>
+<iframe src="javascript:(() => { parent.javascriptUrlRan++; })()" onload="iframeLoaded = true; this.onload = assert_unreached;"></iframe>
+<script>
+onload = () => {
+ const iframe = document.querySelector('iframe');
+ assert_true(iframeLoaded, "iframeLoaded");
+ iframe.src = iframe.src + ";";
+ assert_equals(javascriptUrlRan, 1, "javascriptUrlRan");
+ step_timeout(() => {
+ assert_equals(javascriptUrlRan, 2, "javascriptUrlRan");
+ done();
+ }, 100); // Verify only one load event is fired on iframe
+};
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm
new file mode 100644
index 00000000000..e88592b2a11
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_loading_lazy.htm
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>javascript: URL in iframe src and loading="lazy"</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+async_test(t => {
+ const iframe = document.createElement('iframe');
+ iframe.src = 'javascript:"test"';
+ iframe.hidden = true;
+ iframe.loading = 'lazy';
+ iframe.onload = t.step_func_done(() => {
+ assert_false(iframe.hidden, 'Got unexpected load event on iframe while still hidden');
+ assert_equals(iframe.contentDocument.body.textContent, 'test', 'Expected the document created from the javascript: URL');
+ });
+ document.body.append(iframe);
+ window.onload = t.step_func(() => {
+ assert_equals(iframe.contentDocument.body.textContent, '', 'Expected initial about:blank');
+ iframe.hidden = false; // run the lazy load resumption steps, which navigates
+ });
+});
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html
new file mode 100644
index 00000000000..9d236426c96
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_not_about_blank.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>javascript: URL in iframe src, initial src is not about:blank</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+setup({single_test: true});
+let iframeLoaded = false;
+window.javascriptUrlRan = false;
+</script>
+<iframe src="/resources/blank.html" onload="iframeLoaded = true; this.onload = assert_unreached;"></iframe>
+<script>
+onload = () => {
+ const iframe = document.querySelector('iframe');
+ assert_true(iframeLoaded, "iframeLoaded");
+ iframe.src = "javascript:(() => { parent.javascriptUrlRan = true; })()";
+ assert_false(javascriptUrlRan, "javascriptUrlRan");
+ step_timeout(() => {
+ assert_true(javascriptUrlRan, "javascriptUrlRan");
+ done();
+ }, 100); // Verify only one load event is fired on iframe
+};
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html
new file mode 100644
index 00000000000..fee300c5c48
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_remove_srcdoc.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>javascript: URL in iframe src, removing srcdoc</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+setup({single_test: true});
+let iframeLoaded = false;
+window.javascriptUrlRan = false;
+</script>
+<iframe srcdoc="srcdoc" src="javascript:(() => { parent.javascriptUrlRan = true; })()" onload="iframeLoaded = true; this.onload = assert_unreached;"></iframe>
+<script>
+onload = () => {
+ document.querySelector('iframe').removeAttribute('srcdoc');
+ assert_true(iframeLoaded, "iframeLoaded");
+ assert_false(javascriptUrlRan, "javascriptUrlRan");
+ step_timeout(() => {
+ assert_true(javascriptUrlRan, "javascriptUrlRan");
+ done();
+ }, 100); // Verify only one load event is fired on iframe
+};
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_navigate_javascript_url.htm b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_navigate_javascript_url.htm
new file mode 100644
index 00000000000..88867790e7d
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe_navigate_javascript_url.htm
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Navigate an iframe to a javascript: URL</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const tests = [
+ // url, expected_load_event
+ ['javascript:"foo"', true],
+ ['javascript:1', false],
+];
+for (const [url, expected_load_event] of tests) {
+ promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ const loaded = new Promise(resolve => { iframe.onload = resolve; });
+ document.body.append(iframe);
+ await loaded;
+ const secondLoad = new Promise((resolve, reject) => {
+ iframe.onload = () => {
+ expected_load_event ? resolve() : reject();
+ };
+ });
+ const timeout = new Promise((resolve, reject) => {
+ t.step_timeout(() => {
+ expected_load_event ? reject() : resolve();
+ }, 100);
+ });
+ iframe.contentWindow.location.href = url;
+ await Promise.race([secondLoad, timeout]);
+ }, `location.href = '${url}' should ${expected_load_event ? '' : 'not '}fire a load event`);
+}
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html
new file mode 100644
index 00000000000..df9eb374b5a
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html
@@ -0,0 +1,189 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>HTMLImageElement naturalWidth/naturalHeight behavior for SVG that lacks at least one natural dimension</title>
+<!-- Note: this test asserts a different expectation from what the HTML spec
+ requires, as of mid-2025 when this testcase is being written. The spec
+ behavior doesn't appear to be web-compatible for some of the cases here,
+ and issue https://github.com/whatwg/html/issues/11287 is filed on
+ addresing that. In the meantime, this test is named with ".tentative" to
+ indicate that it's not authoritative. -->
+<link rel="help" href="https://github.com/whatwg/html/issues/11287">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-naturalwidth-dev">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-width">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#density-corrected-intrinsic-width-and-height">
+<link rel="help" href="https://drafts.csswg.org/css-images/#natural-dimensions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.scroller {
+ /* We wrap all the test content in a scroller so that it doesn't push
+ * the textual test-results too far out of view.
+ */
+ border: 1px solid black;
+ height: 400px;
+ width: max-content;
+ overflow: scroll;
+}
+.container {
+ /* There are a few SVG images here that size so that their margin-box fills
+ * their containing block width. We define a specific size here so that we
+ * can then check for it (minus the margins) in the "data-width" attribute.
+ */
+ width: 740px;
+}
+img {
+ /* This styling is just cosmetic, to help visualize the images. */
+ border: 5px solid teal;
+ margin: 5px;
+ vertical-align: top;
+ display: block;
+ width: max-content;
+}
+</style>
+<div class="scroller">
+ <div class="container">
+<!-- FIRST PART OF TEST: No viewBox. Just a missing (or edge-casey, i.e.
+ negative or percent-valued) values, for the width and height attrs on the
+ root svg element in a SVG image. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
+ title="SVG image, no natural dimensions"
+ data-natural-width="300" data-natural-height="150">
+<!-- Note: percent values can't be resolved when determining natural
+ dimensions, so the exact percentage shouldn't matter. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%'></svg>"
+ title="SVG image, percengage natural dimensions"
+ data-natural-width="300" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%'></svg>"
+ title="SVG image, negative percengage natural dimensions"
+ data-natural-width="300" data-natural-height="150">
+<!-- If only one attribute is present, it should show up as a natural
+ dimension, without influencing the other natural dimension. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60'></svg>"
+ title="SVG image, with natural width"
+ data-natural-width="60" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60'></svg>"
+ title="SVG image, with natural height"
+ data-natural-width="300" data-natural-height="60">
+<!-- If either attribute is 0 or a negative length, it should show up as a
+ natural dimension: of 0. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0'></svg>"
+ title="SVG image, with natural width of 0"
+ data-natural-width="0" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0'></svg>"
+ title="SVG image, with natural height of 0"
+ data-natural-width="300" data-natural-height="0">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5'></svg>"
+ title="SVG image, with natural width being negative"
+ data-natural-width="0" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5'></svg>"
+ title="SVG image, with natural height being negative"
+ data-natural-width="300" data-natural-height="0">
+
+<!-- NEXT PART OF TEST: Same as above, but now with a viewBox that grants a
+ 3:1 aspect-ratio; whenever we know one natural dimension, that should
+ combine with the aspect ratio to produce the other natural dimension.
+
+ NOTE: for a few subtests here, the image ends up expanding to fill the
+ containing block's width, i.e. rendering at a larger size than its natural
+ size. In those cases, we include 'data-width' & 'data-height' attributes,
+ so that this test's JS can validate that img.width and img.height return
+ these expected larger values. (Otherwise, we expect img.width and
+ img.height to return the same values as img.naturalWidth and
+ img.naturalHeight). -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 200'></svg>"
+ title="SVG image, no natural dimensions, and aspect ratio from viewBox"
+ data-natural-width="300" data-natural-height="100"
+ data-width="720" data-height="240">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%' viewBox='0 0 600 200'></svg>"
+ title="SVG image, percengage natural dimensions, and aspect ratio from viewBox"
+ data-natural-width="300" data-natural-height="100"
+ data-width="720" data-height="240">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%' viewBox='0 0 600 200'></svg>"
+ title="SVG image, negative percengage natural dimensions, and aspect ratio from viewBox"
+ data-natural-width="300" data-natural-height="100"
+ data-width="720" data-height="240">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width, and aspect ratio from viewBox"
+ data-natural-width="60" data-natural-height="20">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural height, and aspect ratio from viewBox"
+ data-natural-width="180" data-natural-height="60">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width of 0, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural height of 0, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width being negative, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural height being negative, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+
+<!-- THIRD PART OF TEST: Check a degenerate 0-sized viewBox for some of the
+ cases; it should have no impact. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 0'></svg>"
+ title="SVG image, no natural dimensions, viewBox with 0 width/height"
+ data-natural-width="300" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 0'></svg>"
+ title="SVG image, no natural dimensions, viewBox with 0 width"
+ data-natural-width="300" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 10'></svg>"
+ title="SVG image, no natural dimensions, viewBox with 0 height"
+ data-natural-width="300" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 0'></svg>"
+ title="SVG image, with natural width, viewBox with 0 width/height"
+ data-natural-width="60" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 10 0'></svg>"
+ title="SVG image, with natural width, viewBox with 0 width"
+ data-natural-width="60" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 10'></svg>"
+ title="SVG image, with natural width, viewBox with 0 height"
+ data-natural-width="60" data-natural-height="150">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 0'></svg>"
+ title="SVG image, with natural height, viewBox with 0 width/height"
+ data-natural-width="300" data-natural-height="60">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 10 0'></svg>"
+ title="SVG image, with natural height, viewBox with 0 width"
+ data-natural-width="300" data-natural-height="60">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 10'></svg>"
+ title="SVG image, with natural height, viewBox with 0 height"
+ data-natural-width="300" data-natural-height="60">
+
+<!~- FINAL PART OF TEST: we have width/height/viewBox all specified on the
+ svg element. The width and height attrs should determine the natural
+ dimensions, with no impact from viewBox. -->
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width and height, and aspect ratio from viewBox"
+ data-natural-width="60" data-natural-height="60">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' height='0' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width and height of 0, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' height='-5' viewBox='0 0 600 200'></svg>"
+ title="SVG image, with natural width and height being negative, and aspect ratio from viewBox"
+ data-natural-width="0" data-natural-height="0">
+</div>
+</div>
+<script>
+setup({explicit_done:true});
+onload = function() {
+ Array.from(document.images).forEach(img => {
+ test(function() {
+ const expectedNaturalWidth = parseFloat(img.dataset.naturalWidth);
+ const expectedNaturalHeight = parseFloat(img.dataset.naturalHeight);
+ assert_equals(img.naturalWidth, expectedNaturalWidth, 'naturalWidth');
+ assert_equals(img.naturalHeight, expectedNaturalHeight, 'naturalHeight');
+
+ const expectedWidth = 'width' in img.dataset ?
+ parseFloat(img.dataset.width) : expectedNaturalWidth;
+ const expectedHeight = 'height' in img.dataset ?
+ parseFloat(img.dataset.height) : expectedNaturalHeight;
+ assert_equals(img.width, expectedWidth, 'width');
+ assert_equals(img.height, expectedHeight, 'height');
+
+ }, `${img.title}`);
+ });
+ done();
+};
+</script>
diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-object-element/object-javascript-url.html b/tests/wpt/tests/html/semantics/embedded-content/the-object-element/object-javascript-url.html
new file mode 100644
index 00000000000..79c3ff9c407
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/embedded-content/the-object-element/object-javascript-url.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>object - javascript: URL</title>
+<link rel="help" href="https://html.spec.whatwg.org/#the-object-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ // the steps to (re)determine what the object element represents
+ // fetches url, which results in a network error
+ // and thus "fallback".
+ promise_test(async function (t) {
+ const object = document.createElement('object');
+ object.data = 'javascript:"foo"';
+ object.onload = t.unreached_func('No load event expected');
+ document.body.append(object);
+ t.add_cleanup(() => { object.remove(); });
+ await new Promise(resolve => { t.step_timeout(resolve, 100); });
+ }, "javascript: in data attribute should do nothing");
+
+ function insertObjectNavigable(t) {
+ const object = document.createElement('object');
+ object.data = '/resources/blank.html';
+ document.body.append(object);
+ t.add_cleanup(() => { object.remove(); });
+ return object;
+ }
+
+ promise_test(async function (t) {
+ const object = insertObjectNavigable(t);
+ await new Promise(resolve => { object.onload = resolve; });
+ const loaded = new Promise(resolve => { object.onload = resolve; });
+ window[0].location.href = 'javascript:"test"';
+ await loaded;
+ }, 'location.href = \'javascript:"test"\' should fire a load event');
+
+ promise_test(async function (t) {
+ const object = insertObjectNavigable(t);
+ await new Promise(resolve => { object.onload = resolve; });
+ object.onload = t.unreached_func('No second load event expected');
+ window[0].location.href = 'javascript:1';
+ await new Promise(resolve => { t.step_timeout(resolve, 100); });
+ }, 'location.href = \'javascript:1\' should not fire a load event');
+</script>
diff --git a/tests/wpt/tests/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml b/tests/wpt/tests/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml
new file mode 100644
index 00000000000..c5f2a8811dd
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: datalist
+ files: "**"
diff --git a/tests/wpt/tests/html/semantics/forms/the-meter-element/WEB_FEATURES.yml b/tests/wpt/tests/html/semantics/forms/the-meter-element/WEB_FEATURES.yml
new file mode 100644
index 00000000000..944746a8eec
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-meter-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: meter
+ files: "**"
diff --git a/tests/wpt/tests/html/semantics/forms/the-progress-element/WEB_FEATURES.yml b/tests/wpt/tests/html/semantics/forms/the-progress-element/WEB_FEATURES.yml
new file mode 100644
index 00000000000..95c7b887c37
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-progress-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: progress
+ files: "**"
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-optgroup-arrow-keys.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-optgroup-arrow-keys.tentative.html
new file mode 100644
index 00000000000..00ba0e3a39b
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-optgroup-arrow-keys.tentative.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/417119055">
+<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/testdriver-actions.js"></script>
+
+<style>
+select, ::picker(select) {
+ appearance: base-select;
+}
+</style>
+
+<select>
+ <optgroup label=group1>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ </optgroup>
+ <optgroup label=group2>
+ <option class=three>three</option>
+ <option class=four>four</option>
+ </optgroup>
+ <optgroup label=group3>
+ <option class=five>five</option>
+ <option class=six>six</option>
+ </optgroup>
+</select>
+
+<script>
+const ArrowUp = '\uE013';
+const ArrowDown = '\uE015';
+const Space = ' ';
+
+function sendKey(key) {
+ return (new test_driver.Actions()
+ .keyDown(key)
+ .keyUp(key))
+ .send();
+}
+
+promise_test(async () => {
+ const select = document.querySelector('select');
+ const options = [
+ document.querySelector('.one'),
+ document.querySelector('.two'),
+ document.querySelector('.three'),
+ document.querySelector('.four'),
+ document.querySelector('.five'),
+ document.querySelector('.six')
+ ];
+
+ assert_equals(getComputedStyle(select).appearance, 'base-select',
+ 'appearance:base-select must be supported to run this test.');
+
+ select.focus();
+ await sendKey(Space);
+ assert_true(select.matches(':open'),
+ 'Space should open picker.');
+ assert_equals(document.activeElement, options[0],
+ 'First option should be initially focused.');
+
+ for (let i = 1; i < 6; i++) {
+ await sendKey(ArrowDown);
+ assert_equals(document.activeElement, options[i],
+ `Option ${i} should be focused after ArrowDown.`);
+ }
+
+ for (let i = 4; i > -1; i--) {
+ await sendKey(ArrowUp);
+ assert_equals(document.activeElement, options[i],
+ `Option ${i} should be focused after ArrowUp.`);
+ }
+}, 'Keyboard navigation forwards and backwards should visit each option with optgroups.');
+</script>
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
index 0c6972bcab5..5fe50d50775 100644
--- a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html
@@ -104,6 +104,14 @@
</div>
</select>
+<select class=test
+ data-description='Input tags should close select when directly inside an <option>'
+ data-expect='<option></option>'>
+ <option>
+ <input>
+ </option>
+</select>
+
<div id=afterlast>
keep this div after the last test case
</div>
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html
new file mode 100644
index 00000000000..45f2ff78139
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent-mutations.tentative.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+select, ::picker(select) {
+ appearance: base-select;
+}
+</style>
+
+<div id=target>
+ <script>
+ window.selectedcontentRecords = [];
+ window.selectedcontentObserver = new MutationObserver(mutations => {
+ window.selectedcontentRecords = window.selectedcontentRecords.concat(mutations);
+ });
+ const config = {attributes: true, childList: true, subtree: true};
+ window.selectedcontentObserver.observe(document.getElementById('target'), config);
+ </script>
+
+ <select>
+ <button>
+ <selectedcontent></selectedcontent>
+ </button>
+ <option><span>span</span> one</option>
+ <option><span>span</span> two</option>
+ <option selected><span>span</option> three</option>
+ </select>
+</div>
+
+<script>
+function getNodeRepresentation(node) {
+ if (!node) {
+ return 'null';
+ }
+ switch (node.nodeType) {
+ case Node.ELEMENT_NODE:
+ let representation = node.tagName.toLowerCase();
+ if (node.id) {
+ representation += `#${node.id}`;
+ }
+ if (node.classList && node.classList.length > 0) {
+ representation += `.${Array.from(node.classList).join('.')}`;
+ }
+ return representation;
+ case Node.TEXT_NODE:
+ const text = node.textContent.trim();
+ return `#text: "${text.length > 50 ? text.substring(0, 47) + '...' : text}"`;
+ case Node.COMMENT_NODE:
+ return '';
+ default:
+ return `[Node type ${node.nodeType}]`;
+ }
+}
+
+function mutationRecordToString(record) {
+ if (!record) {
+ return '[Invalid MutationRecord]';
+ }
+
+ const targetStr = getNodeRepresentation(record.target);
+ let summary = `Type: ${record.type} | Target: ${targetStr}`;
+
+ switch (record.type) {
+ case 'attributes':
+ const attrName = record.attributeName;
+ const oldValue = record.oldValue !== null ? `"${record.oldValue}"` : 'null';
+ const newValue = record.target.getAttribute(attrName);
+ const newValueStr = newValue !== null ? `"${newValue}"` : 'null';
+ summary += ` | Attribute: '${attrName}' changed from ${oldValue} to ${newValueStr}`;
+ if (record.attributeNamespace) {
+ summary += ` (Namespace: ${record.attributeNamespace})`;
+ }
+ break;
+
+ case 'characterData':
+ const oldText = record.oldValue !== null ? `"${record.oldValue}"` : 'null';
+ const newText = record.target.textContent !== null ? `"${record.target.textContent}"` : 'null';
+ summary += ` | Data changed from ${oldText} to ${newText}`;
+ break;
+
+ case 'childList':
+ if (record.addedNodes.length > 0) {
+ const added = Array.from(record.addedNodes).map(getNodeRepresentation).join(', ');
+ summary += ` | Added: [${added}]`;
+ }
+ if (record.removedNodes.length > 0) {
+ const removed = Array.from(record.removedNodes).map(getNodeRepresentation).join(', ');
+ summary += ` | Removed: [${removed}]`;
+ }
+ if (record.previousSibling) {
+ summary += ` | After: ${getNodeRepresentation(record.previousSibling)}`;
+ }
+ if (record.nextSibling) {
+ summary += ` | Before: ${getNodeRepresentation(record.nextSibling)}`;
+ }
+ break;
+
+ default:
+ summary += ' | [Unknown mutation type]';
+ break;
+ }
+
+ return summary;
+}
+
+function convertMutationRecords(records) {
+ const output = [];
+ for (const record of records) {
+ output.push(mutationRecordToString(record));
+ }
+ return output;
+}
+
+test(() => {
+ const expectedMutations = [
+ "Type: childList | Target: div#target | Added: [#text: \"\"] | After: script",
+ "Type: childList | Target: div#target | Added: [select] | After: #text: \"\"",
+ "Type: childList | Target: select | Added: [#text: \"\"]",
+ "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
+ "Type: childList | Target: button | Added: [#text: \"\"]",
+ "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
+ "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
+ "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
+ "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
+ "Type: childList | Target: option | Added: [span]",
+ "Type: childList | Target: span | Added: [#text: \"span\"]",
+ "Type: childList | Target: option | Added: [#text: \"one\"] | After: span",
+ "Type: childList | Target: selectedcontent | Added: [span, #text: \"one\"]",
+ "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
+ "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
+ "Type: childList | Target: option | Added: [span]",
+ "Type: childList | Target: span | Added: [#text: \"span\"]",
+ "Type: childList | Target: option | Added: [#text: \"two\"] | After: span",
+ "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
+ "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
+ "Type: childList | Target: selectedcontent | Removed: [span, #text: \"one\"]",
+ "Type: childList | Target: option | Added: [span]",
+ "Type: childList | Target: span | Added: [#text: \"span\"]",
+ "Type: childList | Target: selectedcontent | Added: [span]",
+ "Type: childList | Target: select | Added: [#text: \"three\"] | After: option",
+ "Type: childList | Target: div#target | Added: [#text: \"\"] | After: select"
+ ];
+ assert_array_equals(convertMutationRecords(window.selectedcontentRecords), expectedMutations);
+}, 'MutationObserver records during parsing of <select> with <selectedcontent>');
+</script>
diff --git a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent.tentative.html b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent.tentative.html
index d3299051537..ce298adc23e 100644
--- a/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent.tentative.html
+++ b/tests/wpt/tests/html/semantics/forms/the-select-element/customizable-select/selectedcontent.tentative.html
@@ -7,7 +7,7 @@
<script src="/resources/testdriver-vendor.js"></script>
<style>
-select, select::picker(select) {
+select, ::picker(select) {
appearance: base-select;
}
</style>
@@ -92,8 +92,6 @@ promise_test(async () => {
optionOne.remove();
assert_equals(selectedcontent.innerHTML, '',
'The content of <selectedcontent> should be cleared if there is no selected <option>.');
-
- // TODO(crbug.com/336844298): Add tests for mutation records during parsing
}, 'The <selectedcontent> element should reflect the HTML contents of the selected <option>.');
</script>
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-details-element/details-toggle-source.tentative.html b/tests/wpt/tests/html/semantics/interactive-elements/the-details-element/details-toggle-source.tentative.html
new file mode 100644
index 00000000000..1a571f54414
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-details-element/details-toggle-source.tentative.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9111">
+<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/testdriver-actions.js"></script>
+<script src="../../popovers/resources/toggle-event-source-test.js"></script>
+
+<button id=commandsource commandfor=details command=toggle>command source</button>
+<details id=details>
+ <summary>summary</summary>
+ details
+</details>
+
+<details id=detailsWithoutSummary>
+ details without summary
+</details>
+
+<script>
+const details = document.getElementById('details');
+const detailsWithoutSummary = document.getElementById('detailsWithoutSummary');
+const summary = details.querySelector('summary');
+const commandsource = document.getElementById('commandsource');
+
+async function click(element) {
+ // Click halfway up the element to click the activatable summary instead of
+ // the details.
+ const height = element.getBoundingClientRect().height;
+ return (new test_driver.Actions()
+ .pointerMove(0, -height / 2, {origin: element})
+ .pointerDown()
+ .pointerUp())
+ .send();
+}
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on <details> elements: details.open.',
+ target: details,
+ openFunc: async () => details.open = true,
+ closeFunc: async () => details.open = false,
+ openSource: null,
+ closeSource: null,
+ skipBeforetoggle: true
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on <details> elements: click summary.',
+ target: details,
+ openFunc: async () => summary.click(),
+ closeFunc: async () => summary.click(),
+ openSource: null,
+ closeSource: null,
+ skipBeforetoggle: true
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on <details> elements: click details.',
+ target: detailsWithoutSummary,
+ openFunc: async () => await click(detailsWithoutSummary),
+ closeFunc: async () => await click(detailsWithoutSummary),
+ openSource: null,
+ closeSource: null,
+ skipBeforetoggle: true
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on <details> elements: command invokers.',
+ target: details,
+ openFunc: async () => commandsource.click(),
+ closeFunc: async () => commandsource.click(),
+ openSource: commandsource,
+ closeSource: commandsource,
+ skipBeforetoggle: true
+});
+</script>
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-corner-cases.html b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-corner-cases.html
index 06a90844154..511acaccef3 100644
--- a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-corner-cases.html
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-corner-cases.html
@@ -36,10 +36,17 @@
assert_true(dialog.matches(':open'),'Should be open now (pseudo)');
}
+ function awaitEvent(el, type, signal) {
+ const {promise, resolve} = Promise.withResolvers();
+ el.addEventListener(type, resolve, { once: true, signal });
+ return promise
+ }
+
const changeMethods = [
{
description: 'focusin removes and reinserts',
setup: (openMethod,signal) => {
+ outside.focus();
document.body.addEventListener('focusin',(e) => {
if (!dialog.contains(e.target)) {
const position = dialog.nextElementSibling;
@@ -47,21 +54,29 @@
document.body.insertBefore(dialog,position);
}
}, {signal});
+
+ // Await for the close event before asserting.
+ return awaitEvent(dialog, 'close', signal)
}
},
{
description: 'focusin closes dialog',
setup: (openMethod,signal) => {
+ outside.focus();
document.body.addEventListener('focusin',(e) => {
if (!dialog.contains(e.target)) {
dialog.close();
}
}, {signal});
+
+ // Await for the close event before asserting.
+ return awaitEvent(dialog, 'close', signal)
}
},
{
description: 'focusin calls showModal',
setup: (openMethod,signal) => {
+ outside.focus();
document.body.addEventListener('focusin',(e) => {
if (!dialog.contains(e.target)) {
try {
@@ -69,6 +84,11 @@
} catch {}
}
}, {signal});
+
+ // Await for the close event before asserting.
+ return awaitEvent(dialog, 'close', signal)
+ },
+ respondsTo(openMethod) {
// Since the closing steps will trigger another call to showModal
// in this case, before we're done with closing, we should expect
// that the ESC/light dismiss still results in a showing modal, if it
@@ -77,19 +97,33 @@
}
},
{
- description: 'requestIdleCallback calls showModal',
+ description: 'beforetoggle closes dialog',
setup: (openMethod,signal) => {
- requestIdleCallback(() => {
- try {
- dialog.showModal();
- } catch {}
- });
+ dialog.addEventListener('beforetoggle', (e) => {
+ if (e.newState == "open") {
+ dialog.close()
+ }
+ }, {signal});
+
+ // Await for the close event before asserting.
+ return awaitEvent(dialog, 'close', signal)
}
},
{
- description: 'beforetoggle closes dialog',
+ description: 'requestIdleCallback calls showModal',
setup: (openMethod,signal) => {
- dialog.addEventListener('beforetoggle',() => dialog.close(), {signal});
+ return new Promise(resolve => {
+ requestIdleCallback(() => {
+ try {
+ dialog.showModal();
+ } catch {
+ } finally {
+ resolve();
+ }
+ });
+ // Wait for one more tick to reduce racey behaviour between
+ // requestIdleCallback and task queue event dispatch
+ }).then(() => waitForRender());
}
},
{
@@ -104,51 +138,64 @@
dialog.showModal();
} catch {}
}, {signal});
+
+ // Await for the close event before asserting.
+ return awaitEvent(dialog, 'close', signal)
}
},
];
function runTest(openMethod, changeMethod) {
- promise_test(async (t) => {
+ function setup(t) {
assert_false(dialog.open,'setup');
- assert_false(dialog.matches(':open'));
+ assert_false(dialog.matches(':open'), 'Dialog should start the test closed');
+ assert_equals(dialog.closedBy, "any", 'Dialog should be closedby=any');
- const controller = new AbortController();
+ const signal = t.get_signal();
t.add_cleanup(() => {
- controller.abort();
dialog.close();
});
- const expectResponds = changeMethod.setup(openMethod,controller.signal) ?? true;
+
+ const step = changeMethod.setup(openMethod, signal);
// Open the dialog
openDialog(openMethod);
+ return step;
+ }
+
+ promise_test(async (t) => {
+ const step = setup(t);
+
// Try hitting ESC
const ESC = '\uE00C';
- const close_fired = new Promise(resolve => {
- dialog.addEventListener('close', resolve, { once: true })
- });
await test_driver.send_keys(document.documentElement,ESC);
- if (expectResponds) {
- await close_fired;
- } else {
- await waitForRender();
- }
+
+ await step;
+
const respondsToEsc = !dialog.open;
assert_equals(!dialog.matches(':open'),respondsToEsc,':open should match dialog.open');
- dialog.close();
+
+ const shouldRespond = changeMethod.respondsTo?.(openMethod) ?? true;
+
+ assert_equals(respondsToEsc, shouldRespond, 'Dialog should respond to ESC');
+ }, `Pressing escape, when ${changeMethod.description}, ${openMethod}`);
+
+ promise_test(async (t) => {
+ const step = setup(t);
// Try clicking outside
- openDialog(openMethod);
await clickOn(outside);
+
+ await step;
+
const respondsToLightDismiss = !dialog.open;
assert_equals(!dialog.matches(':open'),respondsToLightDismiss,':open should match dialog.open');
- dialog.close();
- // See if expectations match
- assert_equals(respondsToEsc,expectResponds,`Dialog ${expectResponds ? "should" : "should NOT"} respond to ESC`);
- assert_equals(respondsToLightDismiss,expectResponds,`Dialog ${expectResponds ? "should" : "should NOT"} respond to light dismiss`);
- }, `${changeMethod.description}, ${openMethod}`);
+ const shouldRespond = changeMethod.respondsTo?.(openMethod) ?? true;
+
+ assert_true(respondsToLightDismiss, shouldRespond, 'Dialog respond to light dismiss');
+ }, `Clicking outside, when ${changeMethod.description}, ${openMethod}`);
}
// Run tests
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-show-stacked.html b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-show-stacked.html
new file mode 100644
index 00000000000..30021a79be3
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-closedby-show-stacked.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" href="mailto:wpt@keithcirkel.co.uk">
+<link rel=help href="https://html.spec.whatwg.org/multipage/interactive-elements.html#dialog-light-dismiss">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="../../popovers/resources/popover-utils.js"></script>
+
+<button id="outside">Outside</button>
+<dialog id=outer closedby="closerequest">
+ <dialog id=inner>
+ </dialog>
+</dialog>
+
+<script>
+function awaitEvent(el, type, signal) {
+ const {promise, resolve} = Promise.withResolvers();
+ el.addEventListener(type, resolve, { once: true, signal });
+ return promise
+}
+
+promise_test(async (t) => {
+ inner.setAttribute('closedby', 'none');
+ outer.show();
+ // Need to ensure that CloseWatcher does not collapse
+ // both of these shows into a single CloseWatcher group.
+ await test_driver.bless();
+ inner.show();
+ assert_true(inner.open, "The inner dialog is open");
+ assert_true(outer.open, "The outer dialog is open");
+
+ let cancelFired = false;
+ inner.addEventListener('cancel', () => cancelFired = true, t.get_signal());
+ outer.addEventListener('cancel', () => cancelFired = true, t.get_signal());
+
+ const ESC = '\uE00C';
+ await test_driver.send_keys(document.documentElement,ESC);
+
+ assert_false(cancelFired, "The cancel event was not fired");
+ assert_true(inner.open, "The inner dialog is still open");
+ assert_true(outer.open, "The outer dialog is still open");
+},'With an inner closedby=none, the outer & inner dialogs stays open when Esc is pressed');
+
+promise_test(async (t) => {
+ inner.setAttribute('closedby', 'none');
+ outer.show();
+ // Need to ensure that CloseWatcher does not collapse
+ // both of these shows into a single CloseWatcher group.
+ await test_driver.bless();
+ inner.show();
+ assert_true(inner.open, "The inner dialog is open");
+ assert_true(outer.open, "The outer dialog is open");
+
+ let cancelFired = false;
+ inner.addEventListener('cancel', () => cancelFired = true, t.get_signal());
+ outer.addEventListener('cancel', () => cancelFired = true, t.get_signal());
+
+ // Try clicking outside
+ await clickOn(outside);
+
+ assert_false(cancelFired, "The cancel event was not fired");
+ assert_true(inner.open, "The inner dialog is open");
+ assert_true(outer.open, "The outer dialog is open");
+},'With an inner closedby=none, the outer & inner dialogs stays open when clicked outside');
+
+promise_test(async (t) => {
+ inner.setAttribute('closedby', 'any');
+ outer.show();
+ // Need to ensure that CloseWatcher does not collapse
+ // both of these shows into a single CloseWatcher group.
+ await test_driver.bless();
+ inner.show();
+ assert_true(inner.open, "The inner dialog is open");
+ assert_true(outer.open, "The outer dialog is open");
+
+ let innerCancelled = false;
+ let outerCancelled = false;
+ inner.addEventListener('cancel', () => innerCancelled = true, t.get_signal());
+ outer.addEventListener('cancel', () => outerCancelled = true, t.get_signal());
+
+ let innerClosed = awaitEvent(inner, 'close', t.get_signal());
+
+ // Try clicking outside
+ const ESC = '\uE00C';
+ await test_driver.send_keys(document.documentElement,ESC);
+
+ await innerClosed;
+
+ assert_false(outerCancelled, "The outer cancel event was not fired");
+ assert_true(innerCancelled, "The inner cancel event was fired");
+
+ assert_false(inner.open, "The inner dialog is NOT open");
+ assert_true(outer.open, "The outer dialog is open");
+},'With an inner closedby=any, the outer dialog stays open but the inner dialogs should close, when Esc is pressed');
+
+promise_test(async (t) => {
+ inner.setAttribute('closedby', 'any');
+ outer.show();
+ // Need to ensure that CloseWatcher does not collapse
+ // both of these shows into a single CloseWatcher group.
+ await test_driver.bless();
+ inner.show();
+ assert_true(inner.open, "The inner dialog is open");
+ assert_true(outer.open, "The outer dialog is open");
+
+ let innerCancelled = false;
+ let outerCancelled = false;
+ inner.addEventListener('cancel', () => innerCancelled = true, t.get_signal());
+ outer.addEventListener('cancel', () => outerCancelled = true, t.get_signal());
+
+ let innerClosed = awaitEvent(inner, 'close', t.get_signal());
+
+ // Try clicking outside
+ await clickOn(outside);
+
+ await innerClosed;
+
+ assert_false(outerCancelled, "The outer cancel event was not fired");
+ assert_true(innerCancelled, "The inner cancel event was fired");
+
+ assert_false(inner.open, "The inner dialog is NOT open");
+ assert_true(outer.open, "The outer dialog is open");
+},'With an inner closedby=any, the outer dialog stays open but the inner dialogs should close, when clicked outside');
+</script>
diff --git a/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-toggle-source.tentative.html b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-toggle-source.tentative.html
new file mode 100644
index 00000000000..7e6fe25dabf
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/interactive-elements/the-dialog-element/dialog-toggle-source.tentative.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9111">
+<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/testdriver-actions.js"></script>
+<script src="../../popovers/resources/toggle-event-source-test.js"></script>
+
+<button id=showmodalbutton commandfor=dialog command=show-modal>show modal</button>
+<dialog id=dialog>
+ dialog
+ <button id=closebutton commandfor=dialog command=close>close</button>
+</dialog>
+
+<script>
+const showmodalbutton = document.getElementById('showmodalbutton');
+const dialog = document.getElementById('dialog');
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on <dialog> elements: dialog.showModal().',
+ target: dialog,
+ openFunc: async () => dialog.showModal(),
+ closeFunc: async () => dialog.close(),
+ openSource: null,
+ closeSource: null
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.soruce on <dialog> elements: command button.',
+ target: dialog,
+ openFunc: async () => showmodalbutton.click(),
+ closeFunc: async () => closebutton.click(),
+ openSource: showmodalbutton,
+ closeSource: closebutton
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.soruce on <dialog> elements: open with showModal, close with button.',
+ target: dialog,
+ openFunc: async () => dialog.showModal(),
+ closeFunc: async () => closebutton.click(),
+ openSource: null,
+ closeSource: closebutton
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.soruce on <dialog> elements: open with button, close with dialog.close().',
+ target: dialog,
+ openFunc: async () => showmodalbutton.click(),
+ closeFunc: async () => dialog.close(),
+ openSource: showmodalbutton,
+ closeSource: null
+});
+</script>
diff --git a/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest-ref.html b/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest-ref.html
deleted file mode 100644
index aa5ffe07a95..00000000000
--- a/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest-ref.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<body>
- <div>
- The permission element should either be display 'none' or 'inline-block'
- </div>
-
-<style>
- #id1 {
- display: inline-block;
- }
-</style>
-
-<permission id="id1" type="geolocation"></permission>
-<span>After element</span>
-</body> \ No newline at end of file
diff --git a/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html b/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html
deleted file mode 100644
index e4288cae3b2..00000000000
--- a/tests/wpt/tests/html/semantics/permission-element/display-css-property-reftest.tentative.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<link rel="match" href="display-css-property-reftest-ref.html">
-<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
-<body>
- <div>
- The permission element should either be display 'none' or 'inline-block'
- </div>
-
-<style>
- #id1 {
- display: flex;
- }
- #id2 {
- display: none;
- }
-</style>
-
-<permission id="id1" type="geolocation"></permission>
-<permission id="id2" type="camera"></permission>
-<span>After element</span>
-</body> \ No newline at end of file
diff --git a/tests/wpt/tests/html/semantics/permission-element/display-css-property.tentative.html b/tests/wpt/tests/html/semantics/permission-element/display-css-property.tentative.html
deleted file mode 100644
index b87b6aa9e04..00000000000
--- a/tests/wpt/tests/html/semantics/permission-element/display-css-property.tentative.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body>
-<!--
- 'display' should either be 'none' or 'inline-block'
--->
-<style>
- #id1 {
- display: inline-block;
- }
- #id2 {
- display: block;
- }
- #id3 {
- display: none;
- }
-</style>
-
-
-<permission id="id1" type="geolocation"></permission>
-<permission id="id2" type="camera"></permission>
-<permission id="id3" type="microphone"></permission>
-
-<script>
- test(function(){
- assert_equals(getComputedStyle(document.getElementById("id1")).display, "inline-block", "'inline-block' should be kept");
- assert_equals(getComputedStyle(document.getElementById("id2")).display, "inline-block", "'block' should be changed to 'inline-block'");
- assert_equals(getComputedStyle(document.getElementById("id3")).display, "none", "'none' should be kept");
- }, "'display' should be either 'inline-block' or 'none'");
-</script>
-</body> \ No newline at end of file
diff --git a/tests/wpt/tests/html/semantics/popovers/popover-toggle-source.tentative.html b/tests/wpt/tests/html/semantics/popovers/popover-toggle-source.tentative.html
new file mode 100644
index 00000000000..00ced8f7070
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/popovers/popover-toggle-source.tentative.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9111">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/toggle-event-source-test.js"></script>
+
+<button id=popoversource popovertarget=popover>popovertarget source</button>
+<button id=commandsource commandfor=popover command=show-popover>command source</button>
+<div id=popover popover=auto>
+ popover
+ <button id=popoversourcehide popovertarget=popover>popovertarget source</button>
+ <button id=commandsourcehide commandfor=popover command=hide-popover>command source</button>
+</div>
+
+<script>
+const popoversource = document.getElementById('popoversource');
+const popoversourcehide = document.getElementById('popoversourcehide');
+const commandsource = document.getElementById('commandsource');
+const commandsourcehide = document.getElementById('commandsourcehide');
+const popover = document.getElementById('popover');
+
+let beforetoggleEvent = null;
+let toggleEvent = null;
+popover.addEventListener('beforetoggle', event => beforetoggleEvent = event);
+popover.addEventListener('toggle', event => toggleEvent = event);
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: showPopover() without source.',
+ target: popover,
+ openFunc: async () => popover.showPopover(),
+ closeFunc: async () => popover.hidePopover(),
+ openSource: null,
+ closeSource: null
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: showPopover() with source.',
+ target: popover,
+ openFunc: async () => popover.showPopover({source: popoversource}),
+ closeFunc: async () => popover.hidePopover(),
+ openSource: popoversource,
+ closeSource: null
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: Calling click() on a popovertarget button.',
+ target: popover,
+ openFunc: async () => popoversource.click(),
+ closeFunc: async () => popoversourcehide.click(),
+ openSource: popoversource,
+ closeSource: popoversourcehide
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: Calling click() on a command button.',
+ target: popover,
+ openFunc: async () => commandsource.click(),
+ closeFunc: async () => commandsourcehide.click(),
+ openSource: commandsource,
+ closeSource: commandsourcehide
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: showPopover() then popovertarget button.',
+ target: popover,
+ openFunc: async () => popover.showPopover(),
+ closeFunc: async () => popoversourcehide.click(),
+ openSource: null,
+ closeSource: popoversourcehide
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: showPopover(invoker) then popovertarget button.',
+ target: popover,
+ openFunc: async () => popover.showPopover({source: popoversource}),
+ closeFunc: async () => popoversourcehide.click(),
+ openSource: popoversource,
+ closeSource: popoversourcehide
+});
+
+createToggleEventSourceTest({
+ description: 'ToggleEvent.source on popover elements: popovertarget button then hidePopover().',
+ target: popover,
+ openFunc: async () => popoversource.click(),
+ closeFunc: async () => popover.hidePopover(),
+ openSource: popoversource,
+ closeSource: null
+});
+</script>
diff --git a/tests/wpt/tests/html/semantics/popovers/resources/toggle-event-source-test.js b/tests/wpt/tests/html/semantics/popovers/resources/toggle-event-source-test.js
new file mode 100644
index 00000000000..93ecd270fac
--- /dev/null
+++ b/tests/wpt/tests/html/semantics/popovers/resources/toggle-event-source-test.js
@@ -0,0 +1,76 @@
+function createToggleEventSourceTest({
+ description,
+ target,
+ openFunc,
+ closeFunc,
+ openSource,
+ closeSource,
+ skipBeforetoggle}) {
+ promise_test(async () => {
+ let beforetoggleEvent = null;
+ let beforetoggleDuplicate = false;
+ let toggleEvent = null;
+ let toggleDuplicate = false;
+ target.addEventListener('beforetoggle', event => {
+ if (beforetoggleEvent) {
+ beforetoggleDuplicate = true;
+ }
+ beforetoggleEvent = event;
+ });
+ target.addEventListener('toggle', event => {
+ if (toggleEvent) {
+ toggleDuplicate = true;
+ }
+ toggleEvent = event;
+ });
+
+ await openFunc();
+ await new Promise(requestAnimationFrame);
+ await new Promise(requestAnimationFrame);
+ if (!skipBeforetoggle) {
+ assert_true(!!beforetoggleEvent,
+ 'An opening beforetoggle event should have been fired.');
+ assert_false(beforetoggleDuplicate,
+ 'Only one opening beforetoggle event should have been fired.');
+ assert_equals(beforetoggleEvent.newState, 'open',
+ 'beforetoggle newState should be open.');
+ assert_equals(beforetoggleEvent.source, openSource,
+ 'Opening beforetoggle.source.');
+ }
+ assert_true(!!toggleEvent,
+ 'An opening toggle event should have been fired.');
+ assert_false(toggleDuplicate,
+ 'Only one opening toggle event should have been fired.');
+ assert_equals(toggleEvent.newState, 'open',
+ 'toggle newstate should be open.');
+ assert_equals(toggleEvent.source, openSource,
+ 'Opening toggle.source.');
+ beforetoggleEvent = null;
+ beforetoggleDuplicate = false;
+ toggleEvent = null;
+ toggleDuplicate = false;
+
+ await closeFunc();
+ await new Promise(requestAnimationFrame);
+ await new Promise(requestAnimationFrame);
+
+ if (!skipBeforetoggle) {
+ assert_true(!!beforetoggleEvent,
+ 'A closing beforetoggle event should have been fired.');
+ assert_false(beforetoggleDuplicate,
+ 'Only one closing beforetoggle event should have been fired.');
+ assert_equals(beforetoggleEvent.newState, 'closed',
+ 'beforetoggle newState should be closed.');
+ assert_equals(beforetoggleEvent.source, closeSource,
+ 'Closing beforetoggle.source.');
+ }
+ assert_true(!!toggleEvent,
+ 'A closing toggle event should have been fired.');
+ assert_false(toggleDuplicate,
+ 'Only one closing toggle event should have been fired.');
+ assert_equals(toggleEvent.newState, 'closed',
+ 'toggle newstate should be closed.');
+ assert_equals(toggleEvent.source, closeSource,
+ 'Closing toggle.source.');
+ }, description);
+}
diff --git a/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-keyboard-behavior.tentative.html b/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-keyboard-behavior.tentative.html
index 7040019e750..997c2b93825 100644
--- a/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-keyboard-behavior.tentative.html
+++ b/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-keyboard-behavior.tentative.html
@@ -110,9 +110,7 @@ allInterestTargetElements.forEach(el => {
let events = [];
function addListeners(t,element) {
- const controller = new AbortController();
- const signal = controller.signal;
- t.add_cleanup(() => controller.abort());
+ const signal = t.get_signal();
element.addEventListener('interest',(e) => events.push(`${e.target.id} interest`),{signal});
element.addEventListener('loseinterest',(e) => events.push(`${e.target.id} loseinterest`),{signal});
}
@@ -147,10 +145,16 @@ allInterestTargetElements.forEach(el => {
await focusOn(el);
assert_array_equals(events,['target interest'],'setup');
verifyInterest(el,`After show interest in ${el.id}`);
- target.addEventListener('loseinterest',(e) => e.preventDefault(),{once: true});
+ const signal = t.get_signal();
+ let shouldCancelLoseInterest = true;
+ target.addEventListener('loseinterest',(e) => {
+ if (shouldCancelLoseInterest) {
+ e.preventDefault();
+ }
+ },{signal});
await focusOn(another);
- assert_array_equals(events,['target interest','target loseinterest','anothertarget interest'],
- 'the loseinterest listener should fire, and anothertarget should still get interest');
+ assert_array_equals(events,['target interest','target loseinterest','anothertarget interest','target loseinterest'],
+ 'the loseinterest listener should fire but get cancelled, anothertarget should still get interest, and that should close the first target popover firing another loseinterest');
events = [];
verifyInterest([el,another],`${el.id} should still have interest because loseinterest was cancelled`);
assert_false(target.matches(':popover-open'),'anothertarget popover opens, closing target');
@@ -159,6 +163,7 @@ allInterestTargetElements.forEach(el => {
assert_array_equals(events,['anothertarget loseinterest'],'Lose interest hot key on focused element loses just interest in that element');
assert_false(target.matches(':popover-open'));
assert_false(anothertarget.matches(':popover-open'));
+ shouldCancelLoseInterest = false;
await focusOn(el);
await sendLoseInterestHotkey();
assert_array_equals(events,['anothertarget loseinterest','target loseinterest'],'Now both lost interest');
diff --git a/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-pseudo-classes.tentative.html b/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-pseudo-classes.tentative.html
index 7cd50ebfe20..924c4d5fbc8 100644
--- a/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-pseudo-classes.tentative.html
+++ b/tests/wpt/tests/html/semantics/the-button-element/interest-target/interesttarget-pseudo-classes.tentative.html
@@ -128,6 +128,28 @@ promise_test(async (t) => {
promise_test(async (t) => {
checkPseudos(invoker,target,false,false,false,false,'initial');
await focusOn(invoker);
+ checkPseudos(invoker,target,true,true,true,true,'focusing invoker shows partial interest');
+ invoker.setAttribute('style',`interest-target-delay: 10000s`);
+ await hoverOver(target);
+ checkPseudos(invoker,target,false,true,false,true,'invoker now has full interest');
+ assert_equals(document.activeElement,invoker,'focus does not move in this case');
+ await do_cleanup();
+},'Hovering the popover confers "full interest", without any delays');
+
+promise_test(async (t) => {
+ checkPseudos(invoker,target,false,false,false,false,'initial');
+ await focusOn(invoker);
+ checkPseudos(invoker,target,true,true,true,true,'focusing invoker shows partial interest');
+ invoker.setAttribute('style',`interest-target-delay: 10000s`);
+ await hoverOver(invoker);
+ checkPseudos(invoker,target,false,true,false,true,'invoker now has full interest');
+ assert_equals(document.activeElement,invoker,'focus does not move in this case');
+ await do_cleanup();
+},'Hovering the invoker confers "full interest", without any delays');
+
+promise_test(async (t) => {
+ checkPseudos(invoker,target,false,false,false,false,'initial');
+ await focusOn(invoker);
await sendShowInterestHotkey();
checkPseudos(invoker,target,false,true,false,true,'invoker now has full interest');
await sendTab();
@@ -152,6 +174,27 @@ promise_test(async (t) => {
await do_cleanup();
},`Lose interest hotkey works`);
+promise_test(async (t) => {
+ checkPseudos(invoker,target,false,false,false,false,'initial');
+ await focusOn(invoker);
+ checkPseudos(invoker,target,true,true,true,true,'focusing invoker shows partial interest');
+ invoker.setAttribute('style',`interest-target-delay: 10000s`);
+ target.hidePopover();
+ checkPseudos(invoker,target,false,false,false,false,'closing the popover loses interest');
+ assert_equals(document.activeElement,invoker,'focus does not move');
+ await do_cleanup();
+},'Closing the target popover loses interest, without any delays (keyboard activation)');
+
+promise_test(async (t) => {
+ checkPseudos(invoker,target,false,false,false,false,'initial');
+ await hoverOver(invoker);
+ checkPseudos(invoker,target,false,true,false,true,'hovering invoker shows full interest (and not partial interest)');
+ invoker.setAttribute('style',`interest-target-delay: 10000s`);
+ target.hidePopover();
+ checkPseudos(invoker,target,false,false,false,false,'closing the popover loses interest');
+ await do_cleanup();
+},'Closing the target popover loses interest, without any delays (mouse activation)');
+
const invokerDelayMs = 100; // The CSS delay setting.
const hoverWaitTime = 200; // How long to wait to cover the delay for sure.
promise_test(async (t) => {
diff --git a/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/initial-color.html.ini b/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/initial-color.html.ini
new file mode 100644
index 00000000000..5759f761c6f
--- /dev/null
+++ b/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/initial-color.html.ini
@@ -0,0 +1,3 @@
+[initial-color.html]
+ expected:
+ if product == "safari": [PASS, CRASH]
diff --git a/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini b/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini
index 87d8cd43c41..36a803d3ed7 100644
--- a/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini
+++ b/tests/wpt/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini
@@ -1,4 +1,3 @@
[non-local-ports.sub.window.html]
[Fetch from http-public to local http fails.]
- expected:
- if product != "chrome": FAIL
+ expected: FAIL
diff --git a/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini b/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini
new file mode 100644
index 00000000000..2feff7063f8
--- /dev/null
+++ b/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/bless.html.ini
@@ -0,0 +1,6 @@
+[bless.html]
+ expected:
+ if product == "safari": [OK, CRASH]
+ [functions in the absence of a `body` element]
+ expected:
+ if product == "safari": [PASS, FAIL]
diff --git a/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/click-multiple.html.ini b/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/click-multiple.html.ini
new file mode 100644
index 00000000000..5c005edd40a
--- /dev/null
+++ b/tests/wpt/tests/infrastructure/metadata/infrastructure/testdriver/click-multiple.html.ini
@@ -0,0 +1,4 @@
+[click-multiple.html]
+ [TestDriver multiple consecutive clicks]
+ expected:
+ if product == "safari": [PASS, FAIL]
diff --git a/tests/wpt/tests/interfaces/crash-reporting.idl b/tests/wpt/tests/interfaces/crash-reporting.idl
index a6737ca8482..6eaee138a82 100644
--- a/tests/wpt/tests/interfaces/crash-reporting.idl
+++ b/tests/wpt/tests/interfaces/crash-reporting.idl
@@ -8,4 +8,6 @@ interface CrashReportBody : ReportBody {
[Default] object toJSON();
readonly attribute DOMString? reason;
readonly attribute DOMString? stack;
+ readonly attribute DOMString? is_top_level;
+ readonly attribute DocumentVisibilityState? page_visibility;
};
diff --git a/tests/wpt/tests/interfaces/digital-credentials.idl b/tests/wpt/tests/interfaces/digital-credentials.idl
index e4ebb3b3e86..60b63975640 100644
--- a/tests/wpt/tests/interfaces/digital-credentials.idl
+++ b/tests/wpt/tests/interfaces/digital-credentials.idl
@@ -1,17 +1,30 @@
// GENERATED CONTENT - DO NOT EDIT
// Content was automatically extracted by Reffy into webref
// (https://github.com/w3c/webref)
-// Source: Digital Credentials (https://wicg.github.io/digital-credentials/)
+// Source: Digital Credentials (https://w3c-fedid.github.io/digital-credentials/)
partial dictionary CredentialRequestOptions {
DigitalCredentialRequestOptions digital;
};
dictionary DigitalCredentialRequestOptions {
- sequence<DigitalCredentialRequest> requests;
+ sequence<DigitalCredentialGetRequest> requests;
};
-dictionary DigitalCredentialRequest {
+dictionary DigitalCredentialGetRequest {
+ required DOMString protocol;
+ required object data;
+};
+
+partial dictionary CredentialCreationOptions {
+ DigitalCredentialCreationOptions digital;
+};
+
+dictionary DigitalCredentialCreationOptions {
+ sequence<DigitalCredentialCreateRequest> requests;
+};
+
+dictionary DigitalCredentialCreateRequest {
required DOMString protocol;
required object data;
};
diff --git a/tests/wpt/tests/interfaces/speech-api.idl b/tests/wpt/tests/interfaces/speech-api.idl
index 0e07b4619a5..94a416f262b 100644
--- a/tests/wpt/tests/interfaces/speech-api.idl
+++ b/tests/wpt/tests/interfaces/speech-api.idl
@@ -3,7 +3,7 @@
// (https://github.com/w3c/webref)
// Source: Web Speech API (https://webaudio.github.io/web-speech-api/)
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognition : EventTarget {
constructor();
@@ -61,7 +61,7 @@ enum AvailabilityStatus {
"available"
};
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionErrorEvent : Event {
constructor(DOMString type, SpeechRecognitionErrorEventInit eventInitDict);
readonly attribute SpeechRecognitionErrorCode error;
@@ -74,14 +74,14 @@ dictionary SpeechRecognitionErrorEventInit : EventInit {
};
// Item in N-best list
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionAlternative {
readonly attribute DOMString transcript;
readonly attribute float confidence;
};
// A complete one-shot simple response
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionResult {
readonly attribute unsigned long length;
getter SpeechRecognitionAlternative item(unsigned long index);
@@ -89,14 +89,14 @@ interface SpeechRecognitionResult {
};
// A collection of responses (used in continuous mode)
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionResultList {
readonly attribute unsigned long length;
getter SpeechRecognitionResult item(unsigned long index);
};
// A full response, which could be interim or final, part of a continuous response or not
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionEvent : Event {
constructor(DOMString type, SpeechRecognitionEventInit eventInitDict);
readonly attribute unsigned long resultIndex;
@@ -109,7 +109,7 @@ dictionary SpeechRecognitionEventInit : EventInit {
};
// The object representing a phrase for contextual biasing.
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionPhrase {
constructor(DOMString phrase, optional float boost = 1.0);
readonly attribute DOMString phrase;
@@ -117,7 +117,7 @@ interface SpeechRecognitionPhrase {
};
// The object representing a list of phrases for contextual biasing.
-[Exposed=Window]
+[SecureContext, Exposed=Window]
interface SpeechRecognitionPhraseList {
constructor(sequence<SpeechRecognitionPhrase> phrases);
readonly attribute unsigned long length;
diff --git a/tests/wpt/tests/interfaces/translation-api.idl b/tests/wpt/tests/interfaces/translation-api.idl
new file mode 100644
index 00000000000..6cbad38938a
--- /dev/null
+++ b/tests/wpt/tests/interfaces/translation-api.idl
@@ -0,0 +1,85 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Translator and Language Detector APIs (https://webmachinelearning.github.io/translation-api/)
+
+[Exposed=Window, SecureContext]
+interface Translator {
+ static Promise<Translator> create(TranslatorCreateOptions options);
+ static Promise<Availability> availability(TranslatorCreateCoreOptions options);
+
+ Promise<DOMString> translate(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+ ReadableStream translateStreaming(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+
+ readonly attribute DOMString sourceLanguage;
+ readonly attribute DOMString targetLanguage;
+
+ Promise<double> measureInputUsage(
+ DOMString input,
+ optional TranslatorTranslateOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+Translator includes DestroyableModel;
+
+dictionary TranslatorCreateCoreOptions {
+ required DOMString sourceLanguage;
+ required DOMString targetLanguage;
+};
+
+dictionary TranslatorCreateOptions : TranslatorCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+};
+
+dictionary TranslatorTranslateOptions {
+ AbortSignal signal;
+};
+
+[Exposed=Window, SecureContext]
+interface LanguageDetector {
+ static Promise<LanguageDetector> create(
+ optional LanguageDetectorCreateOptions options = {}
+ );
+ static Promise<Availability> availability(
+ optional LanguageDetectorCreateCoreOptions options = {}
+ );
+
+ Promise<sequence<LanguageDetectionResult>> detect(
+ DOMString input,
+ optional LanguageDetectorDetectOptions options = {}
+ );
+
+ readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
+
+ Promise<double> measureInputUsage(
+ DOMString input,
+ optional LanguageDetectorDetectOptions options = {}
+ );
+ readonly attribute unrestricted double inputQuota;
+};
+LanguageDetector includes DestroyableModel;
+
+dictionary LanguageDetectorCreateCoreOptions {
+ sequence<DOMString> expectedInputLanguages;
+};
+
+dictionary LanguageDetectorCreateOptions : LanguageDetectorCreateCoreOptions {
+ AbortSignal signal;
+ CreateMonitorCallback monitor;
+};
+
+dictionary LanguageDetectorDetectOptions {
+ AbortSignal signal;
+};
+
+dictionary LanguageDetectionResult {
+ DOMString detectedLanguage;
+ double confidence;
+};
diff --git a/tests/wpt/tests/interfaces/webnn.idl b/tests/wpt/tests/interfaces/webnn.idl
index 37fcc32501e..8d0e485bc76 100644
--- a/tests/wpt/tests/interfaces/webnn.idl
+++ b/tests/wpt/tests/interfaces/webnn.idl
@@ -799,8 +799,7 @@ partial dictionary MLOpSupportLimits {
enum MLPaddingMode {
"constant",
"edge",
- "reflection",
- "symmetric"
+ "reflection"
};
dictionary MLPadOptions : MLOperatorOptions {
diff --git a/tests/wpt/tests/lifecycle/META.yml b/tests/wpt/tests/lifecycle/META.yml
deleted file mode 100644
index abd5e0f6ed6..00000000000
--- a/tests/wpt/tests/lifecycle/META.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spec: https://wicg.github.io/page-lifecycle/
-suggested_reviewers:
- - fmeawad
diff --git a/tests/wpt/tests/lint.ignore b/tests/wpt/tests/lint.ignore
index 955e5df4907..b39180815c2 100644
--- a/tests/wpt/tests/lint.ignore
+++ b/tests/wpt/tests/lint.ignore
@@ -282,6 +282,7 @@ SET TIMEOUT: service-workers/service-worker/resources/opaque-response-being-prel
SET TIMEOUT: service-workers/service-worker/resources/opaque-response-preloaded-xhr.html
SET TIMEOUT: service-workers/service-worker/resources/performance-timeline-worker.js
SET TIMEOUT: service-workers/service-worker/resources/resource-timing-worker.js
+SET TIMEOUT: soft-navigation-heuristics/smoke/tentative/task-attribution.html
SET TIMEOUT: shadow-dom/Document-prototype-currentScript.html
SET TIMEOUT: shadow-dom/scroll-to-the-fragment-in-shadow-tree.html
SET TIMEOUT: shadow-dom/slotchange-event.html
diff --git a/tests/wpt/tests/magnetometer/Magnetometer-iframe-access.https.html b/tests/wpt/tests/magnetometer/Magnetometer-iframe-access.https.html
index 7aabd0eb61b..455a06b060b 100644
--- a/tests/wpt/tests/magnetometer/Magnetometer-iframe-access.https.html
+++ b/tests/wpt/tests/magnetometer/Magnetometer-iframe-access.https.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://www.w3.org/TR/magnetometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/magnetometer/Magnetometer.https.html b/tests/wpt/tests/magnetometer/Magnetometer.https.html
index 6beb534509d..964ef2bd875 100644
--- a/tests/wpt/tests/magnetometer/Magnetometer.https.html
+++ b/tests/wpt/tests/magnetometer/Magnetometer.https.html
@@ -6,7 +6,7 @@
<link rel="help" href="https://www.w3.org/TR/magnetometer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html b/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html
index 4831b5e7192..599bff7b4a3 100644
--- a/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html
+++ b/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://www.w3.org/TR/orientation-sensor/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor.https.html b/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor.https.html
index 4c516da1451..0a6e2dae897 100644
--- a/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor.https.html
+++ b/tests/wpt/tests/orientation-sensor/AbsoluteOrientationSensor.https.html
@@ -7,7 +7,7 @@
<link rel="help" href="https://w3c.github.io/sensors/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html b/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html
index fe995e2d1b9..7e55cb3b69e 100644
--- a/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html
+++ b/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html
@@ -5,7 +5,7 @@
<link rel="help" href="https://www.w3.org/TR/orientation-sensor/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
<script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script>
diff --git a/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor.https.html b/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor.https.html
index 35dc8c31113..9ad37a627c1 100644
--- a/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor.https.html
+++ b/tests/wpt/tests/orientation-sensor/RelativeOrientationSensor.https.html
@@ -7,7 +7,7 @@
<link rel="help" href="https://w3c.github.io/sensors/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver.js?feature=bidi"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/page-visibility/resources/window_state_context.js"></script>
<script src="/generic-sensor/resources/generic-sensor-helpers.js"></script>
diff --git a/tests/wpt/tests/page-lifecycle/META.yml b/tests/wpt/tests/page-lifecycle/META.yml
index 8036af19bb9..abd5e0f6ed6 100644
--- a/tests/wpt/tests/page-lifecycle/META.yml
+++ b/tests/wpt/tests/page-lifecycle/META.yml
@@ -1 +1,3 @@
spec: https://wicg.github.io/page-lifecycle/
+suggested_reviewers:
+ - fmeawad
diff --git a/tests/wpt/tests/lifecycle/child-display-none.tentative.html b/tests/wpt/tests/page-lifecycle/child-display-none.tentative.html
index d4ca6dab1e0..d4ca6dab1e0 100644
--- a/tests/wpt/tests/lifecycle/child-display-none.tentative.html
+++ b/tests/wpt/tests/page-lifecycle/child-display-none.tentative.html
diff --git a/tests/wpt/tests/lifecycle/child-out-of-viewport.tentative.html b/tests/wpt/tests/page-lifecycle/child-out-of-viewport.tentative.html
index 4d8f868bfb5..4d8f868bfb5 100644
--- a/tests/wpt/tests/lifecycle/child-out-of-viewport.tentative.html
+++ b/tests/wpt/tests/page-lifecycle/child-out-of-viewport.tentative.html
diff --git a/tests/wpt/tests/lifecycle/freeze.html b/tests/wpt/tests/page-lifecycle/freeze.html
index a2a9a7d3f14..a2a9a7d3f14 100644
--- a/tests/wpt/tests/lifecycle/freeze.html
+++ b/tests/wpt/tests/page-lifecycle/freeze.html
diff --git a/tests/wpt/tests/lifecycle/resources/beacon.py b/tests/wpt/tests/page-lifecycle/resources/beacon.py
index 09915ffbcf0..09915ffbcf0 100644
--- a/tests/wpt/tests/lifecycle/resources/beacon.py
+++ b/tests/wpt/tests/page-lifecycle/resources/beacon.py
diff --git a/tests/wpt/tests/lifecycle/resources/child.html b/tests/wpt/tests/page-lifecycle/resources/child.html
index 708bbfe02dc..708bbfe02dc 100644
--- a/tests/wpt/tests/lifecycle/resources/child.html
+++ b/tests/wpt/tests/page-lifecycle/resources/child.html
diff --git a/tests/wpt/tests/lifecycle/resources/subframe.html b/tests/wpt/tests/page-lifecycle/resources/subframe.html
index 2f1d70a80a7..2f1d70a80a7 100644
--- a/tests/wpt/tests/lifecycle/resources/subframe.html
+++ b/tests/wpt/tests/page-lifecycle/resources/subframe.html
diff --git a/tests/wpt/tests/lifecycle/resources/subframe_worker.html b/tests/wpt/tests/page-lifecycle/resources/subframe_worker.html
index 350d27437a6..350d27437a6 100644
--- a/tests/wpt/tests/lifecycle/resources/subframe_worker.html
+++ b/tests/wpt/tests/page-lifecycle/resources/subframe_worker.html
diff --git a/tests/wpt/tests/lifecycle/resources/subframe_worker1.js b/tests/wpt/tests/page-lifecycle/resources/subframe_worker1.js
index 2d13e89065a..2d13e89065a 100644
--- a/tests/wpt/tests/lifecycle/resources/subframe_worker1.js
+++ b/tests/wpt/tests/page-lifecycle/resources/subframe_worker1.js
diff --git a/tests/wpt/tests/lifecycle/resources/subframe_worker2.js b/tests/wpt/tests/page-lifecycle/resources/subframe_worker2.js
index 32d2741331e..32d2741331e 100644
--- a/tests/wpt/tests/lifecycle/resources/subframe_worker2.js
+++ b/tests/wpt/tests/page-lifecycle/resources/subframe_worker2.js
diff --git a/tests/wpt/tests/lifecycle/resources/window.html b/tests/wpt/tests/page-lifecycle/resources/window.html
index 58181f32da7..58181f32da7 100644
--- a/tests/wpt/tests/lifecycle/resources/window.html
+++ b/tests/wpt/tests/page-lifecycle/resources/window.html
diff --git a/tests/wpt/tests/lifecycle/set-composited-layer-position-ref.html b/tests/wpt/tests/page-lifecycle/set-composited-layer-position-ref.html
index 600de56d608..600de56d608 100644
--- a/tests/wpt/tests/lifecycle/set-composited-layer-position-ref.html
+++ b/tests/wpt/tests/page-lifecycle/set-composited-layer-position-ref.html
diff --git a/tests/wpt/tests/lifecycle/set-composited-layer-position.html b/tests/wpt/tests/page-lifecycle/set-composited-layer-position.html
index f1a3807d81a..f1a3807d81a 100644
--- a/tests/wpt/tests/lifecycle/set-composited-layer-position.html
+++ b/tests/wpt/tests/page-lifecycle/set-composited-layer-position.html
diff --git a/tests/wpt/tests/lifecycle/worker-dispay-none.tentative.html b/tests/wpt/tests/page-lifecycle/worker-dispay-none.tentative.html
index 0bcfde6d179..0bcfde6d179 100644
--- a/tests/wpt/tests/lifecycle/worker-dispay-none.tentative.html
+++ b/tests/wpt/tests/page-lifecycle/worker-dispay-none.tentative.html
diff --git a/tests/wpt/tests/pointerevents/pointerevent_click_during_parent_capture.html b/tests/wpt/tests/pointerevents/pointerevent_click_during_parent_capture.html
new file mode 100644
index 00000000000..f25e61aade3
--- /dev/null
+++ b/tests/wpt/tests/pointerevents/pointerevent_click_during_parent_capture.html
@@ -0,0 +1,280 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="variant" content="?pointerType=mouse&preventDefault=">
+<meta name="variant" content="?pointerType=mouse&preventDefault=pointerdown">
+<meta name="variant" content="?pointerType=touch&preventDefault=">
+<meta name="variant" content="?pointerType=touch&preventDefault=pointerdown">
+<meta name="variant" content="?pointerType=touch&preventDefault=touchstart">
+<title>Test `click` event target when a parent element captures the pointer</title>
+<style>
+ #parent {
+ background: green;
+ border: 1px solid black;
+ width: 40px;
+ height: 40px;
+ }
+
+ #target {
+ background: blue;
+ border: 1px solid black;
+ width: 20px;
+ height: 20px;
+ margin: 10px;
+ }
+</style>
+<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/testdriver-actions.js"></script>
+<script>
+"use strict";
+
+const searchParams = new URLSearchParams(document.location.search);
+const pointerType = searchParams.get("pointerType");
+const preventDefaultType = searchParams.get("preventDefault");
+
+addEventListener(
+ "load",
+ () => {
+ const iframe = document.querySelector("iframe");
+ iframe.contentDocument.head.innerHTML = `<style>${
+ document.querySelector("style").textContent
+ }</style>`;
+
+ async function runTest(t, win, doc) {
+ let pointerId;
+ const parent = doc.getElementById("parent");
+ const target = doc.getElementById("target");
+ const body = doc.body;
+ const html = doc.documentElement;
+ let eventTypes = [];
+ let composedPaths = [];
+ function stringifyIfElement(eventTarget) {
+ if (!(eventTarget instanceof win.Node)) {
+ return eventTarget;
+ }
+ switch (eventTarget.nodeType) {
+ case win.Node.ELEMENT_NODE:
+ return `<${eventTarget.localName}${
+ eventTarget.id ? ` id="${eventTarget.id}"` : ""
+ }>`;
+ default:
+ return eventTarget;
+ }
+ }
+ function stringifyElements(eventTargets) {
+ return eventTargets.map(stringifyIfElement);
+ }
+ function captureEvent(e) {
+ eventTypes.push(e.type);
+ composedPaths.push(e.composedPath());
+ }
+ const expectedEvents = (() => {
+ const pathToTarget = [target, parent, body, html, doc, win];
+ const pathToParent = [parent, body, html, doc, win];
+ function getExpectedEventsForMouse() {
+ switch (preventDefaultType) {
+ case "pointerdown":
+ return {
+ types: ["pointerdown", "pointerup", "click"],
+ composedPaths: [
+ pathToTarget, // pointerdown
+ pathToParent, // pointerup
+ // Captured by the parent element, `click` should be fired on
+ // it.
+ pathToParent, // click
+ ],
+ };
+ default:
+ return {
+ types: [
+ "pointerdown",
+ "mousedown",
+ "pointerup",
+ "mouseup",
+ "click",
+ ],
+ composedPaths: [
+ pathToTarget, // pointerdown
+ // `mousedown` target should be considered without the
+ // capturing element.
+ pathToTarget, // mousedown
+ pathToParent, // pointerup
+ // However, `mouseup` target should be considered with the
+ // capturing element.
+ pathToParent, // mouseup
+ // Captured by the parent element, `click` should be fired on
+ // it.
+ pathToParent, // click
+ ],
+ };
+ }
+ }
+ function getExpectedEventsForTouch() {
+ switch (preventDefaultType) {
+ case "pointerdown":
+ return {
+ types: [
+ "pointerdown",
+ "touchstart",
+ "pointerup",
+ "touchend",
+ "click",
+ ],
+ composedPaths: [
+ pathToTarget, // pointerdown
+ // `touchstart` target should be considered without the
+ // capturing element.
+ pathToTarget, // touchstart
+ pathToParent, // pointerup
+ // Different from `mouseup`, `touchend` should always be fired
+ // on same target as `touchstart`.
+ pathToTarget, // touchend
+ // `click` event is NOT a compatibility mouse event of Touch
+ // Events because canceling `pointerdown` should cancel them.
+ // So, the event target should be considered with `userEvent`
+ // which caused this `click` event. In this case, it's the
+ // preceding `pointerup`. Therefore, this should be
+ // considered with the capturing element.
+ pathToParent, // click
+ ],
+ };
+ case "touchstart":
+ return {
+ types: ["pointerdown", "touchstart", "pointerup", "touchend"],
+ composedPaths: [
+ pathToTarget, // pointerdown
+ // `touchstart` target should be considered without the
+ // capturing element.
+ pathToTarget, // touchstart
+ pathToParent, // pointerup
+ // Different from `mouseup`, `touchend` should always be fired
+ // on same target as `touchstart`.
+ pathToTarget, // touchend
+ // `click` shouldn't be fired if `touchstart` is canceled
+ // especially for the backward compatibility.
+ ],
+ };
+ default:
+ return {
+ types: [
+ "pointerdown",
+ "touchstart",
+ "pointerup",
+ "touchend",
+ "mousedown",
+ "mouseup",
+ "click",
+ ],
+ composedPaths: [
+ pathToTarget, // pointerdown
+ // `touchstart` target should be considered without the
+ // capturing element.
+ pathToTarget, // touchstart
+ pathToParent, // touchup
+ // Different from `mouseup`, `touchend` should always be fired
+ // on same target as `touchstart`.
+ pathToTarget, // touchend
+ // Compatibility mouse events should be fired on the element
+ // at the touch point.
+ pathToTarget, // mousedown
+ pathToTarget, // mouseup
+ // `click` should NOT be a compatibility mouse event of the
+ // Touch Events since touchstart was not consumed. So,
+ // captured by the parent element, `click` should be fired on
+ // it.
+ pathToParent, //click
+ ],
+ };
+ }
+ }
+ return pointerType == "mouse"
+ ? getExpectedEventsForMouse()
+ : getExpectedEventsForTouch();
+ })();
+
+ win.addEventListener(
+ "pointerdown",
+ e => {
+ captureEvent(e);
+ pointerId = e.pointerId;
+ parent.setPointerCapture(pointerId);
+ if (preventDefaultType == e.type) {
+ e.preventDefault();
+ }
+ },
+ { once: true, passive: false }
+ );
+ win.addEventListener(
+ "pointerup",
+ e => {
+ captureEvent(e);
+ parent.releasePointerCapture(pointerId);
+ },
+ { once: true }
+ );
+ win.addEventListener(
+ "touchstart",
+ e => {
+ captureEvent(e);
+ if (preventDefaultType == e.type) {
+ e.preventDefault();
+ }
+ },
+ { once: true, passive: false }
+ );
+ win.addEventListener(
+ "touchend",
+ captureEvent,
+ { once: true }
+ );
+ win.addEventListener("mousedown", captureEvent, { once: true });
+ win.addEventListener("mouseup", captureEvent, { once: true });
+ win.addEventListener("click", captureEvent, { once: true });
+
+ await new test_driver.Actions()
+ .addPointer("TestPointer", pointerType)
+ .pointerMove(0, 0, { origin: target })
+ .pointerDown()
+ .pointerUp()
+ .send();
+
+ test(() => {
+ assert_array_equals(eventTypes, expectedEvents.types);
+ }, `${t.name}: all expected events should be fired`);
+ for (let i = 0; i < eventTypes.length; i++) {
+ const eventType = eventTypes[i];
+ const expectedEventIndex = expectedEvents.types.indexOf(eventType);
+ if (expectedEventIndex < 0) {
+ continue;
+ }
+ test(() => {
+ assert_array_equals(
+ stringifyElements(composedPaths[i]),
+ stringifyElements(expectedEvents.composedPaths[expectedEventIndex])
+ );
+ }, `${t.name}: "${eventType}" event should be fired on expected target`);
+ }
+ }
+
+ promise_test(async t => {
+ await runTest(t, window, document);
+ }, "Test in the topmost document");
+ promise_test(async t => {
+ await runTest(t, iframe.contentWindow, iframe.contentDocument);
+ }, "Test in the iframe");
+ },
+ { once: true }
+);
+</script>
+</head>
+<body>
+ <div id="parent">
+ <div id="target"></div>
+ </div>
+ <iframe srcdoc="<div id='parent'><div id='target'></div></div>"></iframe>
+</body>
+</html>
diff --git a/tests/wpt/tests/requestidlecallback/WEB_FEATURES.yml b/tests/wpt/tests/requestidlecallback/WEB_FEATURES.yml
new file mode 100644
index 00000000000..989f1fc7e45
--- /dev/null
+++ b/tests/wpt/tests/requestidlecallback/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: requestidlecallback
+ files: "**"
diff --git a/tests/wpt/tests/resources/idlharness.js b/tests/wpt/tests/resources/idlharness.js
index d52ba9fd3c4..2eb710c1827 100644
--- a/tests/wpt/tests/resources/idlharness.js
+++ b/tests/wpt/tests/resources/idlharness.js
@@ -783,6 +783,10 @@ IdlArray.prototype.merge_partials = function()
}
testedPartials.set(parsed_idl.name, partialTestCount);
+ if (!self.shouldRunSubTest(partialTestName)) {
+ return;
+ }
+
if (!parsed_idl.untested) {
test(function () {
assert_true(originalExists, `Original ${parsed_idl.type} should be defined`);
@@ -871,6 +875,7 @@ IdlArray.prototype.merge_mixins = function()
{
const lhs = parsed_idl.target;
const rhs = parsed_idl.includes;
+ const testName = lhs + " includes " + rhs + ": member names are unique";
var errStr = lhs + " includes " + rhs + ", but ";
if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";
@@ -878,7 +883,7 @@ IdlArray.prototype.merge_mixins = function()
if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";
if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";
- if (this.members[rhs].members.length) {
+ if (this.members[rhs].members.length && self.shouldRunSubTest(testName)) {
test(function () {
var clash = this.members[rhs].members.find(function(member) {
return this.members[lhs].members.find(function(m) {
@@ -892,7 +897,7 @@ IdlArray.prototype.merge_mixins = function()
this.members[lhs].members.push(new IdlInterfaceMember(member));
}.bind(this));
assert_true(!clash, "member " + (clash && clash.name) + " is unique");
- }.bind(this), lhs + " includes " + rhs + ": member names are unique");
+ }.bind(this), testName);
}
}
this.includes = [];
diff --git a/tests/wpt/tests/sanitizer-api/sanitizer-basic-filtering.tentative.html b/tests/wpt/tests/sanitizer-api/sanitizer-basic-filtering.tentative.html
index 38c764ae181..0be3604ecfe 100644
--- a/tests/wpt/tests/sanitizer-api/sanitizer-basic-filtering.tentative.html
+++ b/tests/wpt/tests/sanitizer-api/sanitizer-basic-filtering.tentative.html
@@ -142,21 +142,43 @@ a <!-- comment --> b
<p data-x="1" data-y="2" data-z="3">
#config
{
- "attributes": [ "data-x" ],
- "removeAttributes": [ "data-y" ],
+ "attributes": [],
"dataAttributes": true
}
#document
| <p>
| data-x="1"
+| data-y="2"
| data-z="3"
+
+#data
+<p data-x="1" data-y="2" data-z="3">
+#config
+{
+ "removeAttributes": ["data-z"],
+ "dataAttributes": true
+}
+#document
+| <p>
+| data-x="1"
+| data-y="2"
+
+#data
+<p data-x="1" data-y="2" data-z="3">
+#config
+{
+ "attributes": [],
+ "dataAttributes": false
+}
+#document
+| <p>
+
#data
<p data-x="1" data-y="2" data-z="3">
#config
{
"attributes": [ "data-x" ],
- "removeAttributes": [ "data-y" ],
"dataAttributes": false
}
#document
@@ -193,8 +215,7 @@ a <!-- comment --> b
#data
<svg><rect>
#config
-{ "elements": [{ "name": "svg", "namespace": "http://www.w3.org/2000/svg" }],
- "removeElements": [{ "name": "rect", "namespace": "http://www.w3.org/2000/svg" }]}
+{ "removeElements": [{ "name": "rect", "namespace": "http://www.w3.org/2000/svg" }]}
#document
| <svg svg>
@@ -218,8 +239,7 @@ a <!-- comment --> b
#data
<math><mi>x
#config
-{ "elements": [{ "name": "math", "namespace": "http://www.w3.org/1998/Math/MathML" }],
- "removeElements": [{ "name": "mi", "namespace": "http://www.w3.org/1998/Math/MathML" }]}
+{ "removeElements": [{ "name": "mi", "namespace": "http://www.w3.org/1998/Math/MathML" }] }
#document
| <math math>
@@ -237,8 +257,7 @@ a <!-- comment --> b
<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">
#config
{ "elements": [{ "name": "svg", "namespace": "http://www.w3.org/2000/svg" }],
- "attributes": [{"name": "space", "namespace": "http://www.w3.org/XML/1998/namespace" }],
- "removeAttributes": [{"name": "href", "namespace": "http://www.w3.org/1999/xlink" }] }
+ "attributes": [{"name": "space", "namespace": "http://www.w3.org/XML/1998/namespace" }] }
#document
| <svg svg>
| xml space="default"
@@ -247,8 +266,7 @@ a <!-- comment --> b
<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">
#config
{ "elements": [{ "name": "svg", "namespace": "http://www.w3.org/2000/svg" }],
- "attributes": [{"name": "href", "namespace": "http://www.w3.org/1999/xlink" }] ,
- "removeAttributes": [{"name": "space", "namespace": "http://www.w3.org/XML/1998/namespace" }] }
+ "attributes": [{"name": "href", "namespace": "http://www.w3.org/1999/xlink" }] }
#document
| <svg svg>
| xlink href="about:blank"
@@ -259,9 +277,9 @@ for(const group of
document.querySelectorAll("script[type='html5lib-testcases']")) {
parse_html5lib_testcases(group.textContent).forEach((testcase, index) => {
let config = undefined;
- try {
+ if (testcase.config) {
config = { sanitizer: JSON.parse(testcase.config) };
- } catch { /* config remains undefined */ }
+ }
test(_ => {
const div = document.createElement("div");
@@ -274,15 +292,28 @@ for(const group of
assert_testcase(div, testcase);
}, `setHTMLUnsafe testcase ${group.id}/${index}, "${testcase.data}"`);
- // parseHTML and parseHTMLUnsafe need to allow "html" and "body" for these
- // tests to be useful. Update the config, if necessary.
- if (config && config["sanitizer"] && config["sanitizer"]["elements"]) {
- config["sanitizer"] = new Sanitizer(config["sanitizer"]);
- config["sanitizer"].allowElement("body");
- config["sanitizer"].allowElement("html");
- }
-
test(_ => {
+ const div = document.createElement("div");
+ const shadowRoot = div.attachShadow({ mode: "open" });
+ shadowRoot .setHTML(testcase.data, config);
+ assert_testcase(shadowRoot, testcase);
+ }, `ShadowRoot.setHTML testcase ${group.id}/${index}, "${testcase.data}"`);
+ test(_ => {
+ const div = document.createElement("div");
+ const shadowRoot = div.attachShadow({ mode: "open" });
+ shadowRoot .setHTMLUnsafe(testcase.data, config);
+ assert_testcase(shadowRoot, testcase);
+ }, `ShadowRoot.setHTMLUnsafe testcase ${group.id}/${index}, "${testcase.data}"`);
+
+ // parseHTML and parseHTMLUnsafe need to allow "html" and "body" for these
+ // tests to be useful. Update the config, if necessary.
+ if (config && config["sanitizer"] && config["sanitizer"]["elements"]) {
+ config["sanitizer"] = new Sanitizer(config["sanitizer"]);
+ config["sanitizer"].allowElement("body");
+ config["sanitizer"].allowElement("html");
+ }
+
+ test(_ => {
assert_testcase(
Document.parseHTML(testcase.data, config).body, testcase);
}, `parseHTML testcase ${group.id}/${index}, "${testcase.data}"`);
diff --git a/tests/wpt/tests/scroll-animations/crashtests/scroll-timeline-completion-crash.html b/tests/wpt/tests/scroll-animations/crashtests/scroll-timeline-completion-crash.html
new file mode 100644
index 00000000000..fb7ecd1ed1b
--- /dev/null
+++ b/tests/wpt/tests/scroll-animations/crashtests/scroll-timeline-completion-crash.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>This test passes if it does not crash</title>
+<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/">
+<script src="/web-animations/testcommon.js"></script>
+
+<style>
+ @keyframes grow-progress {
+ from { background-color: green; }
+ to { background-color: red; }
+ }
+
+ #container {
+ overflow: scroll;
+ width: 100px;
+ height: 100px;
+ animation: grow-progress linear forwards;
+ animation-timeline: scroll(self);
+ }
+
+ #content {
+ width: 200px;
+ height: 200px;
+ }
+</style>
+<body onload="runTest()">
+<div id="container">
+ <div id="content"></div>
+</div>
+<script>
+
+async function runTest() {
+ const container = document.getElementById("container");
+ container.scrollTo(0, container.scrollHeight - container.clientHeight);
+ await waitForNextFrame();
+
+ const elem = document.getElementById("content");
+ elem.style.width = "0px";
+ elem.style.height = "0px";
+
+ await waitForNextFrame();
+ }
+</script>
diff --git a/tests/wpt/tests/scroll-animations/css/timeline-scope-computed.tentative.html b/tests/wpt/tests/scroll-animations/css/timeline-scope-computed.html
index 2e0a024a600..1096a9aa136 100644
--- a/tests/wpt/tests/scroll-animations/css/timeline-scope-computed.tentative.html
+++ b/tests/wpt/tests/scroll-animations/css/timeline-scope-computed.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7759">
+<link rel="help" href="https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
diff --git a/tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.tentative.html b/tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.html
index 61bf6975a81..ff6fcb7e5a5 100644
--- a/tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.tentative.html
+++ b/tests/wpt/tests/scroll-animations/css/timeline-scope-parsing.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7759">
+<link rel="help" href="https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
diff --git a/tests/wpt/tests/shadow-dom/crashtests/manual-assignment-beforeattrmodified.html b/tests/wpt/tests/shadow-dom/crashtests/manual-assignment-beforeattrmodified.html
new file mode 100644
index 00000000000..50ba9303a8a
--- /dev/null
+++ b/tests/wpt/tests/shadow-dom/crashtests/manual-assignment-beforeattrmodified.html
@@ -0,0 +1,15 @@
+<script>
+const func_a = function(arg1) {
+ let a = document.getElementById("x")
+ a.insertBefore(arg1.originalTarget, a.childNodes[0])
+}
+window.addEventListener("load", () => {
+ let b = document.createElement("video")
+ document.documentElement.appendChild(b)
+ document.createElement("slot").assign(b)
+ document.addEventListener("DOMAttrModified", func_a, true)
+ b.setAttribute("width", 165)
+ document.createElement("slot").assign(b)
+})
+</script>
+<marquee id="x">
diff --git a/tests/wpt/tests/soft-navigation-heuristics/replacestate.tentative.html b/tests/wpt/tests/soft-navigation-heuristics/replacestate.tentative.html
deleted file mode 100644
index d47b9b65388..00000000000
--- a/tests/wpt/tests/soft-navigation-heuristics/replacestate.tentative.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Detect soft navigation with replaceState.</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/soft-navigation-helper.js"></script>
-</head>
-<body>
- <main id=main>
- <a id=link>Click me!</a>
- </main>
- <script>
- const link = document.getElementById("link");
- testSoftNavigationNotDetected({
- link: link,
- eventTarget: link,
- eventName: "click",
- eventHandler: async e => {
- const url = URL + "?" + counter;
- history.replaceState({}, '', url);
- await addImageToMain();
- },
- testName: "Should not detect soft navigation with just replaceState"});
- </script>
-</body>
-</html>
diff --git a/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js b/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js
index a29978c8760..c9f2b41b552 100644
--- a/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js
+++ b/tests/wpt/tests/soft-navigation-heuristics/resources/soft-navigation-helper.js
@@ -1,58 +1,54 @@
var counter = 0;
var interacted;
-var timestamps = []
+var timestamps = [];
const MAX_CLICKS = 50;
// Entries for one hard navigation + 50 soft navigations.
const MAX_PAINT_ENTRIES = 51;
-const URL = "foobar.html";
+const URL = 'foobar.html';
const readValue = (value, defaultValue) => {
return value !== undefined ? value : defaultValue;
-}
-const testSoftNavigation =
- options => {
- const addContent = options.addContent;
- const link = options.link;
- const pushState = readValue(options.pushState,
- url=>{history.pushState({}, '', url)});
- const clicks = readValue(options.clicks, 1);
- const extraValidations = readValue(options.extraValidations,
- () => {});
- const testName = options.testName;
- const pushUrl = readValue(options.pushUrl, true);
- const eventType = readValue(options.eventType, "click");
- const interactionFunc = options.interactionFunc;
- const eventPrepWork = options.eventPrepWork;
- promise_test(async t => {
- await waitInitialLCP();
- const preClickLcp = await getLcpEntries();
- setEvent(t, link, pushState, addContent, pushUrl, eventType,
- eventPrepWork);
- let first_navigation_id;
- for (let i = 0; i < clicks; ++i) {
- const firstClick = (i === 0);
- let paint_entries_promise =
- waitOnPaintEntriesPromise(firstClick);
- interacted = false;
- const soft_nav_promise = waitOnSoftNav();
- interact(link, interactionFunc);
+};
+const testSoftNavigation = options => {
+ const addContent = options.addContent;
+ const link = options.link;
+ const pushState =
+ readValue(options.pushState, url => {history.pushState({}, '', url)});
+ const clicks = readValue(options.clicks, 1);
+ const extraValidations = readValue(options.extraValidations, () => {});
+ const testName = options.testName;
+ const pushUrl = readValue(options.pushUrl, true);
+ const eventType = readValue(options.eventType, 'click');
+ const interactionFunc = options.interactionFunc;
+ const eventPrepWork = options.eventPrepWork;
+ promise_test(async t => {
+ await waitInitialLCP();
+ const preClickLcp = await getLcpEntries();
+ setEvent(t, link, pushState, addContent, pushUrl, eventType, eventPrepWork);
+ let first_navigation_id;
+ for (let i = 0; i < clicks; ++i) {
+ const firstClick = (i === 0);
+ let paint_entries_promise = waitOnPaintEntriesPromise(firstClick);
+ interacted = false;
+ const soft_nav_promise = waitOnSoftNav();
+ interact(link, interactionFunc);
- const navigation_id = await soft_nav_promise;
- if (!first_navigation_id) {
- first_navigation_id = navigation_id;
- }
- // Ensure paint timing entries are fired before moving on to the next
- // click.
- await paint_entries_promise;
- }
- assert_equals(
- document.softNavigations, clicks,
- 'Soft Navigations detected are the same as the number of clicks');
- await validateSoftNavigationEntry(
- clicks, extraValidations, pushUrl);
+ const navigation_id = await soft_nav_promise;
+ if (!first_navigation_id) {
+ first_navigation_id = navigation_id;
+ }
+ // Ensure paint timing entries are fired before moving on to the next
+ // click.
+ await paint_entries_promise;
+ }
+ assert_equals(
+ document.softNavigations, clicks,
+ 'Soft Navigations detected are the same as the number of clicks');
+ await validateSoftNavigationEntry(clicks, extraValidations, pushUrl);
- await runEntryValidations(preClickLcp, first_navigation_id, clicks + 1, options.validate);
- }, testName);
- };
+ await runEntryValidations(
+ preClickLcp, first_navigation_id, clicks + 1, options.validate);
+ }, testName);
+};
const testNavigationApi = (testName, navigateEventHandler, link) => {
promise_test(async t => {
@@ -77,35 +73,34 @@ const testNavigationApi = (testName, navigateEventHandler, link) => {
};
const testSoftNavigationNotDetected = options => {
- promise_test(async t => {
- const preClickLcp = await getLcpEntries();
- options.eventTarget.addEventListener(options.eventName, options.eventHandler);
- interact(options.link);
- await new Promise((resolve, reject) => {
- (new PerformanceObserver(() =>
- reject("Soft navigation should not be triggered"))).observe({
- type: 'soft-navigation',
- buffered: true
- });
- t.step_timeout(resolve, 1000);
- });
- if (document.softNavigations) {
- assert_equals(
- document.softNavigations, 0, 'Soft Navigation not detected');
- }
- const postClickLcp = await getLcpEntries();
+ promise_test(async t => {
+ const preClickLcp = await getLcpEntries();
+ options.eventTarget.addEventListener(
+ options.eventName, options.eventHandler);
+ interact(options.link);
+ await new Promise((resolve, reject) => {
+ new PerformanceObserver(() => {
+ reject('Soft navigation should not be triggered');
+ }).observe({type: 'soft-navigation', buffered: true});
+ t.step_timeout(resolve, 1000);
+ });
+ if (document.softNavigations) {
assert_equals(
- preClickLcp.length, postClickLcp.length, 'No LCP entries accumulated');
- }, options.testName);
- };
+ document.softNavigations, 0, 'Soft Navigation not detected');
+ }
+ const postClickLcp = await getLcpEntries();
+ assert_equals(
+ preClickLcp.length, postClickLcp.length, 'No LCP entries accumulated');
+ }, options.testName);
+};
-const runEntryValidations =
- async (preClickLcp, first_navigation_id, entries_expected_number = 2,
- validate = null) => {
- await validatePaintEntries('first-contentful-paint', entries_expected_number,
- first_navigation_id);
- await validatePaintEntries('first-paint', entries_expected_number,
- first_navigation_id);
+const runEntryValidations = async (
+ preClickLcp, first_navigation_id, entries_expected_number = 2,
+ validate = null) => {
+ await validatePaintEntries(
+ 'first-contentful-paint', entries_expected_number, first_navigation_id);
+ await validatePaintEntries(
+ 'first-paint', entries_expected_number, first_navigation_id);
const postClickLcp = await getLcpEntries();
const postClickLcpWithoutSoftNavs = await getLcpEntriesWithoutSoftNavs();
assert_greater_than(
@@ -118,16 +113,16 @@ const runEntryValidations =
assert_equals(
postClickLcpWithoutSoftNavs.length, preClickLcp.length,
'Soft navigation should not have triggered an LCP entry when the ' +
- 'observer did not opt in');
+ 'observer did not opt in');
assert_not_equals(
postClickLcp[postClickLcp.length - 1].size,
preClickLcp[preClickLcp.length - 1].size,
'Soft navigation LCP element should not have identical size to the hard ' +
'navigation LCP element');
assert_equals(
- postClickLcp[preClickLcp.length].navigationId,
- first_navigation_id, 'Soft navigation LCP should have the same navigation ' +
- 'ID as the last soft nav entry')
+ postClickLcp[preClickLcp.length].navigationId, first_navigation_id,
+ 'Soft navigation LCP should have the same navigation ' +
+ 'ID as the last soft nav entry');
};
const interact =
@@ -138,202 +133,214 @@ const interact =
} else {
test_driver.click(link);
}
- timestamps[counter] = {"syncPostInteraction": performance.now()};
+ timestamps[counter] = {'syncPostInteraction': performance.now()};
}
}
-const setEvent = (t, button, pushState, addContent, pushUrl, eventType, prepWork) => {
- const eventObject =
- (eventType == 'click' || eventType.startsWith("key")) ? button : window;
- eventObject.addEventListener(eventType, async e => {
- let prepWorkFailed = false;
- if (prepWork &&!prepWork(t)) {
- prepWorkFailed = true;
- }
- // This is the end of the event's sync processing.
- if (!timestamps[counter]["eventEnd"]) {
- timestamps[counter]["eventEnd"] = performance.now();
- }
- if (prepWorkFailed) {
- return;
- }
- // Jump through a task, to ensure task tracking is working properly.
- await new Promise(r => t.step_timeout(r, 0));
+const setEvent =
+ (t, button, pushState, addContent, pushUrl, eventType, prepWork) => {
+ const eventObject =
+ (eventType == 'click' || eventType.startsWith('key')) ? button :
+ window;
+ eventObject.addEventListener(eventType, async e => {
+ let prepWorkFailed = false;
+ if (prepWork && !prepWork(t)) {
+ prepWorkFailed = true;
+ }
+ // This is the end of the event's sync processing.
+ if (!timestamps[counter]['eventEnd']) {
+ timestamps[counter]['eventEnd'] = performance.now();
+ }
+ if (prepWorkFailed) {
+ return;
+ }
+ // Jump through a task, to ensure task tracking is working properly.
+ await new Promise(r => t.step_timeout(r, 0));
- const url = URL + "?" + counter;
- if (pushState) {
- // Change the URL
- if (pushUrl) {
- pushState(url);
- } else {
- pushState();
- }
- }
+ const url = URL + '?' + counter;
+ if (pushState) {
+ // Change the URL
+ if (pushUrl) {
+ pushState(url);
+ } else {
+ pushState();
+ }
+ }
- // Wait 10 ms to make sure the timestamps are correct.
- await new Promise(r => t.step_timeout(r, 10));
+ // Wait 10 ms to make sure the timestamps are correct.
+ await new Promise(r => t.step_timeout(r, 10));
- await addContent(url);
+ await addContent(url);
- interacted = true;
- ++counter;
- });
-};
+ interacted = true;
+ ++counter;
+ });
+ };
-const validateSoftNavigationEntry = async (clicks, extraValidations,
- pushUrl) => {
+const validateSoftNavigationEntry =
+ async (clicks, extraValidations, pushUrl) => {
const [entries, options] = await new Promise(resolve => {
- (new PerformanceObserver((list, obs, options) => resolve(
- [list.getEntries(), options]))).observe(
- {type: 'soft-navigation', buffered: true});
- });
+ new PerformanceObserver((list, obs, options) => {
+ resolve([list.getEntries(), options]);
+ }).observe({type: 'soft-navigation', buffered: true});
+ });
const expectedClicks = Math.min(clicks, MAX_CLICKS);
- assert_equals(entries.length, expectedClicks,
- "Performance observer got an entry");
+ assert_equals(
+ entries.length, expectedClicks, 'Performance observer got an entry');
for (let i = 0; i < entries.length; ++i) {
const entry = entries[i];
- assert_true(entry.name.includes(pushUrl ? URL : document.location.href),
- "The soft navigation name is properly set");
+ assert_true(
+ entry.name.includes(pushUrl ? URL : document.location.href),
+ 'The soft navigation name is properly set');
const entryTimestamp = entry.startTime;
- assert_less_than_equal(timestamps[i]["syncPostInteraction"], entryTimestamp,
- "Entry timestamp is lower than the post interaction one");
+ assert_less_than_equal(
+ timestamps[i]['syncPostInteraction'], entryTimestamp,
+ 'Entry timestamp is lower than the post interaction one');
assert_greater_than_equal(
entryTimestamp, timestamps[i]['eventEnd'],
'Event start timestamp matches');
- assert_not_equals(entry.navigationId,
- performance.getEntriesByType("navigation")[0].navigationId,
- "The navigation ID was re-generated and different from the initial one.");
+ assert_not_equals(
+ entry.navigationId,
+ performance.getEntriesByType('navigation')[0].navigationId,
+ 'The navigation ID was re-generated and different from the initial one.');
if (i > 0) {
- assert_not_equals(entry.navigationId,
- entries[i-1].navigationId,
- "The navigation ID was re-generated between clicks");
+ assert_not_equals(
+ entry.navigationId, entries[i - 1].navigationId,
+ 'The navigation ID was re-generated between clicks');
}
}
- assert_equals(performance.getEntriesByType("soft-navigation").length,
- expectedClicks, "Performance timeline got an entry");
+ assert_equals(
+ performance.getEntriesByType('soft-navigation').length, expectedClicks,
+ 'Performance timeline got an entry');
await extraValidations(entries, options);
-
};
-const validatePaintEntries = async (type, entries_number, first_navigation_id) => {
+const validatePaintEntries =
+ async (type, entries_number, first_navigation_id) => {
if (!performance.softNavPaintMetricsSupported) {
return;
}
const expected_entries_number = Math.min(entries_number, MAX_PAINT_ENTRIES);
const entries = await new Promise(resolve => {
const entries = [];
- (new PerformanceObserver(list => {
+ new PerformanceObserver(list => {
entries.push(...list.getEntriesByName(type));
if (entries.length >= expected_entries_number) {
resolve(entries);
}
- })).observe(
- {type: 'paint', buffered: true, includeSoftNavigationObservations: true});
+ }).observe({
+ type: 'paint',
+ buffered: true,
+ includeSoftNavigationObservations: true
});
+ });
const entries_without_softnavs = await new Promise(resolve => {
- (new PerformanceObserver(list => resolve(
- list.getEntriesByName(type)))).observe(
- {type: 'paint', buffered: true});
- });
- assert_equals(entries.length, expected_entries_number,
- `There are ${entries_number} entries for ${type}`);
- assert_equals(entries_without_softnavs.length, 1,
- `There is one non-softnav entry for ${type}`);
+ new PerformanceObserver(list => {
+ resolve(list.getEntriesByName(type));
+ }).observe({type: 'paint', buffered: true});
+ });
+ assert_equals(
+ entries.length, expected_entries_number,
+ `There are ${entries_number} entries for ${type}`);
+ assert_equals(
+ entries_without_softnavs.length, 1,
+ `There is one non-softnav entry for ${type}`);
if (entries_number > 1) {
- assert_not_equals(entries[0].startTime, entries[1].startTime,
- "Entries have different timestamps for " + type);
+ assert_not_equals(
+ entries[0].startTime, entries[1].startTime,
+ 'Entries have different timestamps for ' + type);
}
if (expected_entries_number > entries_without_softnavs.length) {
- assert_equals(entries[entries_without_softnavs.length].navigationId,
- first_navigation_id,
- "First paint entry should have the same navigation ID as the last soft " +
- "navigation entry");
+ assert_equals(
+ entries[entries_without_softnavs.length].navigationId,
+ first_navigation_id,
+ 'First paint entry should have the same navigation ID as the last soft ' +
+ 'navigation entry');
}
};
-const waitInitialLCP = () => {
- return new Promise(resolve => {
- new PerformanceObserver(list => resolve()).observe({
- type: 'largest-contentful-paint',
- buffered: true
+const waitInitialLCP =
+ () => {
+ return new Promise(resolve => {
+ new PerformanceObserver(resolve).observe(
+ {type: 'largest-contentful-paint', buffered: true});
});
- });
-}
+ }
const waitOnSoftNav = () => {
return new Promise(resolve => {
- (new PerformanceObserver(list => {
- const entries = list.getEntries();
- assert_equals(entries.length, 1,
- "Only one soft navigation entry");
- resolve(entries[0].navigationId);
- })).observe({
- type: 'soft-navigation'
- });
+ new PerformanceObserver(list => {
+ const entries = list.getEntries();
+ assert_equals(entries.length, 1, 'Only one soft navigation entry');
+ resolve(entries[0].navigationId);
+ }).observe({type: 'soft-navigation'});
});
};
const getLcpEntries = async () => {
const entries = await new Promise(resolve => {
- (new PerformanceObserver(list => resolve(
- list.getEntries()))).observe(
- {type: 'largest-contentful-paint', buffered: true,
- includeSoftNavigationObservations: true});
+ new PerformanceObserver(list => {
+ resolve(list.getEntries());
+ }).observe({
+ type: 'largest-contentful-paint',
+ buffered: true,
+ includeSoftNavigationObservations: true
});
+ });
return entries;
};
const getLcpEntriesWithoutSoftNavs = async () => {
const entries = await new Promise(resolve => {
- (new PerformanceObserver(list => resolve(
- list.getEntries()))).observe(
- {type: 'largest-contentful-paint', buffered: true});
- });
+ new PerformanceObserver(list => {
+ resolve(list.getEntries());
+ }).observe({type: 'largest-contentful-paint', buffered: true});
+ });
return entries;
};
-const addImage = async (element, url="blue.png", id = "imagelcp") => {
+const addImage = async (element, url = 'blue.png', id = 'imagelcp') => {
const img = new Image();
- img.src = '/images/'+ url + "?" + Math.random();
- img.id=id
- img.setAttribute("elementtiming", id);
+ img.src = '/images/' + url + '?' + Math.random();
+ img.id = id;
+ img.setAttribute('elementtiming', id);
await img.decode();
element.appendChild(img);
};
-const addImageToMain = async (url="blue.png", id = "imagelcp") => {
+const addImageToMain = async (url = 'blue.png', id = 'imagelcp') => {
await addImage(document.getElementById('main'), url, id);
};
-const addTextParagraphToMain = (text, element_timing = "") => {
- const main = document.getElementById("main");
- const p = document.createElement("p");
+const addTextParagraphToMain = (text, element_timing = '') => {
+ const main = document.getElementById('main');
+ const p = document.createElement('p');
const textNode = document.createTextNode(text);
p.appendChild(textNode);
if (element_timing) {
- p.setAttribute("elementtiming", element_timing);
+ p.setAttribute('elementtiming', element_timing);
}
- p.style = "font-size: 3em";
+ p.style = 'font-size: 3em';
main.appendChild(p);
return p;
};
const addTextToDivOnMain = () => {
- const main = document.getElementById("main");
- const prevDiv = document.getElementsByTagName("div")[0];
+ const main = document.getElementById('main');
+ const prevDiv = document.getElementsByTagName('div')[0];
if (prevDiv) {
main.removeChild(prevDiv);
}
- const div = document.createElement("div");
- const text = document.createTextNode("Lorem Ipsum");
+ const div = document.createElement('div');
+ const text = document.createTextNode('Lorem Ipsum');
div.appendChild(text);
- div.style = "font-size: 3em";
+ div.style = 'font-size: 3em';
main.appendChild(div);
-}
+};
const waitOnPaintEntriesPromise = (expectLCP = true) => {
return new Promise((resolve, reject) => {
if (performance.softNavPaintMetricsSupported) {
- const paint_entries = []
+ const paint_entries = [];
new PerformanceObserver(list => {
paint_entries.push(...list.getEntries());
if (paint_entries.length == 2) {
@@ -343,16 +350,18 @@ const waitOnPaintEntriesPromise = (expectLCP = true) => {
}
}).observe({type: 'paint', includeSoftNavigationObservations: true});
} else if (expectLCP) {
- new PerformanceObserver(list => {
- resolve();
- }).observe({
- type: 'largest-contentful-paint',
- includeSoftNavigationObservations: true
- });
+ new PerformanceObserver(list => {
+ resolve();
+ }).observe({
+ type: 'largest-contentful-paint',
+ includeSoftNavigationObservations: true
+ });
} else {
- step_timeout(
- () => requestAnimationFrame(() => requestAnimationFrame(resolve)),
- 100);
+ step_timeout(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(resolve);
+ });
+ }, 100);
}
});
};
diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/almost-soft-navigation.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/almost-soft-navigation.html
new file mode 100644
index 00000000000..aa5732f9fb7
--- /dev/null
+++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/almost-soft-navigation.html
@@ -0,0 +1,120 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>No Detection of Almost Soft Navigations.</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>
+ // We append this value to the URL of actualSoftNavigation() to
+ // identify the test, and to ensure it's unique.
+ let global_test_id;
+
+ // This click handler *does* cause a soft navigation, and *each test
+ // ends with detecting it*. This is by design a very simple soft
+ // navigation which we reliably detect - the same as in basic.html.
+ function actualSoftNavigation() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ history.pushState({}, "", "/actual-softnavigation?" + global_test_id);
+ }
+
+ // This click handler won't cause a soft navigation, because it
+ // doesn't change the URL.
+ function noUrlChange() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ }
+
+ // This click handler won't cause a soft navigation, because the
+ // element isn't attached to the DOM.
+ function domNotAttached() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ history.pushState({}, "", "/dom-not-attached");
+ }
+
+ // This click handler won't cause a soft navigation, because it
+ // doesn't change the DOM.
+ function noDomChange() {
+ history.pushState({}, "", "/no-dom-change");
+ }
+
+ // This click handler won't cause a soft navigation, because it
+ // doesn't paint, even though the element is attached to the DOM.
+ function noPaint() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ greeting.style.display = "none";
+ document.body.appendChild(greeting);
+ history.pushState({}, "", "/no-paint");
+ }
+
+ // This click handler won't cause a soft navigation, because it
+ // uses history.replaceState() instead of history.pushState().
+ function replaceState() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ history.replaceState({}, "", "/replace-state");
+ }
+
+ // This click handler won't cause a soft navigation, because it
+ // doesn't pass a URL to pushState().
+ function noUrlPassedToPushState() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ history.pushState({}, "");
+ }
+ </script>
+ </head>
+ <body>
+ <div id="actual-softnavigation" onclick="actualSoftNavigation()">Click here!</div>
+ <div id="no-url-change" onclick="noUrlChange()">Click here!</div>
+ <div id="dom-not-attached" onclick="domNotAttached()">Click here!</div>
+ <div id="no-dom-change" onclick="noDomChange()">Click here!</div>
+ <div id="no-paint" onclick="noPaint()">Click here!</div>
+ <div id="replace-state" onclick="replaceState()">Click here!</div>
+ <div id="no-url-passed-to-push-state" onclick="noUrlPassedToPushState()">Click here!</div>
+
+ <script>
+ function test_template(test_id, description) {
+ promise_test(() => {
+ return new Promise((resolve) => {
+ const entries = [];
+ new PerformanceObserver((list, observer) => {
+ entries.push(...list.getEntries());
+ if (entries[entries.length - 1].name.endsWith("actual-softnavigation?" + test_id)) {
+ observer.disconnect();
+ resolve(entries);
+ }
+ }).observe({ type: "soft-navigation" });
+ if (test_driver) {
+ global_test_id = test_id;
+ test_driver.click(document.getElementById(test_id));
+ test_driver.click(document.getElementById("actual-softnavigation"));
+ }
+ }).then((entries) => {
+ assert_equals(
+ entries.length,
+ 1,
+ "Expected only one soft navigation (test_id=" + test_id + ").",
+ );
+ });
+ }, description);
+ }
+
+ test_template("no-url-change", "The URL change is missing.");
+ test_template("dom-not-attached", "Creates an element but doesn't attach it to the DOM.");
+ test_template("no-paint", "Doesn't paint because the element is hidden.");
+ test_template("no-dom-change", "The DOM change is missing.");
+ test_template("replace-state", "Uses replaceState() instead of pushState().");
+ test_template("no-url-passed-to-push-state", "Doesn't pass a URL to pushState().");
+ </script>
+ </body>
+</html>
diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html
new file mode 100644
index 00000000000..66d23b22788
--- /dev/null
+++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/dom.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>The DOM Modification Criterion for Soft Navigation Detection.</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>
+ // Uses Element.innerHTML to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
+ function elementInnerHTML() {
+ document.getElementById("element-inner-html").innerHTML = "<div>Hello, World.</div>";
+ history.pushState({}, "", "/element-inner-html");
+ }
+
+ // Uses Node.appendChild to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild
+ function nodeAppendChild() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ history.pushState({}, "", "/node-append-child");
+ }
+
+ // Uses Node.insertBefore to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
+ function nodeInsertBefore() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.insertBefore(greeting, document.body.firstChild);
+ history.pushState({}, "", "/node-insert-before");
+ }
+
+ // Uses Document.importNode to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode
+ function documentImportNode() {
+ const iframe = document.getElementById("iframe-example");
+ const oldNode = iframe.contentWindow.document.getElementById("import-this");
+ const newNode = document.importNode(oldNode, true);
+ document.body.appendChild(newNode);
+ history.pushState({}, "", "/document-import-node");
+ }
+
+ // Uses Document.adoptNode to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptNode
+ function documentAdoptNode() {
+ const iframe = document.getElementById("iframe-example");
+ const oldNode = iframe.contentWindow.document.getElementById("import-this");
+ const newNode = document.adoptNode(oldNode);
+ document.body.appendChild(newNode);
+ history.pushState({}, "", "/document-adopt-node");
+ }
+
+ // Uses a template element to add to the DOM.
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template
+ function templateElement() {
+ const template = document.getElementById("template-example");
+ const cloned = template.content.cloneNode(true);
+ document.body.appendChild(cloned);
+ history.pushState({}, "", "/template-element");
+ }
+ </script>
+ </head>
+ <body>
+ <div id="element-inner-html" onclick="elementInnerHTML()">Click here!</div>
+ <div id="node-append-child" onclick="nodeAppendChild()">Click here!</div>
+ <div id="node-insert-before" onclick="nodeInsertBefore()">Click here!</div>
+ <div id="document-import-node" onclick="documentImportNode()">Click here!</div>
+ <div id="document-adopt-node" onclick="documentAdoptNode()">Click here!</div>
+ <div id="template-element" onclick="templateElement()">Click here!</div>
+
+ <iframe id="iframe-example" srcdoc="&lt;div id='import-this'>Hello, World.&lt;/div>"></iframe>
+
+ <template id="template-example">
+ <div>Hello, World.</div>
+ </template>
+
+ <script>
+ function test_template(test_id, description) {
+ promise_test(async (t) => {
+ let entries;
+ new PerformanceObserver((list, observer) => {
+ entries = list.getEntries();
+ observer.disconnect();
+ }).observe({ type: "soft-navigation" });
+ if (test_driver) {
+ test_driver.click(document.getElementById(test_id));
+ }
+ await t.step_wait(() => entries !== undefined, "Soft navigation event not fired.");
+
+ assert_equals(entries.length, 1, "Expected exactly one soft navigation.");
+ assert_equals(
+ entries[0].name.replace(/.*\//, ""),
+ test_id,
+ "URL should end with the test ID.",
+ );
+ }, description);
+ }
+
+ test_template("element-inner-html", "Soft Navigation Detection supports Element.innerHTML.");
+ test_template("node-append-child", "Soft Navigation Detection supports Node.appendChild.");
+ test_template("node-insert-before", "Soft Navigation Detection supports Node.insertBefore.");
+ test_template(
+ "document-import-node",
+ "Soft Navigation Detection supports Document.importNode.",
+ );
+ test_template(
+ "document-adopt-node",
+ "Soft Navigation Detection supports Document.adoptNode.",
+ );
+ test_template("template-element", "Soft Navigation Detection supports template elements.");
+ </script>
+ </body>
+</html>
diff --git a/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/task-attribution.html b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/task-attribution.html
new file mode 100644
index 00000000000..8f6f93c8daf
--- /dev/null
+++ b/tests/wpt/tests/soft-navigation-heuristics/smoke/tentative/task-attribution.html
@@ -0,0 +1,155 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Soft Navigation Detection: Task Attribution.</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>
+ // Appends a new div with a greeting to the document body.
+ function updateUI() {
+ const greeting = document.createElement("div");
+ greeting.textContent = "Hello, World.";
+ document.body.appendChild(greeting);
+ }
+
+ // Basic soft navigation (see basic.html) which directly does its work
+ // in the click handler. This is our baseline - the methods below
+ // differ in that they require propagating the soft navigation attribution
+ // to a different task.
+ function noSchedulingHop() {
+ updateUI();
+ history.pushState({}, "", "/no-scheduling-hop");
+ }
+
+ // A soft navigation where the click handler schedules its work with
+ // setTimeout, 0ms delay.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
+ function withSetTimeout0() {
+ setTimeout(() => {
+ updateUI();
+ history.pushState({}, "", "/with-set-timeout-0");
+ }, 0);
+ }
+
+ // A soft navigation where the click handler schedules its work with
+ // setTimeout, 10ms delay.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
+ function withSetTimeout10() {
+ setTimeout(() => {
+ updateUI();
+ history.pushState({}, "", "/with-set-timeout-10");
+ }, 10);
+ }
+
+ // A soft navigation where the click handler schedules its work with
+ // two setTimeouts.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
+ function twoSetTimeouts() {
+ setTimeout(updateUI, 20);
+ setTimeout(() => {
+ history.pushState({}, "", "/two-set-timeouts");
+ }, 10);
+ }
+
+ // A soft navigation where the click handler schedules its UI work with
+ // setTimeout and the URL update with a sync history.pushState call.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
+ function setTimeoutAndSyncUrlUpdate() {
+ setTimeout(updateUI, 10);
+ history.pushState({}, "", "/set-timeout-and-sync-url-update");
+ }
+
+ // A soft navigation where the click handler synchronously updates its UI
+ // and schedules the URL update with a setTimeout.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
+ function setTimeoutForUrlUpdate() {
+ updateUI();
+ setTimeout(() => {
+ history.pushState({}, "", "/set-timeout-for-url-update");
+ }, 10);
+ }
+
+ // A soft navigation where the click handler schedules its work with
+ // scheduler.postTask.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask
+ function withSchedulerPostTask() {
+ scheduler.postTask(() => {
+ updateUI();
+ history.pushState({}, "", "/with-scheduler-post-task");
+ });
+ }
+
+ // A soft navigation where the click handler yields
+ // (using scheduler.yield) between UI update and URL update.
+ async function withSchedulerYield() {
+ updateUI();
+ await scheduler.yield();
+ history.pushState({}, "", "/with-scheduler-yield");
+ }
+
+ // A soft navigation where the click handler schedules its work with
+ // requestAnimationFrame.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
+ function withRequestAnimationFrame() {
+ requestAnimationFrame(() => {
+ updateUI();
+ history.pushState({}, "", "/with-request-animation-frame");
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <div id="no-scheduling-hop" onclick="noSchedulingHop()">Click here!</div>
+ <div id="with-set-timeout-0" onclick="withSetTimeout0()">Click here!</div>
+ <div id="with-set-timeout-10" onclick="withSetTimeout10()">Click here!</div>
+ <div id="two-set-timeouts" onclick="twoSetTimeouts()">Click here!</div>
+ <div id="set-timeout-and-sync-url-update" onclick="setTimeoutAndSyncUrlUpdate()">
+ Click here!
+ </div>
+ <div id="set-timeout-for-url-update" onclick="setTimeoutForUrlUpdate()">Click here!</div>
+ <div id="with-scheduler-post-task" onclick="withSchedulerPostTask()">Click here!</div>
+ <div id="with-scheduler-yield" onclick="withSchedulerYield()">Click here!</div>
+ <div id="with-request-animation-frame" onclick="withRequestAnimationFrame()">Click here!</div>
+
+ <script>
+ function test_template(test_id, description) {
+ promise_test(async (t) => {
+ let entries;
+ new PerformanceObserver((list, observer) => {
+ entries = list.getEntries();
+ observer.disconnect();
+ }).observe({ type: "soft-navigation" });
+ if (test_driver) {
+ test_driver.click(document.getElementById(test_id));
+ }
+ await t.step_wait(() => entries !== undefined, "Soft navigation event not fired.");
+
+ assert_equals(entries.length, 1, "Expected exactly one soft navigation.");
+ assert_equals(
+ entries[0].name.replace(/.*\//, ""),
+ test_id,
+ "URL should end with the test ID.",
+ );
+ }, description);
+ }
+
+ test_template("no-scheduling-hop", "No scheduling hop.");
+ test_template("with-set-timeout-0", "With set_timeout, 0ms delay.");
+ test_template("with-set-timeout-10", "With set_timeout, 10ms delay.");
+ test_template("two-set-timeouts", "With two set_timeouts.");
+ test_template("set-timeout-and-sync-url-update", "With set_timeout and sync URL update.");
+ if (scheduler.postTask) {
+ // Skip test if scheduler.postTask is not supported.
+ test_template("with-scheduler-post-task", "With scheduler.postTask.");
+ }
+ if (scheduler.yield) {
+ // Skip test if scheduler.yield is not supported.
+ test_template("with-scheduler-yield", "With scheduler.yield.");
+ }
+ test_template("with-request-animation-frame", "With requestAnimationFrame.");
+ </script>
+ </body>
+</html>
diff --git a/tests/wpt/tests/soft-navigation-heuristics/soft-navigation-no-url.tentative.html b/tests/wpt/tests/soft-navigation-heuristics/soft-navigation-no-url.tentative.html
deleted file mode 100644
index a0055c654c2..00000000000
--- a/tests/wpt/tests/soft-navigation-heuristics/soft-navigation-no-url.tentative.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Detect simple soft navigation.</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/soft-navigation-helper.js"></script>
-</head>
-<body>
- <main id=main>
- <a id=link>Click me!</a>
- </main>
- <script>
- const link = document.getElementById("link");
- testSoftNavigationNotDetected({
- eventHandler: url => {
- addTextToDivOnMain();
- history.pushState({}, '');
- },
- link: link,
- eventName: "click",
- eventTarget: link,
- testName: "Test that a soft navigation is not detected when a URL is not"
- + " passed to the history API."});
- </script>
-</body>
-</html>
-
diff --git a/tests/wpt/tests/speculation-rules/prefetch/resources/utils.sub.js b/tests/wpt/tests/speculation-rules/prefetch/resources/utils.sub.js
index d4efc2dc7dc..adb15d4ea9e 100644
--- a/tests/wpt/tests/speculation-rules/prefetch/resources/utils.sub.js
+++ b/tests/wpt/tests/speculation-rules/prefetch/resources/utils.sub.js
@@ -227,6 +227,18 @@ function assert_intercept_prefetch(interceptedRequest, expectedUrl) {
assert_prefetched(interceptedRequest.request.headers,
"Prefetch request should be intercepted.");
+
+ if (new URL(location.href).searchParams.has('clientId')) {
+ // https://github.com/WICG/nav-speculation/issues/346
+ // https://crbug.com/404294123
+ assert_equals(interceptedRequest.resultingClientId, "",
+ "resultingClientId shouldn't be exposed.");
+
+ // https://crbug.com/404286918
+ // `assert_not_equals()` isn't used for now to create stable failure diffs.
+ assert_false(interceptedRequest.clientId === "",
+ "clientId should be initiator.");
+ }
}
// The ServiceWorker fetch handler intercepted a non-prefetching request.
@@ -236,6 +248,16 @@ function assert_intercept_non_prefetch(interceptedRequest, expectedUrl) {
assert_not_prefetched(interceptedRequest.request.headers,
"Non-prefetch request should be intercepted.");
+
+ if (new URL(location.href).searchParams.has('clientId')) {
+ // Because this is an ordinal non-prefetch request, `resultingClientId`
+ // can be set as normal.
+ assert_not_equals(interceptedRequest.resultingClientId, "",
+ "resultingClientId can be exposed.");
+
+ assert_not_equals(interceptedRequest.clientId, "",
+ "clientId should be initiator.");
+ }
}
// Use nvs_header query parameter to ask the wpt server
diff --git a/tests/wpt/tests/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html b/tests/wpt/tests/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
index 98e089bcc66..5b2a4d00dba 100644
--- a/tests/wpt/tests/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
+++ b/tests/wpt/tests/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
@@ -15,11 +15,23 @@
<meta name="variant" content="?origin=same-site&sw=no-fetch-handler">
<meta name="variant" content="?origin=same-site&sw=no-controller">
+<meta name="variant" content="?origin=same-site&sw=fetch-handler&clientId">
+<meta name="variant" content="?origin=same-site&sw=fetch-handler-to-fallback&clientId">
+<meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-url&clientId">
+<meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-referrer&clientId">
+<meta name="variant" content="?origin=same-site&sw=no-fetch-handler&clientId">
+<meta name="variant" content="?origin=same-site&sw=no-controller&clientId">
+
<meta name="variant" content="?origin=cross-site&sw=fetch-handler">
<meta name="variant" content="?origin=cross-site&sw=fetch-handler-to-fallback">
<meta name="variant" content="?origin=cross-site&sw=no-fetch-handler">
<meta name="variant" content="?origin=cross-site&sw=no-controller">
+<meta name="variant" content="?origin=cross-site&sw=fetch-handler&clientId">
+<meta name="variant" content="?origin=cross-site&sw=fetch-handler-to-fallback&clientId">
+<meta name="variant" content="?origin=cross-site&sw=no-fetch-handler&clientId">
+<meta name="variant" content="?origin=cross-site&sw=no-controller&clientId">
+
<script>
setup(() => assertSpeculationRulesIsSupported());
diff --git a/tests/wpt/tests/speech-api/SpeechRecognition-availableOnDevice.https.html b/tests/wpt/tests/speech-api/SpeechRecognition-availableOnDevice.https.html
index db48f2a7a6f..ace8edd9164 100644
--- a/tests/wpt/tests/speech-api/SpeechRecognition-availableOnDevice.https.html
+++ b/tests/wpt/tests/speech-api/SpeechRecognition-availableOnDevice.https.html
@@ -5,7 +5,8 @@
<script>
promise_test(async (t) => {
const lang = "en-US";
- window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
+ window.SpeechRecognition = window.SpeechRecognition ||
+ window.webkitSpeechRecognition;
// Test that it returns a promise.
const resultPromise = SpeechRecognition.availableOnDevice(lang);
@@ -24,7 +25,8 @@ promise_test(async (t) => {
assert_true(
result === "unavailable" || result === "downloadable" ||
result === "downloading" || result === "available",
- "The resolved value of the availableOnDevice promise should be a valid value."
+ "The resolved value of the availableOnDevice promise should be a " +
+ "valid value."
);
}, "SpeechRecognition.availableOnDevice resolves with a string value.");
@@ -44,4 +46,138 @@ promise_test(async (t) => {
frameSpeechRecognition.availableOnDevice("en-US"),
);
}, "SpeechRecognition.availableOnDevice rejects in a detached context.");
+
+promise_test(async (t) => {
+ const iframe = document.createElement("iframe");
+ // This policy should make the on-device speech recognition
+ // feature unavailable.
+ iframe.setAttribute("allow", "on-device-speech-recognition 'none'");
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ await new Promise(resolve => {
+ if (iframe.contentWindow &&
+ iframe.contentWindow.document.readyState === 'complete') {
+ resolve();
+ } else {
+ iframe.onload = resolve;
+ }
+ });
+
+ const frameWindow = iframe.contentWindow;
+ const frameSpeechRecognition = frameWindow.SpeechRecognition ||
+ frameWindow.webkitSpeechRecognition;
+
+ assert_true(!!frameSpeechRecognition,
+ "SpeechRecognition should exist in iframe.");
+ assert_true(!!frameSpeechRecognition.availableOnDevice,
+ "availableOnDevice method should exist on SpeechRecognition in iframe.");
+
+ // Call availableOnDevice and expect it to resolve to "unavailable".
+ const availabilityStatus =
+ await frameSpeechRecognition.availableOnDevice("en-US");
+ assert_equals(availabilityStatus, "unavailable",
+ "availableOnDevice should resolve to 'unavailable' if " +
+ "'on-device-speech-recognition' Permission Policy is 'none'."
+ );
+}, "SpeechRecognition.availableOnDevice resolves to 'unavailable' if " +
+ "'on-device-speech-recognition' Permission Policy is 'none'.");
+
+promise_test(async (t) => {
+ const html = `
+ <!DOCTYPE html>
+ <script>
+ window.addEventListener('message', async (event) => {
+ // Ensure we only process the message intended to trigger the test.
+ if (event.data !== "runTestCallAvailableOnDevice") return;
+
+ try {
+ const SpeechRecognition = window.SpeechRecognition ||
+ window.webkitSpeechRecognition;
+ if (!SpeechRecognition || !SpeechRecognition.availableOnDevice) {
+ parent.postMessage({
+ type: "error", // Use "error" for API not found or other issues.
+ name: "NotSupportedError",
+ message: "SpeechRecognition.availableOnDevice API not " +
+ "available in iframe"
+ }, "*");
+ return;
+ }
+
+ // Call availableOnDevice and post its resolution.
+ const availabilityStatus =
+ await SpeechRecognition.availableOnDevice("en-US");
+ parent.postMessage(
+ { type: "resolution", result: availabilityStatus },
+ "*"
+ ); // Post the string status
+ } catch (err) {
+ // Catch any unexpected errors during the API call or message post.
+ parent.postMessage({
+ type: "error",
+ name: err.name,
+ message: err.message
+ }, "*");
+ }
+ });
+ <\/script>
+ `;
+
+ const blob = new Blob([html], { type: "text/html" });
+ const blobUrl = URL.createObjectURL(blob);
+ // Important: Revoke the blob URL after the test to free up resources.
+ t.add_cleanup(() => URL.revokeObjectURL(blobUrl));
+
+ const iframe = document.createElement("iframe");
+ iframe.src = blobUrl;
+ // Sandboxing with "allow-scripts" is needed for the script inside
+ // the iframe to run.
+ // The cross-origin nature is primarily due to the blob URL's origin being
+ // treated as distinct from the parent page's origin for security
+ // purposes.
+ iframe.setAttribute("sandbox", "allow-scripts");
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ await new Promise(resolve => iframe.onload = resolve);
+
+ const testResult = await new Promise((resolve, reject) => {
+ const timeoutId = t.step_timeout(() => {
+ reject(new Error("Test timed out waiting for message from iframe. " +
+ "Ensure iframe script is correctly posting a message."));
+ }, 6000); // 6-second timeout
+
+ window.addEventListener("message", t.step_func((event) => {
+ // Basic check to ensure the message is from our iframe.
+ if (event.source !== iframe.contentWindow) return;
+ clearTimeout(timeoutId);
+ resolve(event.data);
+ }));
+
+ // Send a distinct message to the iframe to trigger its test logic.
+ iframe.contentWindow.postMessage("runTestCallAvailableOnDevice", "*");
+ });
+
+ // Check if the iframe's script reported an error (e.g., API not found).
+ if (testResult.type === "error") {
+ const errorMessage =
+ `Iframe reported an error: ${testResult.name} - ` +
+ testResult.message;
+ assert_unreached(errorMessage);
+ }
+
+ assert_equals(
+ testResult.type,
+ "resolution",
+ "The call from the iframe should resolve and post a 'resolution' " +
+ "message."
+ );
+ assert_equals(
+ testResult.result, // Expecting the string "unavailable".
+ "unavailable",
+ "availableOnDevice should resolve to 'unavailable' in a cross-origin " +
+ "iframe."
+ );
+}, "SpeechRecognition.availableOnDevice should resolve to 'unavailable' " +
+ "in a cross-origin iframe.");
</script>
diff --git a/tests/wpt/tests/speech-api/SpeechRecognition-basics.https.html b/tests/wpt/tests/speech-api/SpeechRecognition-basics.https.html
index 827844096f6..91cf8e6d3e5 100644
--- a/tests/wpt/tests/speech-api/SpeechRecognition-basics.https.html
+++ b/tests/wpt/tests/speech-api/SpeechRecognition-basics.https.html
@@ -12,6 +12,6 @@ test(function() {
assert_false(reco.interimResults, 'SpeechRecognition.interimResults');
assert_equals(reco.maxAlternatives, 1, 'SpeechRecognition.maxAlternatives');
assert_equals(reco.mode, 'ondevice-preferred', 'SpeechRecognition.mode');
- assert_equals(reco.phrases, null, 'SpeechRecognition.phrases');
+ assert_equals(reco.phrases.length, 0, 'SpeechRecognition.phrases.length');
});
</script>
diff --git a/tests/wpt/tests/speech-api/SpeechRecognition-installOnDevice.https.html b/tests/wpt/tests/speech-api/SpeechRecognition-installOnDevice.https.html
index 2f5b359c571..5f78fc8c9c1 100644
--- a/tests/wpt/tests/speech-api/SpeechRecognition-installOnDevice.https.html
+++ b/tests/wpt/tests/speech-api/SpeechRecognition-installOnDevice.https.html
@@ -7,92 +7,128 @@
<script>
promise_test(async (t) => {
const validLang = "en-US";
+ const validLangAlternateLocale = "en-GB";
const invalidLang = "invalid language code";
- const validDownloadableLang = "fr-FR";
window.SpeechRecognition =
window.SpeechRecognition || window.webkitSpeechRecognition;
- // Attempt to call installOnDevice directly, without a user gesture with a
- // language that is downloadable but not installed.
- const installWithoutUserGesturePromise =
- SpeechRecognition.installOnDevice(validDownloadableLang);
-
- // Assert that the promise rejects with NotAllowedError.
- await promise_rejects_dom(
- t,
- "NotAllowedError",
- window.DOMException,
- installWithoutUserGesturePromise,
- "SpeechRecognition.installOnDevice() must reject with NotAllowedError if " +
- "called without a user gesture."
- );
-
- // Test that it returns a promise when called with a valid language.
- const validResultPromise = test_driver.bless(
- "Call SpeechRecognition.installOnDevice with a valid language",
- () => SpeechRecognition.installOnDevice(validLang)
- );
+ // Check the availablility of the on-device language pack.
+ const initialAvailabilityPromise =
+ SpeechRecognition.availableOnDevice(validLang);
assert_true(
- validResultPromise instanceof Promise,
- "installOnDevice (with gesture) should return a Promise."
+ initialAvailabilityPromise instanceof Promise,
+ "availableOnDevice should return a Promise."
);
- // Verify the resolved value is a boolean.
- const validResult = await validResultPromise;
+ const initialAvailabilityResult = await initialAvailabilityPromise;
assert_true(
- typeof validResult === "boolean",
- "The resolved value of the installOnDevice promise should be a boolean."
+ typeof initialAvailabilityResult === "string",
+ "The resolved value of the availableOnDevice promise should be a string."
);
- // Verify that the method returns true when called with a supported language.
- assert_equals(
- validResult,
- true,
- "installOnDevice should resolve with `true` when called with a " +
+ if (initialAvailabilityResult === "downloadable") {
+ // Attempt to call installOnDevice directly, without a user gesture with a
+ // language that is downloadable but not installed.
+ const installWithoutUserGesturePromise =
+ SpeechRecognition.installOnDevice(validLang);
+
+ // Assert that the promise rejects with NotAllowedError.
+ await promise_rejects_dom(
+ t,
+ "NotAllowedError",
+ window.DOMException,
+ installWithoutUserGesturePromise, "SpeechRecognition.installOnDevice() " +
+ "must reject with NotAllowedError if called without a user gesture."
+ );
+
+ // Test that it returns a promise when called with a valid language.
+ const validResultPromise = test_driver.bless(
+ "Call SpeechRecognition.installOnDevice with a valid language",
+ () => SpeechRecognition.installOnDevice(validLang)
+ );
+ assert_true(
+ validResultPromise instanceof Promise,
+ "installOnDevice (with gesture) should return a Promise."
+ );
+
+ // Verify the resolved value is a boolean.
+ const validResult = await validResultPromise;
+ assert_true(
+ typeof validResult === "boolean",
+ "The resolved value of the installOnDevice promise should be a boolean."
+ );
+
+ // Verify that the method returns true when called with a supported language.
+ assert_equals(
+ validResult,
+ true,
+ "installOnDevice should resolve with `true` when called with a " +
"supported language code."
- );
+ );
- // Verify that the newly installed language pack is available.
- const availableOnDeviceResultPromise =
- SpeechRecognition.availableOnDevice(validLang);
- assert_true(
- availableOnDeviceResultPromise instanceof Promise,
- "availableOnDevice should return a Promise."
- );
+ // Verify that the newly installed language pack is available.
+ const availableOnDeviceResultPromise =
+ SpeechRecognition.availableOnDevice(validLang);
+ assert_true(
+ availableOnDeviceResultPromise instanceof Promise,
+ "availableOnDevice should return a Promise."
+ );
- const availableOnDeviceResult = await availableOnDeviceResultPromise;
- assert_true(
- typeof availableOnDeviceResult === "string",
- "The resolved value of the availableOnDevice promise should be a string."
- );
+ const availableOnDeviceResult = await availableOnDeviceResultPromise;
+ assert_true(
+ typeof availableOnDeviceResult === "string",
+ "The resolved value of the availableOnDevice promise should be a string."
+ );
- assert_true(
- availableOnDeviceResult === "available",
- "The resolved value of the availableOnDevice promise should be 'available'."
- );
+ assert_true(
+ availableOnDeviceResult === "available",
+ "The resolved value of the availableOnDevice promise should be " +
+ "'available'."
+ );
- // Verify that installing an already installed language resolves to true.
- const secondResultPromise = test_driver.bless(
- "Call SpeechRecognition.installOnDevice for an already installed language",
- () => SpeechRecognition.installOnDevice(validLang)
- );
- assert_true(
- secondResultPromise instanceof Promise,
- "installOnDevice (with gesture, for already installed language) should " +
+ // Verify that the newly installed language pack is available for an alternate locale.
+ const alternateLocaleResultPromise =
+ SpeechRecognition.availableOnDevice(validLangAlternateLocale);
+ assert_true(
+ alternateLocaleResultPromise instanceof Promise,
+ "availableOnDevice should return a Promise."
+ );
+
+ const alternateLocaleResult = await alternateLocaleResultPromise;
+ assert_true(
+ typeof alternateLocaleResult === "string",
+ "The resolved value of the availableOnDevice promise should be a string."
+ );
+
+ assert_true(
+ alternateLocaleResult === "available",
+ "The resolved value of the availableOnDevice promise should be " +
+ "'available'."
+ );
+
+ // Verify that installing an already installed language resolves to true.
+ const secondResultPromise = test_driver.bless(
+ "Call SpeechRecognition.installOnDevice for an already installed language",
+ () => SpeechRecognition.installOnDevice(validLang)
+ );
+ assert_true(
+ secondResultPromise instanceof Promise,
+ "installOnDevice (with gesture, for already installed language) should " +
"return a Promise."
- );
- const secondResult = await secondResultPromise;
- assert_true(
- typeof secondResult === "boolean",
- "The resolved value of the second installOnDevice promise should be a " +
- "boolean."
- );
- assert_equals(
- secondResult,
- true,
- "installOnDevice should resolve with `true` if the language is already " +
+ );
+ const secondResult = await secondResultPromise;
+ assert_true(
+ typeof secondResult === "boolean",
+ "The resolved value of the second installOnDevice promise should be a " +
+ "boolean."
+ );
+ assert_equals(
+ secondResult,
+ true,
+ "installOnDevice should resolve with `true` if the language is already " +
"installed."
- );
+ );
+ }
// Test that it returns a promise and resolves to false for unsupported lang.
const invalidResultPromise = test_driver.bless(
@@ -114,7 +150,7 @@ promise_test(async (t) => {
invalidResult,
false,
"installOnDevice should resolve with `false` when called with an " +
- "unsupported language code."
+ "unsupported language code."
);
}, "SpeechRecognition.installOnDevice resolves with a boolean value " +
"(with user gesture).");
@@ -139,6 +175,116 @@ promise_test(async (t) => {
}
)
);
-}, "SpeechRecognition.installOnDevice rejects in a detached context " +
- "(with user gesture).");
+}, "SpeechRecognition.installOnDevice rejects in a detached context.");
+
+promise_test(async (t) => {
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("allow",
+ "on-device-speech-recognition 'none'");
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ await new Promise(resolve => {
+ if (iframe.contentWindow &&
+ iframe.contentWindow.document.readyState === 'complete') {
+ resolve();
+ } else {
+ iframe.onload = resolve;
+ }
+ });
+
+ const frameWindow = iframe.contentWindow;
+ const frameSpeechRecognition = frameWindow.SpeechRecognition ||
+ frameWindow.webkitSpeechRecognition;
+ const frameDOMException = frameWindow.DOMException;
+
+ assert_true(!!frameSpeechRecognition,
+ "SpeechRecognition should exist in iframe.");
+ assert_true(!!frameSpeechRecognition.installOnDevice,
+ "installOnDevice method should exist on SpeechRecognition in iframe.");
+
+ await promise_rejects_dom(
+ t,
+ "NotAllowedError",
+ frameDOMException,
+ frameSpeechRecognition.installOnDevice("en-US"),
+ "installOnDevice should reject with NotAllowedError if " +
+ "'install-on-device-speech-recognition' Permission Policy is " +
+ "disabled."
+ );
+}, "SpeechRecognition.installOnDevice rejects if " +
+ "'install-on-device-speech-recognition' Permission Policy is disabled.");
+
+promise_test(async (t) => {
+ const html = `
+ <!DOCTYPE html>
+ <script>
+ window.addEventListener('message', async (event) => {
+ try {
+ const SpeechRecognition = window.SpeechRecognition ||
+ window.webkitSpeechRecognition;
+ if (!SpeechRecognition || !SpeechRecognition.installOnDevice) {
+ parent.postMessage({
+ type: "rejection",
+ name: "NotSupportedError",
+ message: "API not available"
+ }, "*");
+ return;
+ }
+
+ await SpeechRecognition.installOnDevice("en-US");
+ parent.postMessage({ type: "resolution", result: "success" }, "*");
+ } catch (err) {
+ parent.postMessage({
+ type: "rejection",
+ name: err.name,
+ message: err.message
+ }, "*");
+ }
+ });
+ <\/script>
+ `;
+
+ // Create a cross-origin Blob URL by fetching from remote origin
+ const blob = new Blob([html], { type: "text/html" });
+ const blobUrl = URL.createObjectURL(blob);
+
+ const iframe = document.createElement("iframe");
+ iframe.src = blobUrl;
+ iframe.setAttribute("sandbox", "allow-scripts");
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ await new Promise(resolve => iframe.onload = resolve);
+
+ const testResult = await new Promise((resolve, reject) => {
+ const timeoutId = t.step_timeout(() => {
+ reject(new Error("Timed out waiting for message from iframe"));
+ }, 6000);
+
+ window.addEventListener("message", t.step_func((event) => {
+ if (event.source !== iframe.contentWindow) return;
+ clearTimeout(timeoutId);
+ resolve(event.data);
+ }));
+
+ iframe.contentWindow.postMessage("runTest", "*");
+ });
+
+ assert_equals(
+ testResult.type,
+ "rejection",
+ "Should reject due to cross-origin restriction"
+ );
+ assert_equals(
+ testResult.name,
+ "NotAllowedError",
+ "Should reject with NotAllowedError"
+ );
+ assert_true(
+ testResult.message.includes("cross-origin iframe") ||
+ testResult.message.includes("cross-site subframe"),
+ `Error message should reference cross-origin. Got: "${testResult.message}"`
+ );
+}, "SpeechRecognition.installOnDevice should reject in a cross-origin iframe.");
</script>
diff --git a/tests/wpt/tests/speech-api/SpeechRecognition-recognitionContext-manual.https.html b/tests/wpt/tests/speech-api/SpeechRecognition-phrases-manual.https.html
index 1039baa2825..2d0b19ab46c 100644
--- a/tests/wpt/tests/speech-api/SpeechRecognition-recognitionContext-manual.https.html
+++ b/tests/wpt/tests/speech-api/SpeechRecognition-phrases-manual.https.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<html lang="en">
-<title>SpeechRecognition RecognitionContext</title>
+<title>SpeechRecognition Phrases</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -29,42 +29,41 @@ promise_test(async (t) => {
"Audio track should be a valid MediaStreamTrack"
);
- // Create the recognition context.
- var list = new SpeechRecognitionPhraseList();
- list.addItem(new SpeechRecognitionPhrase("ASIC", 1.0));
- list.addItem(new SpeechRecognitionPhrase("FPGA", 1.0));
- var context = new SpeechRecognitionContext(list);
-
- // Create the first speech recognition with a mode that does not support
- // recognition context. Note that this may vary between browsers in the future.
+ // Create the first speech recognition with a mode that does not support contextual biasing.
+ // Note that this may vary between browsers in the future.
window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition1 = new SpeechRecognition();
recognition1.mode = "cloud-only";
recognition1.lang = "en-US";
- recognition1.context = context;
recognition1.onerror = function(event) {
assert_equals(
event.error,
- "recognition-context-not-supported",
- "First speech recognition should throw a recognition-context-not-supported error"
+ "phrases-not-supported",
+ "First speech recognition should throw a phrases-not-supported error"
);
};
- recognition1.start(audioTrack);
+ recognition1.phrases = new SpeechRecognitionPhraseList([
+ new SpeechRecognitionPhrase("test", 1.0)
+ ]);
- // Create the second speech recognition with a mode that supports recognition context.
+ // Create the second speech recognition with a mode that supports contextual biasing.
const recognition2 = new SpeechRecognition();
recognition2.mode = "ondevice-only";
recognition2.lang = "en-US";
- recognition2.context = context;
recognition2.onerror = function(event) {
// Currently WPT may not be able to detect that SODA is available and
// will throw a "language-not-supported" error here.
- assert_unreached();
+ assert_unreached("Caught an error: " + event.error);
};
+ recognition2.phrases = new SpeechRecognitionPhraseList([
+ new SpeechRecognitionPhrase("ASIC", 1.0),
+ new SpeechRecognitionPhrase("FPGA", 1.0)
+ ]);
+
const recognitionPromise = new Promise((resolve) => {
recognition2.onresult = (event) => {
const transcript = event.results[0][0].transcript;
@@ -80,6 +79,6 @@ promise_test(async (t) => {
"the fpga's latency were both below expectations",
"Second speech recognition should correctly recognize the phrases"
);
-}, "SpeechRecognition should recognize speech with the given recognition context.");
+}, "SpeechRecognition should recognize speech with the given contextual information.");
</script>
</html>
diff --git a/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.js b/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.js
index 21592a9225f..91826bcbaeb 100644
--- a/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.js
+++ b/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-origin-fetch.sub.https.window.js
@@ -20,6 +20,7 @@
t.add_cleanup(async () => {
await test_driver.delete_all_cookies();
await SetPermissionInFrame(frame, [{ name: 'storage-access' }, 'prompt']);
+ await DeleteCookieInFrame(frame, "cookie", "Secure;SameSite=None;Path=/;Domain={{hosts[alt][]}}");
});
return frame;
diff --git a/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.js b/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.js
index b46f42d1211..f0c9ff91ef7 100644
--- a/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.js
+++ b/tests/wpt/tests/storage-access-api/requestStorageAccess-cross-site-fetch.sub.https.window.js
@@ -17,6 +17,7 @@ async function SetUpResponderFrame(t, url) {
t.add_cleanup(async () => {
await test_driver.delete_all_cookies();
await SetPermissionInFrame(frame, [{ name: 'storage-access' }, 'prompt']);
+ await DeleteCookieInFrame(frame, "cookie", "Secure;SameSite=None;Path=/;Domain={{hosts[alt][]}}");
});
return frame;
diff --git a/tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.https.html b/tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.html
index 205854419a7..205854419a7 100644
--- a/tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.https.html
+++ b/tests/wpt/tests/subresource-integrity/tentative/integrity-policy/parsing.html
diff --git a/tests/wpt/tests/tools/ci/requirements_build.txt b/tests/wpt/tests/tools/ci/requirements_build.txt
index 60c09170a98..4fb858bbd5f 100644
--- a/tests/wpt/tests/tools/ci/requirements_build.txt
+++ b/tests/wpt/tests/tools/ci/requirements_build.txt
@@ -3,3 +3,4 @@ fonttools==4.51.0
genshi==0.7.7
jinja2==3.1.6
pyyaml==6.0.1
+types-pyyaml==6.0.12.20241230
diff --git a/tests/wpt/tests/tools/ci/requirements_tc.txt b/tests/wpt/tests/tools/ci/requirements_tc.txt
index ada75c2f761..e1d74e856b1 100644
--- a/tests/wpt/tests/tools/ci/requirements_tc.txt
+++ b/tests/wpt/tests/tools/ci/requirements_tc.txt
@@ -1,4 +1,6 @@
pygithub==2.6.1
pyyaml==6.0.1
+types-pyyaml==6.0.12.20241230
requests==2.32.3
+types-requests==2.32.0.20241016
taskcluster==83.5.8
diff --git a/tests/wpt/tests/tools/docker/requirements.txt b/tests/wpt/tests/tools/docker/requirements.txt
index b275ccfd8f1..be30f18fb3a 100644
--- a/tests/wpt/tests/tools/docker/requirements.txt
+++ b/tests/wpt/tests/tools/docker/requirements.txt
@@ -1,2 +1,4 @@
pyyaml==6.0.1
+types-pyyaml==6.0.12.20241230
requests==2.32.3
+types-requests==2.32.0.20241016
diff --git a/tests/wpt/tests/tools/manifest/download.py b/tests/wpt/tests/tools/manifest/download.py
index 8527fb232ac..8b119abacec 100644
--- a/tests/wpt/tests/tools/manifest/download.py
+++ b/tests/wpt/tests/tools/manifest/download.py
@@ -5,13 +5,13 @@ import json
import io
import os
from datetime import datetime, timedelta
-from typing import Any, Callable, List, Optional, Text
+from typing import Any, Callable, List, Optional, Text, cast
from urllib.request import urlopen
try:
import zstandard
except ImportError:
- zstandard = None
+ zstandard = cast(Any, None)
from .utils import git
diff --git a/tests/wpt/tests/tools/manifest/sourcefile.py b/tests/wpt/tests/tools/manifest/sourcefile.py
index 4e74fb20770..8682c233e88 100644
--- a/tests/wpt/tests/tools/manifest/sourcefile.py
+++ b/tests/wpt/tests/tools/manifest/sourcefile.py
@@ -5,7 +5,7 @@ from collections import deque
from fnmatch import fnmatch
from io import BytesIO
from typing import (Any, BinaryIO, Callable, Deque, Dict, Iterable, List,
- Optional, Pattern, Set, Text, Tuple, TypedDict, Union, cast)
+ Optional, Pattern, Set, Text, Tuple, TypedDict, Union)
from urllib.parse import parse_qs, urlparse, urljoin
try:
@@ -39,7 +39,7 @@ python_meta_re = re.compile(br"#\s*META:\s*(\w*)=(.*)$")
reference_file_re = re.compile(r'(^|[\-_])(not)?ref[0-9]*([\-_]|$)')
-space_chars: Text = "".join(html5lib.constants.spaceCharacters)
+space_chars: Text = "".join(html5lib.constants.spaceCharacters) # type: ignore[attr-defined]
def replace_end(s: Text, old: Text, new: Text) -> Text:
@@ -179,8 +179,7 @@ def global_variant_url(url: Text, suffix: Text) -> Text:
def _parse_html(f: BinaryIO) -> ElementTree.Element:
- doc = html5lib.parse(f, treebuilder="etree", useChardet=False)
- return cast(ElementTree.Element, doc)
+ return html5lib.parse(f, treebuilder="etree", useChardet=False)
def _parse_xml(f: BinaryIO) -> ElementTree.Element:
try:
diff --git a/tests/wpt/tests/tools/metadata/yaml/requirements.txt b/tests/wpt/tests/tools/metadata/yaml/requirements.txt
index cf39afa6b4c..1a151295165 100644
--- a/tests/wpt/tests/tools/metadata/yaml/requirements.txt
+++ b/tests/wpt/tests/tools/metadata/yaml/requirements.txt
@@ -1 +1,2 @@
pyyaml==6.0.1
+types-pyyaml==6.0.12.20241230
diff --git a/tests/wpt/tests/tools/mypy.ini b/tests/wpt/tests/tools/mypy.ini
index e05220f4bbe..22259b03aab 100644
--- a/tests/wpt/tests/tools/mypy.ini
+++ b/tests/wpt/tests/tools/mypy.ini
@@ -7,7 +7,7 @@
# - tools/wptserve/docs/conf.py (generated code)
# - tools/wptserve/tests/ (deliberately invalid syntax)
exclude = (^tools/third_party/|/setup\.py$|^tools/wptserve/docs/conf.py|^tools/wptserve/tests/|^tools/third_party_modified/mozlog/|^tools/wptserve/wptserve/cgi/test_cgi\.py$)
-mypy_path = tools/wptrunner:tools/wptserve:tools/webdriver:tools/webtransport
+mypy_path = tools/wptrunner:tools/wptserve:tools/webdriver:tools/webtransport:tools/third_party/h2/src:tools/third_party/hpack/src:tools/third_party/hyperframe/src:tools/third_party/pywebsocket3:tools/third_party/websockets/src
#check_untyped_defs = True
disallow_any_generics = True
disallow_incomplete_defs = True
@@ -25,36 +25,30 @@ warn_unreachable = True
show_error_codes = True
-# Ignore missing or untyped libraries.
-
-[mypy-Cocoa.*]
-ignore_missing_imports = True
-
-[mypy-ColorSync.*]
-ignore_missing_imports = True
-
-[mypy-Quartz.*]
-ignore_missing_imports = True
+# Don't type check third_party things
+[mypy-h2.*]
+follow_imports = silent
-[mypy-cgi.*]
-ignore_missing_imports = True
+[mypy-hpack.*]
+follow_imports = silent
-[mypy-github.*]
-ignore_missing_imports = True
+[mypy-hyperframe.*]
+follow_imports = silent
-[mypy-h2.*]
-ignore_missing_imports = True
+[mypy-pywebsocket3.*]
+follow_imports = silent
-[mypy-hpack.*]
-ignore_missing_imports = True
+[mypy-websockets.*]
+follow_imports = silent
-[mypy-html5lib.*]
+# Ignore missing or untyped libraries.
+[mypy-Cocoa.*]
ignore_missing_imports = True
-[mypy-hyperframe.*]
+[mypy-ColorSync.*]
ignore_missing_imports = True
-[mypy-hypothesis.*]
+[mypy-Quartz.*]
ignore_missing_imports = True
[mypy-marionette_driver.*]
@@ -81,9 +75,6 @@ ignore_missing_imports = True
[mypy-mozlog.*]
ignore_missing_imports = True
-[mypy-moznetwork.*]
-ignore_missing_imports = True
-
[mypy-mozprocess.*]
ignore_missing_imports = True
@@ -96,32 +87,8 @@ ignore_missing_imports = True
[mypy-mozversion.*]
ignore_missing_imports = True
-[mypy-PIL.*]
-ignore_missing_imports = True
-
-[mypy-packaging.*]
-ignore_missing_imports = True
-
-[mypy-psutil.*]
-ignore_missing_imports = True
-
-[mypy-pytest.*]
-ignore_missing_imports = True
-
-[mypy-pywebsocket3.*]
-ignore_missing_imports = True
-
-[mypy-selenium.*]
-ignore_missing_imports = True
-
[mypy-taskcluster.*]
ignore_missing_imports = True
[mypy-ua_parser.*]
ignore_missing_imports = True
-
-[mypy-websockets.*]
-ignore_missing_imports = True
-
-[mypy-zstandard.*]
-ignore_missing_imports = True
diff --git a/tests/wpt/tests/tools/requirements_mypy.txt b/tests/wpt/tests/tools/requirements_mypy.txt
index 5edf2d9614d..a846a21ac4f 100644
--- a/tests/wpt/tests/tools/requirements_mypy.txt
+++ b/tests/wpt/tests/tools/requirements_mypy.txt
@@ -1,14 +1,27 @@
-mypy==1.14.0
-mypy-extensions==1.0.0
-pydantic==2.10.6
-toml==0.10.2
-tomli==2.0.1
+mypy==1.14.1
+
types-atomicwrites==1.4.5.1
-types-python-dateutil==2.9.0.20240906
-types-PyYAML==6.0.12.12
-types-requests==2.32.0.20240905
-types-setuptools==69.5.0.20240423
-types-six==1.16.21.20241105
-types-ujson==5.9.0.0
-types-urllib3==1.26.25.14
+types-html5lib==1.1.11.20241018
+types-setuptools==75.8.0.20250110
+types-ujson==5.10.0.20240515
typing_extensions==4.12.2
+
+# Install dependencies so we get type signatures from them.
+-r ci/requirements_build.txt
+-r ci/requirements_tc.txt
+-r docker/requirements.txt
+-r manifest/requirements.txt
+-r metadata/yaml/requirements.txt
+-r requirements_pytest.txt
+-r wave/requirements.txt
+-r webtransport/requirements.txt
+-r wpt/requirements_android.txt
+-r wpt/requirements_install.txt
+-r wpt/requirements_metadata.txt
+-r wpt/requirements.txt
+-r wptrunner/requirements_chromium.txt
+-r wptrunner/requirements_firefox.txt
+-r wptrunner/requirements_opera.txt
+-r wptrunner/requirements_safari.txt
+-r wptrunner/requirements_sauce.txt
+-r wptrunner/requirements.txt
diff --git a/tests/wpt/tests/tools/requirements_tests.txt b/tests/wpt/tests/tools/requirements_tests.txt
index ca00b8f1f98..663b0050729 100644
--- a/tests/wpt/tests/tools/requirements_tests.txt
+++ b/tests/wpt/tests/tools/requirements_tests.txt
@@ -2,5 +2,6 @@ httpx[http2]==0.27.2
json-e==4.7.0
jsonschema==4.17.3
pyyaml==6.0.1
+types-pyyaml==6.0.12.20241230
taskcluster==83.5.8
mozterm==1.0.0
diff --git a/tests/wpt/tests/tools/serve/serve.py b/tests/wpt/tests/tools/serve/serve.py
index d86e66a3743..8343a54bcd0 100644
--- a/tests/wpt/tests/tools/serve/serve.py
+++ b/tests/wpt/tests/tools/serve/serve.py
@@ -93,9 +93,7 @@ def inject_script(html, script_tag):
return html[:offset] + script_tag + html[offset:]
-class WrapperHandler:
-
- __meta__ = abc.ABCMeta
+class WrapperHandler(metaclass=abc.ABCMeta):
headers: ClassVar[List[Tuple[str, str]]] = []
@@ -207,7 +205,6 @@ class WrapperHandler:
# a specific metadata key: value pair.
pass
- @abc.abstractmethod
def check_exposure(self, request):
# Raise an exception if this handler shouldn't be exposed after all.
pass
diff --git a/tests/wpt/tests/tools/wave/requirements.txt b/tests/wpt/tests/tools/wave/requirements.txt
index 3bb476fd968..5404a6916bd 100644
--- a/tests/wpt/tests/tools/wave/requirements.txt
+++ b/tests/wpt/tests/tools/wave/requirements.txt
@@ -1,2 +1,3 @@
ua-parser==0.18.0
python-dateutil==2.9.0.post0
+types-python-dateutil==2.9.0.20241206
diff --git a/tests/wpt/tests/tools/webdriver/webdriver/bidi/transport.py b/tests/wpt/tests/tools/webdriver/webdriver/bidi/transport.py
index 841b9d0933d..7423155bf3a 100644
--- a/tests/wpt/tests/tools/webdriver/webdriver/bidi/transport.py
+++ b/tests/wpt/tests/tools/webdriver/webdriver/bidi/transport.py
@@ -28,7 +28,7 @@ class Transport:
msg_handler: Callable[[Mapping[str, Any]], Coroutine[Any, Any, None]],
loop: Optional[asyncio.AbstractEventLoop] = None):
self.url = url
- self.connection: Optional[websockets.WebSocketClientProtocol] = None # type: ignore
+ self.connection: Optional[websockets.WebSocketClientProtocol] = None
self.msg_handler = msg_handler
self.send_buf: List[Mapping[str, Any]] = []
@@ -41,7 +41,7 @@ class Transport:
async def start(self) -> None:
# Default max_size of 1048576 bytes is too small for some messages.
# 128MB should be enough.
- self.connection = await websockets.connect(self.url, max_size=128 * 1024 * 1024) # type: ignore
+ self.connection = await websockets.connect(self.url, max_size=128 * 1024 * 1024)
self.read_message_task = self.loop.create_task(self.read_messages())
for msg in self.send_buf:
@@ -55,7 +55,7 @@ class Transport:
@staticmethod
async def _send(
- connection: websockets.WebSocketClientProtocol, # type: ignore
+ connection: websockets.WebSocketClientProtocol,
data: Mapping[str, Any]
) -> None:
msg = json.dumps(data)
diff --git a/tests/wpt/tests/tools/webtransport/h3/capsule.py b/tests/wpt/tests/tools/webtransport/h3/capsule.py
index fc8183a65f0..1708bd2cea3 100644
--- a/tests/wpt/tests/tools/webtransport/h3/capsule.py
+++ b/tests/wpt/tests/tools/webtransport/h3/capsule.py
@@ -1,11 +1,7 @@
-# mypy: no-warn-return-any
-
from enum import IntEnum
from typing import Iterator, Optional
-# TODO(bashi): Remove import check suppressions once aioquic dependency is
-# resolved.
-from aioquic.buffer import UINT_VAR_MAX_SIZE, Buffer, BufferReadError # type: ignore
+from aioquic.buffer import UINT_VAR_MAX_SIZE, Buffer, BufferReadError
class CapsuleType(IntEnum):
diff --git a/tests/wpt/tests/tools/webtransport/h3/webtransport_h3_server.py b/tests/wpt/tests/tools/webtransport/h3/webtransport_h3_server.py
index 2dd8f645551..d2a31a93c9e 100644
--- a/tests/wpt/tests/tools/webtransport/h3/webtransport_h3_server.py
+++ b/tests/wpt/tests/tools/webtransport/h3/webtransport_h3_server.py
@@ -1,5 +1,3 @@
-# mypy: allow-subclassing-any, no-warn-return-any
-
import asyncio
import contextlib
import logging
@@ -9,24 +7,24 @@ import sys
import threading
import traceback
from enum import IntEnum
-from urllib.parse import urlparse
+from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, cast
+from urllib.parse import urlparse
-# TODO(bashi): Remove import check suppressions once aioquic dependency is resolved.
-from aioquic.buffer import Buffer # type: ignore
-from aioquic.asyncio import QuicConnectionProtocol, serve # type: ignore
-from aioquic.asyncio.client import connect # type: ignore
-from aioquic.asyncio.protocol import QuicStreamAdapter # type: ignore
-from aioquic.h3.connection import H3_ALPN, FrameType, H3Connection, ProtocolError, SettingsError # type: ignore
-from aioquic.h3.events import H3Event, HeadersReceived, WebTransportStreamDataReceived, DatagramReceived, DataReceived # type: ignore
-from aioquic.quic.configuration import QuicConfiguration # type: ignore
-from aioquic.quic.connection import logger as quic_connection_logger # type: ignore
+from aioquic.buffer import Buffer
+from aioquic.asyncio import QuicConnectionProtocol, serve
+from aioquic.asyncio.client import connect
+from aioquic.asyncio.protocol import QuicStreamAdapter
+from aioquic.h3.connection import H3_ALPN, FrameType, H3Connection, ProtocolError, SettingsError
+from aioquic.h3.events import H3Event, HeadersReceived, WebTransportStreamDataReceived, DatagramReceived, DataReceived
+from aioquic.quic.configuration import QuicConfiguration
+from aioquic.quic.connection import logger as quic_connection_logger
from aioquic.quic.connection import (
stream_is_client_initiated,
stream_is_unidirectional,
)
-from aioquic.quic.events import QuicEvent, ProtocolNegotiated, ConnectionTerminated, StreamReset # type: ignore
-from aioquic.tls import SessionTicket # type: ignore
+from aioquic.quic.events import QuicEvent, ProtocolNegotiated, ConnectionTerminated, StreamReset
+from aioquic.tls import SessionTicket
from tools import localpaths # noqa: F401
from wptserve import stash
@@ -315,7 +313,8 @@ class WebTransportSession:
self.request_headers = request_headers
self._protocol: WebTransportH3Protocol = protocol
- self._http: H3Connection = protocol._http
+ assert protocol._http is not None
+ self._http: H3ConnectionWithDatagram = protocol._http
# Use the a shared default path for all handlers so that different
# WebTransport sessions can access the same store easily.
@@ -413,7 +412,7 @@ class WebTransportSession:
"""
if not self._protocol._allow_datagrams:
_logger.warn(
- "Sending a datagram while that's now allowed - discarding it")
+ "Sending a datagram while that's not allowed - discarding it")
return
stream_id = self.session_id
if self._http.datagram_setting is not None:
@@ -541,17 +540,25 @@ class WebTransportH3Server:
except Exception as e:
_logger.warn(str(e))
- configuration = QuicConfiguration(
- alpn_protocols=H3_ALPN,
- is_client=False,
- max_datagram_frame_size=65536,
- secrets_log_file=secrets_log_file,
- )
+ # Workaround https://github.com/aiortc/aioquic/issues/567 with if/else
+ if secrets_log_file is not None:
+ configuration = QuicConfiguration(
+ alpn_protocols=H3_ALPN,
+ is_client=False,
+ max_datagram_frame_size=65536,
+ secrets_log_file=secrets_log_file,
+ )
+ else:
+ configuration = QuicConfiguration(
+ alpn_protocols=H3_ALPN,
+ is_client=False,
+ max_datagram_frame_size=65536,
+ )
_logger.info("Starting WebTransport over HTTP/3 server on %s:%s",
self.host, self.port)
- configuration.load_cert_chain(self.cert_path, self.key_path)
+ configuration.load_cert_chain(Path(self.cert_path), Path(self.key_path))
ticket_store = SessionTicketStore()
diff --git a/tests/wpt/tests/tools/wpt/browser.py b/tests/wpt/tests/tools/wpt/browser.py
index 0ac1b982ed0..d38017c324f 100644
--- a/tests/wpt/tests/tools/wpt/browser.py
+++ b/tests/wpt/tests/tools/wpt/browser.py
@@ -1,4 +1,6 @@
# mypy: allow-untyped-defs
+import configparser
+import json
import os
import platform
import re
@@ -9,7 +11,7 @@ import tempfile
from abc import ABCMeta, abstractmethod
from datetime import datetime, timedelta, timezone
from shutil import which
-from typing import Optional
+from typing import Any, Dict, Optional, Tuple
from urllib.parse import urlsplit, quote
import html5lib
@@ -81,6 +83,11 @@ def get_taskcluster_artifact(index, path):
return resp
+def get_file_github(repo: str, ref: str, path: str) -> bytes:
+ data: bytes = get(f"https://raw.githubusercontent.com/{repo}/{ref}/{path}").content # type: ignore
+ return data
+
+
class Browser:
__metaclass__ = ABCMeta
@@ -359,43 +366,134 @@ class Firefox(Browser):
def find_webdriver(self, venv_path=None, channel=None):
return which("geckodriver")
- def get_version_and_channel(self, binary):
- version_string = call(binary, "--version").strip()
- m = re.match(r"Mozilla Firefox (\d+\.\d+(?:\.\d+)?)(a|b)?", version_string)
+ def extract_version_number(self, version_string: str) -> Tuple[Optional[str], str]:
+ version_parser = re.compile(r"^(\d+)\.(\d+)(?:\.(\d+))?((a|b)\d+)?")
+ m = version_parser.match(version_string)
if not m:
return None, "nightly"
- version, status = m.groups()
- channel = {"a": "nightly", "b": "beta"}
- return version, channel.get(status, "stable")
+ major, minor, patch, pre, channel_id = m.groups()
+ version = f"{major}.{minor}"
+ if patch is not None:
+ version += f".{patch}"
+ if pre is not None:
+ version += pre
+ channel = {"a": "nightly", "b": "beta"}.get(channel_id, "stable")
+ return version, channel
+
+ def get_version_and_channel(self, binary: str) -> Tuple[Optional[str], str, Optional[str]]:
+ application_ini_path = os.path.join(os.path.dirname(binary), "application.ini")
+ if os.path.exists(application_ini_path):
+ try:
+ return self.get_version_and_channel_application_ini(application_ini_path)
+ except ValueError as e:
+ self.logger.info(f"Reading application ini file failed: {e}")
+ # Fall back to calling the binary
+ version_string: str = call(binary, "--version").strip() # type: ignore
+ version_re = re.compile(r"Mozilla Firefox (.*)")
+ m = version_re.match(version_string)
+ if not m:
+ return None, "nightly", None
+ version, channel = self.extract_version_number(m.group(1))
+ return version, channel, None
+
+ def get_version_and_channel_application_ini(self, path: str) -> Tuple[Optional[str], str, Optional[str]]:
+ """Try to read application version from an ini file
+
+ This doesn't work in all cases e.g. local builds don't have
+ all the information, or builds where the binary path is a shell
+ script or similar."""
+ config = configparser.ConfigParser()
+ paths = config.read(path)
+ if path not in paths:
+ raise ValueError("Failed to read config file")
+
+ version = config.get("App", "Version", fallback=None)
+ if version is None:
+ raise ValueError("Failed to find Version key")
+ version, channel = self.extract_version_number(version)
- def get_profile_bundle_url(self, version, channel):
- if channel == "stable":
- repo = "https://hg.mozilla.org/releases/mozilla-release"
- tag = "FIREFOX_%s_RELEASE" % version.replace(".", "_")
- elif channel == "beta":
- repo = "https://hg.mozilla.org/releases/mozilla-beta"
- major_version = version.split(".", 1)[0]
- # For beta we have a different format for betas that are now in stable releases
- # vs those that are not
- tags = get("https://hg.mozilla.org/releases/mozilla-beta/json-tags").json()["tags"]
- tags = {item["tag"] for item in tags}
- end_tag = "FIREFOX_BETA_%s_END" % major_version
- if end_tag in tags:
- tag = end_tag
- else:
- tag = "tip"
- else:
- repo = "https://hg.mozilla.org/mozilla-central"
- # Always use tip as the tag for nightly; this isn't quite right
- # but to do better we need the actual build revision, which we
- # can get if we have an application.ini file
- tag = "tip"
+ rev = None
+ if channel == "nightly":
+ source_repo = config.get("App", "SourceRepository", fallback=None)
+ commit = config.get("App", "SourceStamp", fallback=None)
+ if source_repo is not None and commit is not None:
+ if source_repo.startswith("https://hg.mozilla.org"):
+ try:
+ commit_data: Dict[str, Any] = get(
+ f"https://hg-edge.mozilla.org/integration/autoland/json-rev/{commit}"
+ ).json() # type: ignore
+ rev = commit_data.get("git_commit")
+ except Exception:
+ pass
+ else:
+ rev = commit
+
+ return version, channel, rev
- return "%s/archive/%s.zip/testing/profiles/" % (repo, tag)
+ def get_git_ref(self, version: str, channel: str, rev: Optional[str]) -> str:
+ if rev is not None:
+ return rev
+
+ if channel == "stable":
+ return "FIREFOX_%s_RELEASE" % version.replace(".", "_")
+
+ if channel == "beta":
+ ref_prefix = "FIREFOX_%s" % version.replace(".", "_")
+ tags = []
+ build_re = re.compile(fr"{ref_prefix}_BUILD(\d)+")
+ for tag_data in get(
+ f"https://api.github.com/repos/mozilla-firefox/firefox/git/matching-refs/tags/{ref_prefix}"
+ ).json(): # type: ignore
+ tag = tag_data["ref"].rsplit("/", 1)[1]
+ if tag.endswith("_RELEASE"):
+ tags = [(0, tag)]
+ break
+ m = build_re.match(tag)
+ if m:
+ tags.append((int(m.group(1)), tag))
+ tags.sort()
+ if not tags:
+ raise ValueError(f"No tag found for {version} beta")
+ return f"{tags[-1][1]}"
+
+ return "main"
+
+ def get_profile_github(self, version: str, channel: str, dest: str, rev: Optional[str]) -> None:
+ """Read the testing/profiles data from firefox source on GitHub"""
+
+ # There are several possible approaches here, none of which are great:
+ # 1. Shallow, sparse, clone of the repo with no history and just the testing/profiles
+ # directory. This is too slow to be usable.
+ # 2. Use the Github repository contents API to read all the files under that directory.
+ # This requires auth to not run into rate limits.
+ # 3. Gitub tree API has basically the same problems
+ # 4. Download a full archive of the relevant commit from Github and extract only the
+ # required directory. This is also too slow to be useful.
+ #
+ # In the end we use githubusercontent.com, which has the problem that it doesn't allow
+ # directory listings. So we have to hardcode in all the files we need. In particular
+ # for each profile we are currently just downloading the user.js file and ignoring the
+ # extensions/ directory, which is currently unused.
+ ref = self.get_git_ref(version, channel, rev)
+ file_data = {}
+ profiles_bytes = get_file_github("mozilla-firefox/firefox", ref, "testing/profiles/profiles.json")
+ profiles = json.loads(profiles_bytes)
+ file_data["profiles.json"] = profiles_bytes
+ for subdir in profiles["web-platform-tests"]:
+ rel_path = os.path.join(subdir, "user.js")
+ file_data[rel_path] = get_file_github("mozilla-firefox/firefox",
+ ref,
+ f"testing/profiles/{subdir}/user.js")
+
+ for path, data in file_data.items():
+ dest_path = os.path.join(dest, path)
+ os.makedirs(os.path.dirname(dest_path), exist_ok=True)
+ with open(dest_path, "wb") as f:
+ f.write(data)
def install_prefs(self, binary, dest=None, channel=None):
if binary and not binary.endswith(".apk"):
- version, channel_ = self.get_version_and_channel(binary)
+ version, channel_, rev = self.get_version_and_channel(binary)
if channel is not None and channel != channel_:
# Beta doesn't always seem to have the b in the version string, so allow the
# manually supplied value to override the one from the binary
@@ -403,12 +501,13 @@ class Firefox(Browser):
elif channel is None:
channel = channel_
else:
+ rev = None
version = None
if dest is None:
dest = os.curdir
- dest = os.path.join(dest, "profiles", channel)
+ dest = os.path.join(dest, "profiles", rev if rev is not None else channel)
if version:
dest = os.path.join(dest, version)
have_cache = False
@@ -426,19 +525,7 @@ class Firefox(Browser):
rmtree(dest)
os.makedirs(dest)
- url = self.get_profile_bundle_url(version, channel)
-
- self.logger.info(f"Downloading test prefs from {url}")
- try:
- extract_dir = tempfile.mkdtemp()
- unzip(get(url).raw, dest=extract_dir)
-
- profiles = os.path.join(extract_dir, os.listdir(extract_dir)[0], 'testing', 'profiles')
- for name in os.listdir(profiles):
- path = os.path.join(profiles, name)
- shutil.move(path, dest)
- finally:
- rmtree(extract_dir)
+ self.get_profile_github(version, channel, dest, rev)
self.logger.info(f"Test prefs downloaded to {dest}")
else:
self.logger.info(f"Using cached test prefs from {dest}")
diff --git a/tests/wpt/tests/tools/wpt/requirements.txt b/tests/wpt/tests/tools/wpt/requirements.txt
index d80d9fc2a3a..ea6498ce15f 100644
--- a/tests/wpt/tests/tools/wpt/requirements.txt
+++ b/tests/wpt/tests/tools/wpt/requirements.txt
@@ -1 +1,2 @@
requests==2.32.3
+types-requests==2.32.0.20241016
diff --git a/tests/wpt/tests/tools/wpt/requirements_metadata.txt b/tests/wpt/tests/tools/wpt/requirements_metadata.txt
new file mode 100644
index 00000000000..3052e99b4fc
--- /dev/null
+++ b/tests/wpt/tests/tools/wpt/requirements_metadata.txt
@@ -0,0 +1 @@
+pydantic==2.10.6
diff --git a/tests/wpt/tests/tools/wptrunner/requirements.txt b/tests/wpt/tests/tools/wptrunner/requirements.txt
index 97b56937955..6605de2deda 100644
--- a/tests/wpt/tests/tools/wptrunner/requirements.txt
+++ b/tests/wpt/tests/tools/wptrunner/requirements.txt
@@ -7,5 +7,7 @@ packaging==25.0
pillow==10.4.0; python_version < '3.9'
pillow==11.1.0; python_version >= '3.9'
requests==2.32.3
+types-requests==2.32.0.20241016
six==1.16.0
+types-six==1.17.0.20241205
urllib3==2.2.2
diff --git a/tests/wpt/tests/tools/wptrunner/requirements_firefox.txt b/tests/wpt/tests/tools/wptrunner/requirements_firefox.txt
index 59a9cd7ba3e..2b98c0a65d4 100644
--- a/tests/wpt/tests/tools/wptrunner/requirements_firefox.txt
+++ b/tests/wpt/tests/tools/wptrunner/requirements_firefox.txt
@@ -7,4 +7,5 @@ mozprofile==3.0.0
mozrunner==8.3.2
mozversion==2.4.0
psutil==5.9.8
+types-psutil==6.1.0.20241221
redo==3.0.0
diff --git a/tests/wpt/tests/tools/wptrunner/requirements_safari.txt b/tests/wpt/tests/tools/wptrunner/requirements_safari.txt
index 0704b2dbf68..177446e1038 100644
--- a/tests/wpt/tests/tools/wptrunner/requirements_safari.txt
+++ b/tests/wpt/tests/tools/wptrunner/requirements_safari.txt
@@ -1 +1,2 @@
psutil==5.9.8
+types-psutil==6.1.0.20241221
diff --git a/tests/wpt/tests/tools/wptrunner/requirements_sauce.txt b/tests/wpt/tests/tools/wptrunner/requirements_sauce.txt
index f6f1581d858..c7bdc25bf5e 100644
--- a/tests/wpt/tests/tools/wptrunner/requirements_sauce.txt
+++ b/tests/wpt/tests/tools/wptrunner/requirements_sauce.txt
@@ -1,2 +1,3 @@
selenium==4.20.0
requests==2.32.3
+types-requests==2.32.0.20241016
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/asyncactions.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/asyncactions.py
index 8397d7838a3..9f7f313f203 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/asyncactions.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/asyncactions.py
@@ -1,5 +1,4 @@
# mypy: allow-untyped-defs
-from webdriver.bidi.undefined import UNDEFINED
webdriver = None
@@ -102,7 +101,7 @@ class BidiEmulationSetGeolocationOverrideAction:
# If `error` is present, do not pass `coordinates` (coordinates: UNDEFINED).
# Otherwise, remove emulation (coordinates: None).
coordinates = payload['coordinates'] if 'coordinates' in payload else (
- None if error is None else UNDEFINED)
+ None if error is None else webdriver.bidi.undefined.UNDEFINED)
if "contexts" not in payload:
raise ValueError("Missing required parameter: contexts")
diff --git a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
index 16eb3cbb4a5..6b9a0de9bb2 100644
--- a/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
+++ b/tests/wpt/tests/tools/wptrunner/wptrunner/executors/protocol.py
@@ -6,9 +6,10 @@ from http.client import HTTPConnection
from abc import ABCMeta, abstractmethod
from typing import Any, Awaitable, Callable, ClassVar, List, Mapping, Optional, \
- Tuple, Type, Union
+ Tuple, Type, TYPE_CHECKING, Union
-from webdriver.bidi.undefined import Undefined
+if TYPE_CHECKING:
+ from webdriver.bidi.undefined import Undefined
def merge_dicts(target, source):
@@ -455,7 +456,7 @@ class BidiEmulationProtocolPart(ProtocolPart):
@abstractmethod
async def set_geolocation_override(self,
- coordinates: Optional[Union[Mapping[str, Any], Undefined]],
+ coordinates: Optional[Union[Mapping[str, Any], "Undefined"]],
error: Optional[Mapping[str, Any]],
contexts: List[str]) -> None:
pass
diff --git a/tests/wpt/tests/tools/wptserve/setup.py b/tests/wpt/tests/tools/wptserve/setup.py
index d66769f0630..670c3dfcea6 100644
--- a/tests/wpt/tests/tools/wptserve/setup.py
+++ b/tests/wpt/tests/tools/wptserve/setup.py
@@ -1,6 +1,6 @@
from setuptools import setup
-PACKAGE_VERSION = '4.0.2'
+PACKAGE_VERSION = '4.0.3'
deps = [
"h2>=4.1.0",
"pywebsocket3>=4.0.2",
diff --git a/tests/wpt/tests/tools/wptserve/tests/functional/test_pipes.py b/tests/wpt/tests/tools/wptserve/tests/functional/test_pipes.py
index c11577acb50..e868b612101 100644
--- a/tests/wpt/tests/tools/wptserve/tests/functional/test_pipes.py
+++ b/tests/wpt/tests/tools/wptserve/tests/functional/test_pipes.py
@@ -146,14 +146,16 @@ server: http://localhost:{0}""".format(self.server.port).encode("ascii")
class TestTrickle(TestUsingServer):
def test_trickle(self):
- #Actually testing that the response trickles in is not that easy
- t0 = time.time()
- resp = self.request("/document.txt", query="pipe=trickle(1:d2:5:d1:r2)")
- t1 = time.time()
- with open(os.path.join(doc_root, "document.txt"), 'rb') as f:
+ # Actually testing that the response trickles in is not that easy
+ clock_info = time.get_clock_info("monotonic")
+ t0 = time.monotonic()
+ with self.request("/document.txt", query="pipe=trickle(1:d2:5:d1:r2)") as resp:
+ actual = resp.read()
+ t1 = time.monotonic()
+ with open(os.path.join(doc_root, "document.txt"), "rb") as f:
expected = f.read()
- self.assertEqual(resp.read(), expected)
- self.assertGreater(6, t1-t0)
+ self.assertEqual(actual, expected)
+ self.assertGreater(t1 - t0, 6 - clock_info.resolution)
def test_headers(self):
resp = self.request("/document.txt", query="pipe=trickle(d0.01)")
diff --git a/tests/wpt/tests/tools/wptserve/wptserve/ws_h2_handshake.py b/tests/wpt/tests/tools/wptserve/wptserve/ws_h2_handshake.py
index ab1ab958a03..99d4dbeac4b 100644
--- a/tests/wpt/tests/tools/wptserve/wptserve/ws_h2_handshake.py
+++ b/tests/wpt/tests/tools/wptserve/wptserve/ws_h2_handshake.py
@@ -20,7 +20,7 @@ def check_connect_method(request):
raise HandshakeException('Method is not CONNECT: %r' % request.method)
-class WsH2Handshaker(HandshakerBase): # type: ignore
+class WsH2Handshaker(HandshakerBase):
def __init__(self, request, dispatcher):
"""Bootstrapping handshake processor for the WebSocket protocol with HTTP/2 (RFC 8441).
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/resources/audio-worklet-source-phase.js b/tests/wpt/tests/wasm/webapi/esm-integration/resources/audio-worklet-source-phase.js
new file mode 100644
index 00000000000..3a07777b1e5
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/resources/audio-worklet-source-phase.js
@@ -0,0 +1,43 @@
+import source modSource from './worker.wasm';
+
+class AudioProcessor extends AudioWorkletProcessor {
+ constructor(...args) {
+ super(...args);
+ let port = this.port;
+
+ port.onmessage = (e) => {
+ let staticCheck = false;
+ let dynamicCheck = false;
+ const pm =
+ (x) => {
+ const message = {
+ value: x,
+ staticCheck: staticCheck,
+ dynamicCheck: dynamicCheck
+ };
+ port.postMessage(message);
+ }
+
+ staticCheck = modSource instanceof WebAssembly.Module;
+ // `import.source` should fail because dynamic imports aren't supported
+ // in worklets.
+ let import_promise = import.source('./execute-start.wasm');
+ import_promise
+ .catch((e) => {
+ dynamicCheck = e instanceof TypeError;
+ })
+ .then(() => {
+ // worker.wasm will call pm with the result, so instantiate this
+ // after the dynamic check.
+ WebAssembly.instantiate(
+ modSource, {'./worker-helper.js': {'pm': pm}});
+ });
+ };
+ }
+
+ process(inputs, outputs, parameters) {
+ return true;
+ }
+}
+
+registerProcessor('audio-processor', AudioProcessor);
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-dynamic-source-phase-import.sub.js b/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-dynamic-source-phase-import.sub.js
new file mode 100644
index 00000000000..c9d75f15ff2
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-dynamic-source-phase-import.sub.js
@@ -0,0 +1,2 @@
+await import.source(
+ 'https://{{hosts[alt][]}}:{{ports[https][0]}}/resources/execute-start.wasm');
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-static-source-phase-import.sub.js b/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-static-source-phase-import.sub.js
new file mode 100644
index 00000000000..2bf64c00093
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/resources/cross-origin-wasm-static-source-phase-import.sub.js
@@ -0,0 +1 @@
+import source exportedNamesSource from 'https://{{hosts[alt][]}}:{{ports[https][0]}}/resources/exported-names.wasm';
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-helper.js b/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-helper.js
index 277bb4c1ea5..537781bef78 100644
--- a/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-helper.js
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-helper.js
@@ -1 +1,4 @@
-export function pm(x) { postMessage(x); }
+export function pm(x) {
+ const message = {value: x, checks: pm.checks};
+ postMessage(message);
+}
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-source-phase.js b/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-source-phase.js
index e1c2703899a..3be7479ddec 100644
--- a/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-source-phase.js
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/resources/worker-source-phase.js
@@ -1,7 +1,10 @@
import source modSource from "./worker.wasm";
import { pm } from "./worker-helper.js";
-assert_true(modSource instanceof WebAssembly.Module);
-assert_true(await import.source("./worker.wasm") === modSource);
+
+pm.checks = [
+ modSource instanceof WebAssembly.Module,
+ (await import.source('./worker.wasm') === modSource)
+];
await WebAssembly.instantiate(modSource, {
"./worker-helper.js": {
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html b/tests/wpt/tests/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html
new file mode 100644
index 00000000000..b96fc756e5c
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/script-src-allows-source-phase-wasm.tentative.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>Source phase imports alowed by CSP</title>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type=module>
+setup({ single_test: true });
+
+import source exportedNamesSource from "./resources/exported-names.wasm";
+
+assert_true(exportedNamesSource instanceof WebAssembly.Module);
+const AbstractModuleSource = Object.getPrototypeOf(WebAssembly.Module);
+assert_equals(AbstractModuleSource.name, "AbstractModuleSource");
+assert_true(exportedNamesSource instanceof AbstractModuleSource);
+
+assert_array_equals(WebAssembly.Module.exports(exportedNamesSource).map(({ name }) => name).sort(),
+ ["func", "glob", "mem", "tab"]);
+
+const wasmImportFromWasmSource = await import.source("./resources/wasm-import-from-wasm.wasm");
+
+assert_true(wasmImportFromWasmSource instanceof WebAssembly.Module);
+
+let logged = false;
+const instance = await WebAssembly.instantiate(wasmImportFromWasmSource, {
+ "./wasm-export-to-wasm.wasm": {
+ log () {
+ logged = true;
+ }
+ }
+});
+instance.exports.logExec();
+assert_true(logged);
+
+done();
+</script>
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html b/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html
new file mode 100644
index 00000000000..86c8d96835e
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-blocked-by-csp.tentative.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>Source phase imports blocked by CSP</title>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ const test_load = async_test(
+ "Importing a WebAssembly module should be guarded by script-src CSP.");
+
+ window.violationCount = 0;
+ document.addEventListener("securitypolicyviolation", (e) => {
+ test_load.step(() => {
+ assert_equals("script-src-elem", e.violatedDirective);
+ });
+ if (++violationCount == 2) {
+ test_load.done();
+ }
+ });
+</script>
+<script type=module src="./resources/cross-origin-wasm-static-source-phase-import.sub.js"></script>
+<script type=module src="./resources/cross-origin-wasm-dynamic-source-phase-import.sub.js"></script>
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-preload.tentative.html b/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-preload.tentative.html
new file mode 100644
index 00000000000..90bfb484741
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/source-phase-preload.tentative.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<title>Preload source phase modules</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+function verifyNumberOfDownloads(url, number, allowTransferSizeOfZero = false) {
+ var numDownloads = 0;
+ let absoluteURL = new URL(url, location.href).href;
+ performance.getEntriesByName(absoluteURL).forEach(entry => {
+ if (entry.transferSize > 0 || allowTransferSizeOfZero) {
+ numDownloads++;
+ }
+ });
+ assert_equals(numDownloads, number, url);
+}
+
+function attachAndWaitForLoad(element) {
+ return new Promise((resolve, reject) => {
+ element.onload = resolve;
+ element.onerror = reject;
+ document.body.appendChild(element);
+ });
+}
+
+promise_test(function(t) {
+ var link = document.createElement('link');
+ link.rel = 'modulepreload';
+ link.href = 'resources/exported-names.wasm';
+ return attachAndWaitForLoad(link).then(() => {
+ verifyNumberOfDownloads('resources/exported-names.wasm', 1);
+ let promise = new Promise((resolve) => {window.resolveStatic = resolve});
+ // Verify that <script> doesn't fetch the module again.
+ var script = document.createElement('script');
+ script.type = 'module';
+ script.text = "import source exportedNamesSource from './resources/exported-names.wasm'; window.resolveStatic()";
+ document.body.appendChild(script);
+ return promise;
+ }).then(() => {
+ verifyNumberOfDownloads('resources/exported-names.wasm', 1);
+ })
+}, 'Static source phase import.');
+
+promise_test(function(t) {
+ var link = document.createElement('link');
+ link.rel = 'modulepreload';
+ link.href = 'resources/execute-start.wasm';
+ return attachAndWaitForLoad(link).then(() => {
+ verifyNumberOfDownloads('resources/execute-start.wasm', 1);
+ let promise = new Promise((resolve) => {window.resolveDynamic = resolve});
+ // Verify that <script> doesn't fetch the module again.
+ var script = document.createElement('script');
+ script.type = 'module';
+ script.text = "await import.source('./resources/execute-start.wasm'); window.resolveDynamic();";
+ document.body.appendChild(script);
+ return promise;
+ }).then(() => {
+ verifyNumberOfDownloads('resources/execute-start.wasm', 1);
+ })
+}, 'Dynamic source phase import.');
+
+</script>
+</body>
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html b/tests/wpt/tests/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html
index e193f3efc69..56aea9f9655 100644
--- a/tests/wpt/tests/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html
@@ -7,7 +7,9 @@
setup({ single_test: true });
const worker = new Worker("resources/worker-source-phase.js", { type: "module" });
worker.onmessage = (msg) => {
- assert_equals(msg.data, 42);
+ assert_equals(msg.data.value, 42);
+ assert_equals(msg.data.checks.length, 2);
+ msg.data.checks.forEach(assert_true);
done();
}
</script>
diff --git a/tests/wpt/tests/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html b/tests/wpt/tests/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html
new file mode 100644
index 00000000000..9a9714a2a3e
--- /dev/null
+++ b/tests/wpt/tests/wasm/webapi/esm-integration/worklet-import-source-phase.tentative.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Import a source phase module to a worklet</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script type=module>
+setup({ single_test: true });
+
+const audioContext = new AudioContext();
+await audioContext.audioWorklet.addModule("./resources/audio-worklet-source-phase.js");
+const audioNode = new AudioWorkletNode(audioContext, "audio-processor");
+
+audioNode.port.postMessage("");
+audioNode.port.onmessage = (msg) => {
+ assert_equals(msg.data.value, 42);
+ assert_true(msg.data.staticCheck);
+ assert_true(msg.data.dynamicCheck);
+ done();
+}
+
+audioNode.connect(audioContext.destination);
+</script>
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/__init__.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/__init__.py
index 8987e12a967..618d2c1a23c 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/__init__.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/__init__.py
@@ -54,8 +54,7 @@ def assert_browsing_context(
assert info["url"] == url
assert info["userContext"] == user_context
assert info["originalOpener"] == original_opener
- if client_window is not None:
- assert info["clientWindow"] == client_window
+ assert info["clientWindow"] == client_window
async def assert_document_status(bidi_session, context, visible, focused):
@@ -107,3 +106,14 @@ async def get_visibility_state(bidi_session, context: Mapping[str, Any]) -> str:
target=ContextTarget(context["context"]),
await_promise=False)
return result["value"]
+
+
+def find_context_info(contexts, context):
+ return next(
+ (
+ context_info
+ for context_info in contexts
+ if context_info["context"] == context
+ ),
+ None,
+ )
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/context_created.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/context_created.py
index 2982f78d991..3c26dbed7dc 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/context_created.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/context_created.py
@@ -3,7 +3,7 @@ from webdriver.error import TimeoutException
from webdriver.bidi.modules.script import ContextTarget
from tests.support.sync import AsyncPoll
-from .. import assert_browsing_context
+from .. import assert_browsing_context, find_context_info
pytestmark = pytest.mark.asyncio
@@ -38,6 +38,7 @@ async def test_new_context(bidi_session, wait_for_event, wait_for_future_safe, s
on_entry = wait_for_event(CONTEXT_CREATED_EVENT)
top_level_context = await bidi_session.browsing_context.create(type_hint=type_hint)
context_info = await wait_for_future_safe(on_entry)
+ contexts = await bidi_session.browsing_context.get_tree(root=top_level_context["context"])
assert_browsing_context(
context_info,
@@ -45,7 +46,8 @@ async def test_new_context(bidi_session, wait_for_event, wait_for_future_safe, s
children=None,
url="about:blank",
parent=None,
- user_context="default"
+ user_context="default",
+ client_window=contexts[0]["clientWindow"],
)
@@ -60,6 +62,11 @@ async def test_evaluate_window_open_without_url(bidi_session, subscribe_events,
await_promise=False)
context_info = await wait_for_future_safe(on_entry)
+ contexts = await bidi_session.browsing_context.get_tree()
+
+ assert len(contexts) == 2
+
+ found_context = find_context_info(contexts, context_info["context"])
assert_browsing_context(
context_info,
@@ -68,6 +75,7 @@ async def test_evaluate_window_open_without_url(bidi_session, subscribe_events,
url="about:blank",
parent=None,
original_opener=top_context["context"],
+ client_window=found_context["clientWindow"],
)
@@ -83,6 +91,11 @@ async def test_evaluate_window_open_with_url(bidi_session, subscribe_events, wai
target=ContextTarget(top_context["context"]),
await_promise=False)
context_info = await wait_for_future_safe(on_entry)
+ contexts = await bidi_session.browsing_context.get_tree()
+
+ assert len(contexts) == 2
+
+ found_context = find_context_info(contexts, context_info["context"])
assert_browsing_context(
context_info,
@@ -91,6 +104,7 @@ async def test_evaluate_window_open_with_url(bidi_session, subscribe_events, wai
url="about:blank",
parent=None,
original_opener=top_context["context"],
+ client_window=found_context["clientWindow"],
)
@@ -110,6 +124,7 @@ async def test_event_emitted_before_create_returns(
remove_listener = bidi_session.add_event_listener(CONTEXT_CREATED_EVENT, on_event)
context = await bidi_session.browsing_context.create(type_hint=type_hint)
+ contexts = await bidi_session.browsing_context.get_tree(root=context["context"])
# If the browsingContext.contextCreated event was emitted after the
# browsingContext.create command resolved, the array would most likely be
@@ -123,6 +138,7 @@ async def test_event_emitted_before_create_returns(
url="about:blank",
parent=None,
user_context="default",
+ client_window=contexts[0]["clientWindow"],
)
remove_listener()
@@ -166,6 +182,7 @@ async def test_navigate_creates_iframes(bidi_session, subscribe_events, top_cont
children=None,
url="about:blank",
parent=root_info["context"],
+ client_window=contexts[0]["clientWindow"],
)
assert_browsing_context(
@@ -174,6 +191,7 @@ async def test_navigate_creates_iframes(bidi_session, subscribe_events, top_cont
children=None,
url="about:blank",
parent=root_info["context"],
+ client_window=contexts[0]["children"][0]["clientWindow"],
)
remove_listener()
@@ -219,6 +237,7 @@ async def test_navigate_creates_nested_iframes(bidi_session, subscribe_events, t
children=None,
url="about:blank",
parent=root_info["context"],
+ client_window=contexts[0]["clientWindow"],
)
assert_browsing_context(
@@ -227,6 +246,7 @@ async def test_navigate_creates_nested_iframes(bidi_session, subscribe_events, t
children=None,
url="about:blank",
parent=child1_info["context"],
+ client_window=contexts[0]["children"][0]["clientWindow"],
)
remove_listener()
@@ -293,6 +313,7 @@ async def test_new_user_context(
context = await bidi_session.browsing_context.create(
type_hint=type_hint, user_context=user_context
)
+ contexts = await bidi_session.browsing_context.get_tree(root=context["context"])
context_info = await wait_for_future_safe(on_entry)
assert len(events) == 1
@@ -304,6 +325,7 @@ async def test_new_user_context(
url="about:blank",
parent=None,
user_context=user_context,
+ client_window=contexts[0]["clientWindow"],
)
remove_listener()
@@ -317,6 +339,7 @@ async def test_existing_context(bidi_session, wait_for_event, wait_for_future_sa
on_entry = wait_for_event(CONTEXT_CREATED_EVENT)
await subscribe_events([CONTEXT_CREATED_EVENT], contexts=[top_level_context["context"]])
context_info = await wait_for_future_safe(on_entry)
+ contexts = await bidi_session.browsing_context.get_tree(root=top_level_context["context"])
assert_browsing_context(
context_info,
@@ -324,7 +347,8 @@ async def test_existing_context(bidi_session, wait_for_event, wait_for_future_sa
children=None,
url="about:blank",
parent=None,
- user_context="default"
+ user_context="default",
+ client_window=contexts[0]["clientWindow"],
)
@@ -337,6 +361,7 @@ async def test_existing_context_via_user_context(bidi_session, create_user_conte
on_entry = wait_for_event(CONTEXT_CREATED_EVENT)
await subscribe_events([CONTEXT_CREATED_EVENT], user_contexts=[user_context])
context_info = await wait_for_future_safe(on_entry)
+ contexts = await bidi_session.browsing_context.get_tree(root=top_level_context["context"])
assert_browsing_context(
context_info,
@@ -344,7 +369,8 @@ async def test_existing_context_via_user_context(bidi_session, create_user_conte
children=None,
url="about:blank",
parent=None,
- user_context=user_context
+ user_context=user_context,
+ client_window=contexts[0]["clientWindow"],
)
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/original_opener.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/original_opener.py
index 18c9483e7ce..9ac59a3a325 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/original_opener.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_created/original_opener.py
@@ -1,7 +1,7 @@
import pytest
from webdriver.bidi.modules.script import ContextTarget
-from .. import assert_browsing_context
+from .. import assert_browsing_context, find_context_info
pytestmark = pytest.mark.asyncio
@@ -15,6 +15,7 @@ async def test_original_opener_context_create(bidi_session, wait_for_event, wait
on_created = wait_for_event(CONTEXT_CREATED_EVENT)
top_level_context = await bidi_session.browsing_context.create(type_hint=type_hint)
+ contexts = await bidi_session.browsing_context.get_tree(root=top_level_context["context"])
context_info = await wait_for_future_safe(on_created)
@@ -23,6 +24,7 @@ async def test_original_opener_context_create(bidi_session, wait_for_event, wait
context=top_level_context["context"],
original_opener=None,
url="about:blank",
+ client_window=contexts[0]["clientWindow"]
)
@@ -57,9 +59,16 @@ async def test_original_opener_window_open(bidi_session, wait_for_event, wait_fo
if returns_window:
context = result["value"]["context"]
+ contexts = await bidi_session.browsing_context.get_tree()
+
+ assert len(contexts) == 3
+
+ found_context = find_context_info(contexts, context_info["context"])
+
assert_browsing_context(
context_info,
context=context,
original_opener=top_level_context["context"],
url="about:blank",
+ client_window=found_context["clientWindow"]
)
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed.py
index 2fd0cd6bb47..0576221de4c 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/context_destroyed/context_destroyed.py
@@ -37,6 +37,7 @@ async def test_new_context(bidi_session, wait_for_event, wait_for_future_safe, s
on_entry = wait_for_event(CONTEXT_DESTROYED_EVENT)
new_context = await bidi_session.browsing_context.create(type_hint=type_hint)
+ contexts = await bidi_session.browsing_context.get_tree(root=new_context["context"])
await bidi_session.browsing_context.close(context=new_context["context"])
@@ -48,7 +49,8 @@ async def test_new_context(bidi_session, wait_for_event, wait_for_future_safe, s
children=0,
url="about:blank",
parent=None,
- user_context="default"
+ user_context="default",
+ client_window=contexts[0]["clientWindow"],
)
@@ -108,6 +110,7 @@ async def test_navigate_iframe(
children=0,
url=frame_url,
parent=new_tab["context"],
+ client_window=contexts[0]["clientWindow"],
)
@@ -140,6 +143,7 @@ async def test_delete_iframe(
children=0,
url=iframe["url"],
parent=new_tab["context"],
+ client_window=contexts[0]["clientWindow"]
)
@@ -180,6 +184,7 @@ async def test_nested_iframes_delete_top_iframe(
children=1,
url=test_page_same_origin_frame,
parent=new_tab["context"],
+ client_window=contexts[0]["clientWindow"]
)
remove_listener()
@@ -224,6 +229,7 @@ async def test_nested_iframes_delete_deepest_iframe(
children=0,
url=deepest_iframe["url"],
parent=top_iframe["context"],
+ client_window=contexts[0]["clientWindow"],
)
remove_listener()
@@ -244,6 +250,7 @@ async def test_iframe_destroy_parent(
await bidi_session.browsing_context.navigate(
url=test_page_nested_frames, context=new_tab["context"], wait="complete"
)
+ contexts = await bidi_session.browsing_context.get_tree(root=new_tab["context"])
# Destroy top context
await bidi_session.browsing_context.close(context=new_tab["context"])
@@ -255,6 +262,7 @@ async def test_iframe_destroy_parent(
children=1,
url=test_page_nested_frames,
parent=None,
+ client_window=contexts[0]["clientWindow"],
)
remove_listener()
@@ -315,6 +323,7 @@ async def test_new_user_context(
context = await bidi_session.browsing_context.create(
type_hint=type_hint, user_context=user_context
)
+ contexts = await bidi_session.browsing_context.get_tree(root=context["context"])
assert len(events) == 0
on_entry = wait_for_event(CONTEXT_DESTROYED_EVENT)
@@ -329,6 +338,7 @@ async def test_new_user_context(
url="about:blank",
parent=None,
user_context=user_context,
+ client_window=contexts[0]["clientWindow"],
)
remove_listener()
@@ -349,6 +359,7 @@ async def test_with_user_context_subscription(
context = await bidi_session.browsing_context.create(
type_hint="tab", user_context=user_context
)
+ contexts = await bidi_session.browsing_context.get_tree(root=context["context"])
with wait_for_events([CONTEXT_DESTROYED_EVENT]) as waiter:
await bidi_session.browsing_context.close(context=context["context"])
@@ -362,6 +373,7 @@ async def test_with_user_context_subscription(
url="about:blank",
parent=None,
user_context=user_context,
+ client_window=contexts[0]["clientWindow"]
)
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/reference_context.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/reference_context.py
index 8511495594b..a39df42acc1 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/reference_context.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/reference_context.py
@@ -6,7 +6,9 @@ pytestmark = pytest.mark.asyncio
@pytest.mark.parametrize("value", ["tab", "window"])
-async def test_reference_context(bidi_session, value):
+async def test_reference_context(bidi_session, wait_for_event, wait_for_future_safe, subscribe_events, value):
+ await subscribe_events(["browsingContext.contextCreated"])
+
contexts = await bidi_session.browsing_context.get_tree(max_depth=0)
assert len(contexts) == 1
@@ -14,9 +16,11 @@ async def test_reference_context(bidi_session, value):
contexts = await bidi_session.browsing_context.get_tree(max_depth=0)
assert len(contexts) == 2
+ on_entry = wait_for_event("browsingContext.contextCreated")
new_context = await bidi_session.browsing_context.create(
reference_context=reference_context["context"], type_hint=value
)
+ context_info = await wait_for_future_safe(on_entry)
assert contexts[0]["context"] != new_context["context"]
assert contexts[0]["context"] != new_context["context"]
@@ -35,6 +39,7 @@ async def test_reference_context(bidi_session, value):
parent_expected=True,
parent=None,
url="about:blank",
+ client_window=context_info["clientWindow"],
)
# We can not assert the specific behavior of reference_context here,
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/type.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/type.py
index 17703d60123..f6dcdcfa064 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/type.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/type.py
@@ -8,7 +8,8 @@ pytestmark = pytest.mark.asyncio
@pytest.mark.parametrize("type_hint", ["tab", "window"])
-async def test_type(bidi_session, top_context, type_hint):
+async def test_type(bidi_session, wait_for_event, wait_for_future_safe, subscribe_events, top_context, type_hint):
+ await subscribe_events(["browsingContext.contextCreated"])
is_window = type_hint == "window"
contexts = await bidi_session.browsing_context.get_tree(max_depth=0)
@@ -16,7 +17,9 @@ async def test_type(bidi_session, top_context, type_hint):
await assert_document_status(bidi_session, top_context, visible=True, focused=True)
+ on_entry = wait_for_event("browsingContext.contextCreated")
new_context = await bidi_session.browsing_context.create(type_hint=type_hint)
+ context_info = await wait_for_future_safe(on_entry)
assert contexts[0]["context"] != new_context["context"]
await assert_document_status(bidi_session, new_context, visible=True, focused=True)
@@ -38,6 +41,7 @@ async def test_type(bidi_session, top_context, type_hint):
parent_expected=True,
parent=None,
url="about:blank",
+ client_window=context_info["clientWindow"],
)
opener_protocol_value = await bidi_session.script.evaluate(
diff --git a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/user_context.py b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/user_context.py
index 490188c265d..92282c6be6a 100644
--- a/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/user_context.py
+++ b/tests/wpt/tests/webdriver/tests/bidi/browsing_context/create/user_context.py
@@ -4,9 +4,13 @@ from .. import assert_browsing_context
pytestmark = pytest.mark.asyncio
+CONTEXT_CREATED_EVENT = "browsingContext.contextCreated"
@pytest.mark.parametrize("type_hint", ["tab", "window"])
-async def test_user_context(bidi_session, type_hint, create_user_context):
+async def test_user_context(bidi_session, wait_for_event, wait_for_future_safe, subscribe_events, type_hint, create_user_context):
+ await subscribe_events([CONTEXT_CREATED_EVENT])
+
+ on_entry = wait_for_event(CONTEXT_CREATED_EVENT)
contexts = await bidi_session.browsing_context.get_tree(max_depth=0)
assert len(contexts) == 1
@@ -18,6 +22,7 @@ async def test_user_context(bidi_session, type_hint, create_user_context):
new_context = await bidi_session.browsing_context.create(
user_context=user_context, type_hint=type_hint
)
+ context_info = await wait_for_future_safe(on_entry)
contexts = await bidi_session.browsing_context.get_tree(max_depth=0)
assert len(contexts) == 2
@@ -30,16 +35,21 @@ async def test_user_context(bidi_session, type_hint, create_user_context):
parent=None,
url="about:blank",
user_context=user_context,
+ client_window=context_info["clientWindow"]
)
-async def test_user_context_default(bidi_session, create_user_context):
+async def test_user_context_default(bidi_session, wait_for_event, wait_for_future_safe, subscribe_events, create_user_context):
+ await subscribe_events([CONTEXT_CREATED_EVENT])
+
+ on_entry = wait_for_event(CONTEXT_CREATED_EVENT)
user_context = await create_user_context()
# Create a browsing context with userContext set to "default"
context_1 = await bidi_session.browsing_context.create(
type_hint="tab", user_context="default"
)
+ context_info_1 = await wait_for_future_safe(on_entry)
context_tree_1 = await bidi_session.browsing_context.get_tree(
max_depth=0, root=context_1["context"]
)
@@ -48,12 +58,14 @@ async def test_user_context_default(bidi_session, create_user_context):
context_1["context"],
url="about:blank",
user_context="default",
+ client_window=context_info_1["clientWindow"],
)
# Create a browsing context with no userContext parameter
context_2 = await bidi_session.browsing_context.create(
type_hint="tab",
)
+ context_info_2 = await wait_for_future_safe(on_entry)
context_tree_2 = await bidi_session.browsing_context.get_tree(
max_depth=0, root=context_2["context"]
)
@@ -62,6 +74,7 @@ async def test_user_context_default(bidi_session, create_user_context):
context_2["context"],
url="about:blank",
user_context="default",
+ client_window=context_info_2["clientWindow"],
)
diff --git a/tests/wpt/tests/webdriver/tests/interop/beforeunload_prompt.py b/tests/wpt/tests/webdriver/tests/interop/beforeunload_prompt.py
index 1e47f690676..68a025ef38c 100644
--- a/tests/wpt/tests/webdriver/tests/interop/beforeunload_prompt.py
+++ b/tests/wpt/tests/webdriver/tests/interop/beforeunload_prompt.py
@@ -3,14 +3,11 @@ import pytest
import pytest_asyncio
from webdriver.error import NoSuchAlertException
-from tests.support.sync import AsyncPoll
-
from ..bidi import (
any_string,
recursive_compare,
)
-
pytestmark = pytest.mark.asyncio
USER_PROMPT_CLOSED_EVENT = "browsingContext.userPromptClosed"
@@ -18,7 +15,7 @@ USER_PROMPT_OPENED_EVENT = "browsingContext.userPromptOpened"
@pytest_asyncio.fixture
-async def check_beforeunload_not_implicitly_accepted(
+async def check_beforeunload_implicitly_accepted(
bidi_session,
current_session,
setup_beforeunload_page,
@@ -29,7 +26,7 @@ async def check_beforeunload_not_implicitly_accepted(
execute_as_async,
url,
):
- async def check_beforeunload_not_implicitly_accepted(accept):
+ async def check_beforeunload_implicitly_accepted():
current_session.window_handle = new_tab["context"]
page_beforeunload = await setup_beforeunload_page(new_tab)
@@ -41,15 +38,16 @@ async def check_beforeunload_not_implicitly_accepted(
await subscribe_events([USER_PROMPT_CLOSED_EVENT, USER_PROMPT_OPENED_EVENT])
# Using WebDriver classic's navigation command to navigate away from
- # the page will hang and wait for the beforeunload dialog to close.
- # As such start the command immediately as task but await for it later
- # when BiDi closed the prompt.
+ # the page can hang if the prompt is not accepted. As such, wrap the
+ # command to fail on timeout gracefully.
def sync_navigate():
current_session.url = page_target
- task_navigate = asyncio.create_task(execute_as_async(sync_navigate))
- opened_event = await wait_for_future_safe(on_prompt_opened)
+ await wait_for_future_safe(
+ asyncio.create_task(execute_as_async(sync_navigate)))
+ # Wait for BiDi events.
+ opened_event = await wait_for_future_safe(on_prompt_opened)
recursive_compare(
{
"context": new_tab["context"],
@@ -59,59 +57,46 @@ async def check_beforeunload_not_implicitly_accepted(
opened_event,
)
- # Close the beforeunload prompt and wait for the navigation to finish.
- await bidi_session.browsing_context.handle_user_prompt(
- context=new_tab["context"], accept=accept
- )
closed_event = await wait_for_future_safe(on_prompt_closed)
- await task_navigate
-
- # Check that the beforeunload prompt is closed and the event was sent.
- with pytest.raises(NoSuchAlertException):
- current_session.alert.text
-
recursive_compare(
{
- "accepted": accept,
+ "accepted": True,
"context": new_tab["context"],
"type": "beforeunload",
},
closed_event,
)
- if accept:
- assert current_session.url == page_target
- else:
- assert current_session.url == page_beforeunload
+ # Assert via classic that the alert is not present.
+ with pytest.raises(NoSuchAlertException):
+ current_session.alert.text
+
+ # Assert the classic url changed.
+ assert current_session.url == page_target
- return check_beforeunload_not_implicitly_accepted
+ return check_beforeunload_implicitly_accepted
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
-@pytest.mark.parametrize("accept", [False, True])
-async def test_accept(check_beforeunload_not_implicitly_accepted, accept):
- await check_beforeunload_not_implicitly_accepted(accept)
+async def test_accept(check_beforeunload_implicitly_accepted):
+ await check_beforeunload_implicitly_accepted()
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
-@pytest.mark.parametrize("accept", [False, True])
-async def test_accept_and_notify(check_beforeunload_not_implicitly_accepted, accept):
- await check_beforeunload_not_implicitly_accepted(accept)
+async def test_accept_and_notify(check_beforeunload_implicitly_accepted):
+ await check_beforeunload_implicitly_accepted()
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
-@pytest.mark.parametrize("accept", [False, True])
-async def test_dismiss(check_beforeunload_not_implicitly_accepted, accept):
- await check_beforeunload_not_implicitly_accepted(accept)
+async def test_dismiss(check_beforeunload_implicitly_accepted):
+ await check_beforeunload_implicitly_accepted()
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
-@pytest.mark.parametrize("accept", [False, True])
-async def test_dismiss_and_notify(check_beforeunload_not_implicitly_accepted, accept):
- await check_beforeunload_not_implicitly_accepted(accept)
+async def test_dismiss_and_notify(check_beforeunload_implicitly_accepted):
+ await check_beforeunload_implicitly_accepted()
@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
-@pytest.mark.parametrize("accept", [False, True])
-async def test_ignore(check_beforeunload_not_implicitly_accepted, accept):
- await check_beforeunload_not_implicitly_accepted(accept)
+async def test_ignore(check_beforeunload_implicitly_accepted):
+ await check_beforeunload_implicitly_accepted()
diff --git a/tests/wpt/tests/webnn/conformance_tests/prelu.https.any.js b/tests/wpt/tests/webnn/conformance_tests/prelu.https.any.js
index b89de832d3e..cfd043ce617 100644
--- a/tests/wpt/tests/webnn/conformance_tests/prelu.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/prelu.https.any.js
@@ -22,8 +22,7 @@ const preluTests = [
'inputs': {
'preluInput': {
'data': [-4.794857501983643],
- 'descriptor': {shape: [], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [], dataType: 'float32'}
},
'preluSlope': {
'data': [1.1202747821807861],
@@ -114,8 +113,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [24], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [24], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -155,6 +153,59 @@ const preluTests = [
}
},
{
+ 'name': 'prelu float32 1D non-constant slope',
+ 'graph': {
+ 'inputs': {
+ 'preluInput': {
+ 'data': [
+ -2.549168109893799, -4.794857501983643, 8.413617134094238,
+ 6.108623504638672, -8.492292404174805, 3.3143365383148193,
+ 1.1687211990356445, -0.141762837767601, -6.714652061462402,
+ 5.787421703338623, -3.755627393722534, -4.89828634262085,
+ 7.3295159339904785, -3.9542298316955566, 7.067296981811523,
+ 9.439736366271973, -2.558180093765259, -8.658834457397461,
+ 8.47507381439209, 4.551425457000732, -9.267870903015137,
+ -0.262177437543869, 1.3258955478668213, -7.41831111907959
+ ],
+ 'descriptor': {shape: [24], dataType: 'float32'}
+ },
+ 'preluSlope': {
+ 'data': [
+ 9.343092918395996, 0.2800687253475189, -4.617084980010986,
+ 1.1202747821807861, -1.4334710836410522, -3.157594919204712,
+ -6.28995418548584, -5.0107879638671875, -6.899077415466309,
+ 3.5725347995758057, 6.861966609954834, -1.961531400680542,
+ 4.5832037925720215, 2.6643502712249756, 9.192955017089844,
+ -9.554699897766113, -5.505102157592773, -2.3927369117736816,
+ 3.58212947845459, -2.3224003314971924, -1.9816573858261108,
+ 4.155889987945557, -1.799522042274475, 9.295849800109863
+ ],
+ 'descriptor': {shape: [24], dataType: 'float32'}
+ }
+ },
+ 'operators': [{
+ 'name': 'prelu',
+ 'arguments': [{'input': 'preluInput'}, {'slope': 'preluSlope'}],
+ 'outputs': 'preluOutput'
+ }],
+ 'expectedOutputs': {
+ 'preluOutput': {
+ 'data': [
+ -23.817113876342773, -1.342889666557312, 8.413617134094238,
+ 6.108623504638672, 12.173455238342285, 3.3143365383148193,
+ 1.1687211990356445, 0.7103435397148132, 46.32490539550781,
+ 5.787421703338623, -25.7709903717041, 9.608142852783203,
+ 7.3295159339904785, -10.535453796386719, 7.067296981811523,
+ 9.439736366271973, 14.083043098449707, 20.718313217163086,
+ 8.47507381439209, 4.551425457000732, 18.365745544433594,
+ -1.0895805358886719, 1.3258955478668213, -68.95950317382812
+ ],
+ 'descriptor': {shape: [24], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
'name': 'prelu float32 2D tensors',
'graph': {
'inputs': {
@@ -169,8 +220,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [4, 6], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [4, 6], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -224,8 +274,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 3, 4], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 3, 4], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -279,8 +328,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -334,8 +382,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -389,8 +436,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [5.073923110961914, 0.480774462223053, -7.091750144958496],
@@ -435,8 +481,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [5.0114545822143555],
@@ -481,8 +526,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [
@@ -530,8 +574,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [5.073923110961914, 0.480774462223053, -7.091750144958496],
@@ -576,8 +619,7 @@ const preluTests = [
8.47507381439209, 4.551425457000732, -9.267870903015137,
-0.262177437543869, 1.3258955478668213, -7.41831111907959
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float32'}
},
'preluSlope': {
'data': [5.0114545822143555, 5.0114545822143555],
@@ -615,8 +657,7 @@ const preluTests = [
'inputs': {
'preluInput': {
'data': [-4.79296875],
- 'descriptor': {shape: [], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [], dataType: 'float16'}
},
'preluSlope': {
'data': [1.1201171875],
@@ -650,8 +691,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [24], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [24], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -698,8 +738,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [24], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [24], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -734,6 +773,52 @@ const preluTests = [
}
},
{
+ 'name': 'prelu float16 1D non-constant slope',
+ 'graph': {
+ 'inputs': {
+ 'preluInput': {
+ 'data': [
+ -2.548828125, -4.79296875, 8.4140625, 6.109375,
+ -8.4921875, 3.314453125, 1.1689453125, -0.1417236328125,
+ -6.71484375, 5.7890625, -3.755859375, -4.8984375,
+ 7.328125, -3.955078125, 7.06640625, 9.4375,
+ -2.55859375, -8.65625, 8.4765625, 4.55078125,
+ -9.265625, -0.26220703125, 1.326171875, -7.41796875
+ ],
+ 'descriptor': {shape: [24], dataType: 'float16'}
+ },
+ 'preluSlope': {
+ 'data': [
+ 9.34375, 0.280029296875, -4.6171875, 1.1201171875,
+ -1.43359375, -3.158203125, -6.2890625, -5.01171875,
+ -6.8984375, 3.572265625, 6.86328125, -1.9619140625,
+ 4.58203125, 2.6640625, 9.1953125, -9.5546875,
+ -5.50390625, -2.392578125, 3.58203125, -2.322265625,
+ -1.9814453125, 4.15625, -1.7998046875, 9.296875
+ ],
+ 'descriptor': {shape: [24], dataType: 'float16'}
+ }
+ },
+ 'operators': [{
+ 'name': 'prelu',
+ 'arguments': [{'input': 'preluInput'}, {'slope': 'preluSlope'}],
+ 'outputs': 'preluOutput'
+ }],
+ 'expectedOutputs': {
+ 'preluOutput': {
+ 'data': [
+ -23.8125, -1.341796875, 8.4140625, 6.109375, 12.171875,
+ 3.314453125, 1.1689453125, 0.71044921875, 46.3125, 5.7890625,
+ -25.78125, 9.609375, 7.328125, -10.5390625, 7.06640625,
+ 9.4375, 14.0859375, 20.703125, 8.4765625, 4.55078125,
+ 18.359375, -1.08984375, 1.326171875, -68.9375
+ ],
+ 'descriptor': {shape: [24], dataType: 'float16'}
+ }
+ }
+ }
+ },
+ {
'name': 'prelu float16 2D tensors',
'graph': {
'inputs': {
@@ -746,8 +831,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [4, 6], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [4, 6], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -794,8 +878,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 3, 4], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 3, 4], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -842,8 +925,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -890,8 +972,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 1, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [
@@ -938,8 +1019,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [5.07421875, 0.480712890625, -7.08984375],
@@ -980,8 +1060,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [5.01171875],
@@ -1021,8 +1100,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [4.875, -8.5, 1.181640625, -9.984375, -4.42578125, -6.65625],
@@ -1062,8 +1140,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [5.07421875, 0.480712890625, -7.08984375],
@@ -1104,8 +1181,7 @@ const preluTests = [
-2.55859375, -8.65625, 8.4765625, 4.55078125,
-9.265625, -0.26220703125, 1.326171875, -7.41796875
],
- 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'},
- 'constant': true
+ 'descriptor': {shape: [2, 2, 2, 3], dataType: 'float16'}
},
'preluSlope': {
'data': [5.01171875],
diff --git a/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js b/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js
index aa816cce7fb..70e8cab0d95 100644
--- a/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js
+++ b/tests/wpt/tests/webnn/conformance_tests/qdq_subgraph.https.any.js
@@ -366,48 +366,47 @@ const subgraphTests = [
'inputs': {
'inputA': {
'data': [
- 49.1112174987793, 11.907459259033203, 21.115795135498047,
- 70.7490005493164, 94.51628112792969, 93.78905487060547,
- 11.178888320922852, 32.80592346191406, 83.31897735595703,
- 91.1207275390625, 0.11235756427049637, 15.397955894470215,
+ 49.1112174987793, 11.907459259033203,
+ 21.115795135498047, 70.7490005493164,
],
- 'descriptor': {shape: [2, 3, 2], dataType: 'float32'},
+ 'descriptor': {shape: [2, 2], dataType: 'float32'},
'constant': false
},
'inputAScale': {
- 'data': [0.003921568859368563],
+ 'data': [0.3921568859368563],
'descriptor': {shape: [1], dataType: 'float32'},
'constant': true
},
'inputAZeroPoint': {
- 'data': [127],
+ 'data': [16],
'descriptor': {shape: [1], dataType: 'int8'},
'constant': true
},
'inputB': {
'data': [
- 2, 17, 38, 41, 5, 3, 2, 17, 38, 41, 5, 3,
+ 21, 24,
+ 8, 13
],
- 'descriptor': {shape: [2, 3, 2], dataType: 'int8'},
+ 'descriptor': {shape: [2, 2], dataType: 'int8'},
'constant': true
},
'inputBScale': {
- 'data': [0.003921568859368563],
+ 'data': [0.3921568859368563],
'descriptor': {shape: [1], dataType: 'float32'},
'constant': true
},
'inputBZeroPoint': {
- 'data': [127],
+ 'data': [16],
'descriptor': {shape: [1], dataType: 'int8'},
'constant': true
},
'outputScale': {
- 'data': [0.003921568859368563],
+ 'data': [0.3921568859368563],
'descriptor': {shape: [1], dataType: 'float32'},
'constant': true
},
'outputZeroPoint': {
- 'data': [127],
+ 'data': [16],
'descriptor': {shape: [1], dataType: 'int8'},
'constant': true
},
@@ -438,24 +437,240 @@ const subgraphTests = [
'outputs': 'dequantizedInputB'
},
{
- 'name': 'add',
+ 'name': 'mul',
'arguments': [
{'inputA': 'dequantizedInputA'}, {'inputB': 'dequantizedInputB'}
],
- 'outputs': 'addOutput'
+ 'outputs': 'mulOutput'
},
{
'name': 'quantizeLinear',
'arguments': [
- {'input': 'addOutput'},
+ {'input': 'mulOutput'},
{'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
],
- 'outputs': 'quantizedAddOutput'
+ 'outputs': 'quantizedMulOutput'
},
{
'name': 'dequantizeLinear',
'arguments': [
- {'input': 'quantizedAddOutput'},
+ {'input': 'quantizedMulOutput'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'output'
+ }
+ ],
+ 'expectedOutputs': {
+ 'output': {
+ 'data': [
+ 43.529415130615234, 36.86274719238281,
+ -56.4705924987793, -51.372554779052734,
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'quantized element-wise binary max',
+ 'graph': {
+ 'inputs': {
+ 'inputA': {
+ 'data': [
+ -2.549168109893799, -4.794857501983643,
+ 8.413617134094238, 6.108623504638672
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'float32'},
+ 'constant': false
+ },
+ 'inputAScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'inputAZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ 'inputB': {
+ 'data': [
+ 12, 24, 35, 11,
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'int8'},
+ 'constant': true
+ },
+ 'inputBScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'inputBZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ 'outputScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'outputZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ },
+ 'operators': [
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'inputA'},
+ {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'}
+ ],
+ 'outputs': 'quantizedInputA'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedInputA'},
+ {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'}
+ ],
+ 'outputs': 'dequantizedInputA'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'inputB'},
+ {'scale': 'inputBScale', 'zeroPoint': 'inputBZeroPoint'}
+ ],
+ 'outputs': 'dequantizedInputB'
+ },
+ {
+ 'name': 'max',
+ 'arguments': [{'inputA': 'dequantizedInputA'}, {'inputB': 'dequantizedInputB'}],
+ 'outputs': 'maxOutput'
+ },
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'maxOutput'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'quantizedMaxOutput'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedMaxOutput'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'output'
+ }
+ ],
+ 'expectedOutputs': {
+ 'output': {
+ 'data': [
+ 48.03300857543945, 52.150123596191406,
+ 55.92414474487305, 47.68991470336914,
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'float32'}
+ }
+ }
+ }
+ },
+ {
+ 'name': 'quantized element-wise binary min',
+ 'graph': {
+ 'inputs': {
+ 'inputA': {
+ 'data': [
+ 3.549168109893799, 4.794857501983643,
+ 8.413617134094238, 6.108623504638672
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'float32'},
+ 'constant': false
+ },
+ 'inputAScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'inputAZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ 'inputB': {
+ 'data': [
+ 12, 24, 35, 11,
+ ],
+ 'descriptor': {shape: [2, 2], dataType: 'int8'},
+ 'constant': true
+ },
+ 'inputBScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'inputBZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ 'outputScale': {
+ 'data': [0.343092918395996],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'outputZeroPoint': {
+ 'data': [-128],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ },
+ 'operators': [
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'inputA'},
+ {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'}
+ ],
+ 'outputs': 'quantizedInputA'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedInputA'},
+ {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'}
+ ],
+ 'outputs': 'dequantizedInputA'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'inputB'},
+ {'scale': 'inputBScale', 'zeroPoint': 'inputBZeroPoint'}
+ ],
+ 'outputs': 'dequantizedInputB'
+ },
+ {
+ 'name': 'min',
+ 'arguments': [{'inputA': 'dequantizedInputA'}, {'inputB': 'dequantizedInputB'}],
+ 'outputs': 'minOutput'
+ },
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'minOutput'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'quantizedMinOutput'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedMinOutput'},
{'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
],
'outputs': 'output'
@@ -464,12 +679,10 @@ const subgraphTests = [
'expectedOutputs': {
'output': {
'data': [
- -0.4901961088180542, -0.43137258291244507, -0.3490196168422699,
- -0.33725491166114807, -0.4784314036369324, -0.4862745404243469,
- -0.4901961088180542, -0.43137258291244507, -0.3490196168422699,
- -0.33725491166114807, -0.4784314036369324, -0.4862745404243469,
+ 3.430929183959961, 4.803300857543945,
+ 8.577322959899902, 6.17567253112793,
],
- 'descriptor': {shape: [2, 3, 2], dataType: 'float32'}
+ 'descriptor': {shape: [2, 2], dataType: 'float32'}
}
}
}
@@ -1255,6 +1468,132 @@ const subgraphTests = [
}
}
},
+ {
+ 'name': 'quantized split',
+ 'graph': {
+ 'inputs': {
+ 'input': {
+ 'data': [
+ 1.6811466217041016, 0.0479511022567749, 0.33355462551116943,
+ -0.1988269537687301, -0.0041167140007019, -0.0634240251779556,
+ ],
+ 'descriptor': {shape: [2, 3], dataType: 'float32'},
+ 'constant': false
+ },
+ 'inputScale': {
+ 'data': [0.003921568859368563],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'inputZeroPoint': {
+ 'data': [16],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ 'outputScale': {
+ 'data': [0.003921568859368563],
+ 'descriptor': {shape: [1], dataType: 'float32'},
+ 'constant': true
+ },
+ 'outputZeroPoint': {
+ 'data': [16],
+ 'descriptor': {shape: [1], dataType: 'int8'},
+ 'constant': true
+ },
+ },
+ 'operators': [
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'input'},
+ {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'}
+ ],
+ 'outputs': 'quantizedInput'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedInput'},
+ {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'}
+ ],
+ 'outputs': 'dequantizedInput'
+ },
+ {
+ 'name': 'split',
+ 'arguments': [{'input': 'dequantizedInput'}, {'splits': 3}, {'options': {'axis': 1}}],
+ 'outputs': ['splitOutput 1', 'splitOutput 2', 'splitOutput 3'],
+ },
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'splitOutput 1'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'quantizedSplitOutput 1'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedSplitOutput 1'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'output 1'
+ },
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'splitOutput 2'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'quantizedSplitOutput 2'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedSplitOutput 2'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'output 2'
+ },
+ {
+ 'name': 'quantizeLinear',
+ 'arguments': [
+ {'input': 'splitOutput 3'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'quantizedSplitOutput 3'
+ },
+ {
+ 'name': 'dequantizeLinear',
+ 'arguments': [
+ {'input': 'quantizedSplitOutput 3'},
+ {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+ ],
+ 'outputs': 'output 3'
+ }
+ ],
+ 'expectedOutputs': {
+ 'output 1': {
+ 'data': [
+ 0.43529415130615234, -0.20000001788139343,
+ ],
+ 'descriptor': {shape: [2, 1], dataType: 'float32'}
+ },
+ 'output 2': {
+ 'data': [
+ 0.0470588281750679, -0.003921568859368563,
+ ],
+ 'descriptor': {shape: [2, 1], dataType: 'float32'}
+ },
+ 'output 3': {
+ 'data': [
+ 0.3333333432674408, -0.062745101749897,
+ ],
+ 'descriptor': {shape: [2, 1], dataType: 'float32'}
+ }
+ }
+ }
+ },
];
if (navigator.ml) {
diff --git a/tests/wpt/tests/webnn/resources/utils.js b/tests/wpt/tests/webnn/resources/utils.js
index 9d5cfc70c10..c562b3028bd 100644
--- a/tests/wpt/tests/webnn/resources/utils.js
+++ b/tests/wpt/tests/webnn/resources/utils.js
@@ -143,8 +143,8 @@ const contextOptions = kContextOptionsForVariant[variant];
const assertDescriptorsEquals = (outputOperand, expected) => {
const dataType =
expected.castedType ? expected.castedType : expected.dataType;
- assert_true(
- outputOperand.dataType === dataType,
+ assert_equals(
+ outputOperand.dataType, dataType,
'actual output dataType should be equal to expected output dataType');
assert_array_equals(
outputOperand.shape, expected.shape,
@@ -282,7 +282,7 @@ const getBitwise = (value, dataType) => {
* @param {Array} actual - Array of test values.
* @param {Array} expected - Array of values expected to be close to the values
* in ``actual``.
- * @param {Number} nulp - A BigInt value indicates acceptable ULP distance.
+ * @param {(Number|BigInt)} nulp - A value indicates acceptable ULP distance.
* @param {String} dataType - A data type string, value: "float32",
* more types, please see:
* https://www.w3.org/TR/webnn/#enumdef-mloperanddatatype
@@ -292,33 +292,25 @@ const assert_array_approx_equals_ulp = (actual, expected, nulp, dataType, descri
/*
* Test if two primitive arrays are equal within acceptable ULP distance
*/
- assert(
- typeof nulp === 'number', `unexpected type for nulp: ${typeof nulp}`);
- assert_true(
- actual.length === expected.length,
- `assert_array_approx_equals_ulp: ${description} lengths differ, ` +
- `expected ${expected.length} but got ${actual.length}`);
- let distance;
+ assert_equals(
+ actual.length, expected.length,
+ `assert_array_approx_equals_ulp: ${description} lengths differ`);
for (let i = 0; i < actual.length; i++) {
if (actual[i] === expected[i]) {
continue;
} else {
- distance = ulpDistance(actual[i], expected[i], dataType);
-
- // if true, invoke assert_true() in failure case
- // if false, it's expected, not invoke assert_true() in success case to
- // prevent spammy output
- if (distance > nulp) {
- assert_true(
- false,
+ let distance = ulpDistance(actual[i], expected[i], dataType);
+
+ // TODO: See if callers can be updated to pass matching type.
+ nulp = typeof distance === 'bigint' ? BigInt(nulp) : Number(nulp);
+
+ assert_less_than_equal(distance, nulp,
`assert_array_approx_equals_ulp: ${description} actual ` +
`${
dataType === 'float16' ?
float16AsUint16ToNumber(actual[i]) :
actual[i]} should be close enough to expected ` +
- `${expected[i]} by the acceptable ${nulp} ULP distance, ` +
- `but they have ${distance} ULP distance`);
- }
+ `${expected[i]} by ULP distance:`);
}
}
};
diff --git a/tests/wpt/tests/webnn/resources/utils_validation.js b/tests/wpt/tests/webnn/resources/utils_validation.js
index 77a6d79205b..3f8687b88f1 100644
--- a/tests/wpt/tests/webnn/resources/utils_validation.js
+++ b/tests/wpt/tests/webnn/resources/utils_validation.js
@@ -205,7 +205,7 @@ promise_setup(async () => {
function assert_throws_with_label(func, regrexp) {
try {
func.call(this);
- assert_true(false, 'Graph builder method unexpectedly succeeded');
+ assert_unreached('Graph builder method unexpectedly succeeded');
} catch (e) {
assert_equals(e.name, 'TypeError');
const error_message = e.message;
diff --git a/tests/wpt/tests/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html b/tests/wpt/tests/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html
index 9eb7020a781..ffb29e7dec6 100644
--- a/tests/wpt/tests/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html
+++ b/tests/wpt/tests/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html
@@ -12,6 +12,31 @@
<body>
<video id="video" autoplay controls playsinline></video>
<script>
+promise_test(async (test) => {
+ const worker = new Worker('RTCRtpScriptTransform-encoded-transform-worker.js');
+ let sender, receiver;
+ const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
+ const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
+
+ const pc = new RTCPeerConnection();
+ const transceiver1 = pc.addTransceiver("audio");
+ const transceiver2 = pc.addTransceiver("audio");
+
+ transceiver1.sender.transform = senderTransform;
+ transceiver1.receiver.transform = receiverTransform;
+
+ transceiver1.sender.transform = senderTransform;
+ transceiver1.receiver.transform = receiverTransform;
+
+ assert_throws_dom("InvalidStateError", () => transceiver2.sender.transform = senderTransform, "set a used transform 1");
+ assert_throws_dom("InvalidStateError", () => transceiver2.receiver.transform = receiverTransform, "set a used transform 2");
+
+ transceiver1.sender.transform = null;
+ transceiver1.receiver.transform = null;
+
+ assert_throws_dom("InvalidStateError", () => transceiver2.sender.transform = senderTransform, "set a used transform 3");
+ assert_throws_dom("InvalidStateError", () => transceiver2.receiver.transform = receiverTransform, "set a used transform 4");
+}, "Once a transform has been attached, it cannot be reused elsewhere.");
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-worker.js');
diff --git a/tests/wpt/tests/webrtc-encoded-transform/idlharness.https.window.js b/tests/wpt/tests/webrtc-encoded-transform/idlharness.https.window.js
index 2c6ef19ca82..d3eea3bc138 100644
--- a/tests/wpt/tests/webrtc-encoded-transform/idlharness.https.window.js
+++ b/tests/wpt/tests/webrtc-encoded-transform/idlharness.https.window.js
@@ -1,3 +1,6 @@
+// META: variant=?exclude=SFrameTransform.*
+// META: variant=?include=SFrameTransform.*
+// META: script=/common/subset-tests-by-key.js
// META: script=/resources/WebIDLParser.js
// META: script=/resources/idlharness.js
// META: script=./RTCPeerConnection-helper.js