Sync WPT with upstream (18-05-2025) (#37040)

Automated downstream sync of changes from upstream as of 18-05-2025
[no-wpt-sync]

Signed-off-by: WPT Sync Bot <ghbot+wpt-sync@servo.org>
This commit is contained in:
Servo WPT Sync 2025-05-18 03:43:27 +02:00 committed by GitHub
parent ed469fe72f
commit 070a8cf937
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
377 changed files with 11542 additions and 2416 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
[align-self-stretch-auto-margins.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[justify-self-stretch-auto-margins.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[justify-self-auto-margins-2.html]
expected: FAIL

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,2 @@
[font-family-name-000.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flex-gap-decorations-020.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flex-gap-decorations-021.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[grid-gap-decorations-034.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[grid-gap-decorations-035.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[grid-gap-decorations-036.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[grid-gap-decorations-037.html]
expected: FAIL

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -73,3 +73,6 @@
[Locals are function specific]
expected: FAIL
[Local with self-cycle in unused fallback]
expected: FAIL

View file

@ -19,3 +19,6 @@
[attr() cycle through function]
expected: FAIL
[attr() cycle through unused fallback in local]
expected: FAIL

View file

@ -0,0 +1,2 @@
[overflow-video.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[empty-span-001.html]
expected: FAIL

View file

@ -47,8 +47,14 @@
[CSS Values and Units Test: attr 18]
expected: FAIL
[CSS Values and Units Test: attr 19]
expected: FAIL
[CSS Values and Units Test: attr 20]
expected: FAIL
[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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
[variable-cycles.html]
[Cycle in unused fallback]
expected: FAIL

View file

@ -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

View file

@ -0,0 +1,2 @@
[hidpi-invert-filter-background.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[has-with-nth-child-sibling-remove.html]
expected: FAIL

View file

@ -1,3 +0,0 @@
[a-click.html]
[aElement.click() before the load event must NOT replace]
expected: FAIL

View file

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

View file

@ -0,0 +1,2 @@
[media_fragment_seek.html]
expected: CRASH

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
[iframe_javascript_url_initial_insertion.html]
[javascript: URL in iframe src, initial insertion check]
expected: FAIL

View file

@ -0,0 +1,3 @@
[iframe_javascript_url_loading_lazy.htm]
[javascript: URL in iframe src and loading="lazy"]
expected: FAIL

View file

@ -0,0 +1,3 @@
[iframe_javascript_url_not_about_blank.html]
[javascript: URL in iframe src, initial src is not about:blank]
expected: FAIL

View file

@ -0,0 +1,3 @@
[iframe_javascript_url_remove_srcdoc.html]
[javascript: URL in iframe src, removing srcdoc]
expected: FAIL

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
[intrinsic_sizes.htm]
[default object size after src is removed]
expected: FAIL

View file

@ -0,0 +1,3 @@
[selectedcontent-mutations.tentative.html]
[MutationObserver records during parsing of <select> with <selectedcontent>]
expected: FAIL

View file

@ -1,2 +0,0 @@
[display-css-property-reftest.tentative.html]
expected: FAIL

View file

@ -1,3 +0,0 @@
[display-css-property.tentative.html]
['display' should be either 'inline-block' or 'none']
expected: FAIL

View file

@ -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

View file

@ -16,9 +16,3 @@
[Reload fetchStart > Original fetchStart]
expected: FAIL
[Reload domContentLoadedEventEnd > Original domContentLoadedEventEnd]
expected: FAIL
[Reload domComplete > Original domComplete]
expected: FAIL

View file

@ -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

View file

@ -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]

View file

@ -0,0 +1,2 @@
[script-src-allows-source-phase-wasm.tentative.html]
expected: ERROR

View file

@ -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

View file

@ -0,0 +1,7 @@
[source-phase-preload.tentative.html]
expected: TIMEOUT
[Static source phase import.]
expected: TIMEOUT
[Dynamic source phase import.]
expected: NOTRUN

View file

@ -0,0 +1,3 @@
[worklet-import-source-phase.tentative.https.html]
[Import a source phase module to a worklet]
expected: FAIL

View file

@ -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

View file

@ -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 }}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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);
}

View file

@ -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>

View file

@ -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.');

View file

@ -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');

View file

@ -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');

View file

@ -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');

View file

@ -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>

View file

@ -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.');

View file

@ -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>

View file

@ -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().');

View file

@ -1,4 +1,5 @@
// META: title=Summarizer Availability Available
// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long

View file

@ -1,4 +1,5 @@
// META: title=Summarizer Availability
// META: script=/resources/testdriver.js
// META: script=../resources/util.js
// META: timeout=long

View file

@ -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);

View file

@ -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."');

View file

@ -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;
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;
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");
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>

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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();
@ -102,11 +94,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'});

View file

@ -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>

View file

@ -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.');

View file

@ -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');

View file

@ -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');

View file

@ -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');

View file

@ -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>

View file

@ -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.');

View file

@ -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>

View file

@ -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>

View file

@ -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'});

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

Some files were not shown because too many files have changed in this diff Show more