diff options
43 files changed, 476 insertions, 1629 deletions
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 493a547882e..38ead3071d5 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -230368,23 +230368,6 @@ } } }, - "std-toast": { - "ref-tests": { - "toast-slotting.html": [ - "4d6f5038f2d6ffa80ebdfa12798c8c4202b39670", - [ - null, - [ - [ - "/std-toast/ref-tests/toast-slotting-expected.html", - "==" - ] - ], - {} - ] - ] - } - }, "svg": { "coordinate-systems": { "abspos.html": [ @@ -239750,7 +239733,7 @@ [] ], "beacon-common.sub.js": [ - "ae2f169f272e9efbbea3b7464ea77c34fe65c6e1", + "3635da73b75400ed3699576e2eac6329c39bba1b", [] ], "headers": { @@ -239761,7 +239744,7 @@ }, "resources": { "beacon.py": [ - "5f2553d3c4d506f7e292cfb73d81930a83a12d76", + "34b55b1a95b9fb6b925b71541a090f23a4aba21d", [] ], "content-type.py": [ @@ -315646,7 +315629,7 @@ [] ], "postback.html.headers": [ - "6604450991a122e3e241e40b1b9e0516c525389d", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", [] ] } @@ -319657,7 +319640,7 @@ [] ], "echo-iframe.html.headers": [ - "6604450991a122e3e241e40b1b9e0516c525389d", + "4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28", [] ], "echo-worker.js": [ @@ -341080,24 +341063,6 @@ [] ] }, - "std-toast": { - "META.yml": [ - "c54357a03f214572481fc08be473cc308d50097b", - [] - ], - "ref-tests": { - "toast-slotting-expected.html": [ - "b4b365c7a9dfa25363acfb3123b1c019c3ca08d0", - [] - ] - }, - "resources": { - "helpers.js": [ - "256f0c880408c3343d36392f8b4cf64d9bbbfbe6", - [] - ] - } - }, "storage": { "META.yml": [ "2aad1fb513710e839ad86c923bf208dae604d3d2", @@ -373249,7 +373214,7 @@ ] ], "beacon-cors.sub.window.js": [ - "4a8e4dfbc6570e58ae7d57e409d4fbbc72a47964", + "5543bddc5f66b3a09c54937c0cf665d2d25ea8d6", [ "beacon/beacon-cors.sub.window.html", { @@ -373299,7 +373264,7 @@ ] ], "beacon-preflight-failure.sub.window.js": [ - "27e6905a9bd95a78621fe86d07d3671f95af111e", + "c5a2d813f176adc42d3ce3b6feeea2b6e34e9c69", [ "beacon/beacon-preflight-failure.sub.window.html", { @@ -373323,10 +373288,10 @@ {} ] ], - "beacon-redirect.window.js": [ - "3a8aef3c742b68348fa2c27303e297e8386768b3", + "beacon-redirect.sub.window.js": [ + "fd23a45f86badfc1d540de414cb351c4e5ef06bb", [ - "beacon/beacon-redirect.window.html", + "beacon/beacon-redirect.sub.window.html", { "script_metadata": [ [ @@ -431060,7 +431025,7 @@ ] ], "none.https.html": [ - "e603753084cf2c3c85b0187a7a8f66b3de8cf401", + "548525968352147dc14ceeeab1ad6b6a93b2729a", [ null, { @@ -529186,82 +529151,6 @@ ] ] }, - "std-toast": { - "actions.html": [ - "6a80def09985f27867f2c41bbb138b1a40399641", - [ - null, - {} - ] - ], - "attributes.html": [ - "9b87280b6688b3847401ea7b97ed63f6164bf70a", - [ - null, - {} - ] - ], - "closebutton.html": [ - "d53c78aca5da605bece2433c3796d8b1197e848e", - [ - null, - {} - ] - ], - "events-open.html": [ - "a49414d2fce2061bcc1399e222cd6b2b5ccdc872", - [ - null, - {} - ] - ], - "events-showhide.html": [ - "547f742f713cbf4c46a82ae1df353aa317b2d2df", - [ - null, - {} - ] - ], - "methods.html": [ - "981b9fba4341e5798c7456e02da53e97bd1369f3", - [ - null, - {} - ] - ], - "options.html": [ - "0383d71f9ae9ff9c2f682abd8158b9c2e31e245b", - [ - null, - { - "timeout": "long" - } - ] - ], - "reflection.html": [ - "36cbaf652287dbbde5a871b398d313cf70d1b275", - [ - null, - { - "timeout": "long" - } - ] - ], - "show-toast.html": [ - "50cdc2c06ddbf34b16119f9c42e3a7cbaf5ec258", - [ - null, - {} - ] - ], - "styles.html": [ - "1db8620485dc459577649e0c2689194d106dcc51", - [ - null, - {} - ] - ] - }, "storage": { "estimate-indexeddb.https.any.js": [ "c62f5a96c1a2c22142988eabd5b59ce3d3409f95", @@ -551948,7 +551837,7 @@ ] ], "RTCDTMFSender-insertDTMF.https.html": [ - "ac27c5139ccb12715d51cbd8f5ecdd83c40c23d1", + "71cfe70171f7ff4aeddd01483fce6edbf29e59b9", [ null, {} @@ -552252,6 +552141,13 @@ {} ] ], + "RTCPeerConnection-operations.https.html": [ + "e88c8b28172c1c0edbfaef4dda10a306470ad96f", + [ + null, + {} + ] + ], "RTCPeerConnection-remote-track-mute.https.html": [ "c280a7d44d8d2a477f2600c741ed68903e516651", [ @@ -552304,7 +552200,7 @@ ] ], "RTCPeerConnection-setLocalDescription-parameterless.https.html": [ - "0cce78bfbca161016721c4e2b122382c4be868f7", + "5a7a76319a0571961d7dacc3d1562327089587bd", [ null, {} diff --git a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini deleted file mode 100644 index 4bfb0c2053a..00000000000 --- a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[hit-test-floats-004.html] - [Miss float below something else] - expected: FAIL - diff --git a/tests/wpt/metadata/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html.ini b/tests/wpt/metadata/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html.ini index e35a452a186..70a00a101f6 100644 --- a/tests/wpt/metadata/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html.ini +++ b/tests/wpt/metadata/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html.ini @@ -1,2 +1,2 @@ [no-transition-from-ua-to-blocking-stylesheet.html] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini b/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini deleted file mode 100644 index 4c79907309b..00000000000 --- a/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[CaretPosition-001.html] - [Element at (400, 100)] - expected: FAIL - diff --git a/tests/wpt/metadata/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini b/tests/wpt/metadata/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini index 628b1fab770..c884dc82eab 100644 --- a/tests/wpt/metadata/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini +++ b/tests/wpt/metadata/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini @@ -2,3 +2,6 @@ [listeners are called when <iframe> is resized] expected: FAIL + [listeners are called correct number of times] + expected: FAIL + diff --git a/tests/wpt/metadata/css/cssom-view/elementFromPosition.html.ini b/tests/wpt/metadata/css/cssom-view/elementFromPosition.html.ini index 5733d536fd3..85e94926cb3 100644 --- a/tests/wpt/metadata/css/cssom-view/elementFromPosition.html.ini +++ b/tests/wpt/metadata/css/cssom-view/elementFromPosition.html.ini @@ -21,6 +21,3 @@ [test the top of layer] expected: FAIL - [test some point of the element: top left corner] - expected: FAIL - diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini index bb8ba7c6ad9..0af08ed6710 100644 --- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini @@ -312,18 +312,9 @@ [fetch(): separate response Content-Type: text/plain ] expected: NOTRUN - [<iframe>: combined response Content-Type: text/html */*;charset=gbk] - expected: FAIL - - [<iframe>: combined response Content-Type: text/html */*] - expected: FAIL - - [<iframe>: combined response Content-Type: text/html;" text/plain] - expected: FAIL - - [<iframe>: separate response Content-Type: text/html */*;charset=gbk] + [<iframe>: separate response Content-Type: text/html;" \\" text/plain] expected: FAIL - [<iframe>: separate response Content-Type: text/html;" \\" text/plain] + [<iframe>: separate response Content-Type: text/html;" text/plain] expected: FAIL diff --git a/tests/wpt/metadata/fetch/content-type/script.window.js.ini b/tests/wpt/metadata/fetch/content-type/script.window.js.ini index 279734168dc..a1ec6ff3aa3 100644 --- a/tests/wpt/metadata/fetch/content-type/script.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/script.window.js.ini @@ -53,9 +53,9 @@ [combined text/javascript ] expected: FAIL - [separate text/javascript x/x] + [separate text/javascript;charset=windows-1252 text/javascript] expected: FAIL - [separate text/javascript;charset=windows-1252 text/javascript] + [separate text/javascript error] expected: FAIL diff --git a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini index 61682d248e2..369bf4d4fa4 100644 --- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,6 +11,6 @@ [X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!] expected: FAIL - [X-Content-Type-Options%3A%20%40%23%24%23%25%25%26%5E%26%5E*()()11!%2Cnosniff] + [Content-Type-Options%3A%20nosniff] expected: FAIL diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini new file mode 100644 index 00000000000..87b07c3e670 --- /dev/null +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini @@ -0,0 +1,4 @@ +[traverse_the_history_1.html] + [Multiple history traversals from the same task] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini deleted file mode 100644 index 385376c7321..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_4.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini index 51f8272a6de..dc2e45516de 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini @@ -1,4 +1,4 @@ -[traverse_the_history_3.html] +[traverse_the_history_5.html] [Multiple history traversals, last would be aborted] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini index e440b1e38c6..71edac2c5ed 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini @@ -1,6 +1,6 @@ [iframe_sandbox_popups_nonescaping-3.html] type: testharness - expected: TIMEOUT + expected: CRASH [Check that popups from a sandboxed iframe do not escape the sandbox] expected: NOTRUN diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini index 66bd350083b..a56bad443a2 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html.ini @@ -1,4 +1,5 @@ [realtimeanalyser-fft-scaling.html] + expected: TIMEOUT [X 2048-point FFT peak position is not equal to 64. Got 0.] expected: FAIL diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini index f1db5900b81..601831e0fda 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html.ini @@ -23,3 +23,6 @@ [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44048 more errors.\n\tMax AbsError of 1.9986916780471802e+0 at index of 29020.\n\t[29020\]\t9.9994289875030518e-1\t-9.9874877929687500e-1\t1.9986916780471802e+0\t2.0011956154322119e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 10584.\n\t[10584\]\t-5.8778524398803711e-1\t0.0000000000000000e+0\t5.8778524398803711e-1\tInfinity\t3.0517578125000000e-5\n] expected: FAIL + [X Rendered audio for channel 5 does not equal [0,0.0626220703125,0.125030517578125,0.18695068359375,0.24810791015625,0.308319091796875,0.3673095703125,0.42486572265625,0.480743408203125,0.53472900390625,0.58660888671875,0.636199951171875,0.68328857421875,0.727691650390625,0.76922607421875,0.8077392578125...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t3.6732959747314453e-1\t6.2622070312500000e-2\t3.0470752716064453e-1\t4.8658168859649127e+0\t3.0517578125000000e-5\n\t[2\]\t6.8329977989196777e-1\t1.2503051757812500e-1\t5.5826926231384277e-1\t4.4650639949963384e+0\t3.0517578125000000e-5\n\t[3\]\t9.0373212099075317e-1\t1.8695068359375000e-1\t7.1678143739700317e-1\t3.8340669508039502e+0\t3.0517578125000000e-5\n\t[4\]\t9.9780619144439697e-1\t2.4810791015625000e-1\t7.4969828128814697e-1\t3.0216621502152523e+0\t3.0517578125000000e-5\n\t[5\]\t9.5236867666244507e-1\t3.0831909179687500e-1\t6.4404958486557007e-1\t2.0889059484187866e+0\t3.0517578125000000e-5\n\t...and 44056 more errors.\n\tMax AbsError of 1.9999977350234985e+0 at index of 10361.\n\t[10361\]\t9.9999773502349854e-1\t-1.0000000000000000e+0\t1.9999977350234985e+0\t1.9999977350234985e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 7056.\n\t[7056\]\t5.8778524398803711e-1\t0.0000000000000000e+0\t5.8778524398803711e-1\tInfinity\t3.0517578125000000e-5\n] + expected: FAIL + diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini index 06f0da3d734..05e13f78c22 100644 --- a/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html.ini @@ -152,3 +152,9 @@ [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[19030\]\t-6.4853054482227890e-8\t-7.3546999692916870e-1\t7.3546993207611422e-1\t9.9999991182093795e-1\t3.8985999999999999e-3\n\t[19031\]\t-3.6017334461212158e-1\t-6.9157749414443970e-1\t3.3140414953231812e-1\t4.7920030992665957e-1\t3.8985999999999999e-3\n\t[38059\]\t-1.5015864107681409e-7\t-9.8956179618835449e-1\t9.8956164602971342e-1\t9.9999984825743915e-1\t3.8985999999999999e-3\n\t[38060\]\t-8.8409073650836945e-2\t-9.9664616584777832e-1\t9.0823709219694138e-1\t9.1129341918891205e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.8956164602971342e-1 at index of 38059.\n\tMax RelError of 9.9999991182093795e-1 at index of 19030.\n] expected: FAIL + [X SNR (39.5689338967812 dB) is not greater than or equal to 65.737. Got 39.5689338967812.] + 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[19030\]\t-4.2493608780205250e-3\t-7.3546999692916870e-1\t7.3122063605114818e-1\t9.9422225121927066e-1\t3.8985999999999999e-3\n\t[19031\]\t-3.6017334461212158e-1\t-6.9157749414443970e-1\t3.3140414953231812e-1\t4.7920030992665957e-1\t3.8985999999999999e-3\n\t[38059\]\t-9.8401503637433052e-3\t-9.8956179618835449e-1\t9.7972164582461119e-1\t9.9005605268751673e-1\t3.8985999999999999e-3\n\t[38060\]\t-8.8409073650836945e-2\t-9.9664616584777832e-1\t9.0823709219694138e-1\t9.1129341918891205e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.7972164582461119e-1 at index of 38059.\n\tMax RelError of 9.9422225121927066e-1 at index of 19030.\n] + expected: FAIL + diff --git a/tests/wpt/metadata/webmessaging/with-ports/017.html.ini b/tests/wpt/metadata/webmessaging/without-ports/017.html.ini index 064cf47545b..064cf47545b 100644 --- a/tests/wpt/metadata/webmessaging/with-ports/017.html.ini +++ b/tests/wpt/metadata/webmessaging/without-ports/017.html.ini diff --git a/tests/wpt/metadata/webmessaging/without-ports/018.html.ini b/tests/wpt/metadata/webmessaging/without-ports/018.html.ini deleted file mode 100644 index 663a1f8fa30..00000000000 --- a/tests/wpt/metadata/webmessaging/without-ports/018.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[018.html] - expected: TIMEOUT - [origin of the script that invoked the method, javascript:] - expected: TIMEOUT - diff --git a/tests/wpt/web-platform-tests/beacon/beacon-common.sub.js b/tests/wpt/web-platform-tests/beacon/beacon-common.sub.js index ae2f169f272..3635da73b75 100644 --- a/tests/wpt/web-platform-tests/beacon/beacon-common.sub.js +++ b/tests/wpt/web-platform-tests/beacon/beacon-common.sub.js @@ -16,33 +16,33 @@ var largePayload = largePayloadSize + ":" + Array(largePayloadSize).fill('*').jo var maxPayload = (maxPayloadSize - 6) + ":" + Array(maxPayloadSize - 6).fill('*').join("") // Test case definitions. -// id: String containing the unique name of the test case. +// name: String containing the unique name of the test case. // data: Payload object to send through sendbeacon. -var noDataTest = { id: "NoData" }; -var nullDataTest = { id: "NullData", data: null }; -var undefinedDataTest = { id: "UndefinedData", data: undefined }; -var smallStringTest = { id: "SmallString", data: smallPayload }; -var mediumStringTest = { id: "MediumString", data: mediumPayload }; -var largeStringTest = { id: "LargeString", data: largePayload }; -var maxStringTest = { id: "MaxString", data: maxPayload }; -var emptyBlobTest = { id: "EmptyBlob", data: new Blob() }; -var smallBlobTest = { id: "SmallBlob", data: new Blob([smallPayload]) }; -var mediumBlobTest = { id: "MediumBlob", data: new Blob([mediumPayload]) }; -var largeBlobTest = { id: "LargeBlob", data: new Blob([largePayload]) }; -var maxBlobTest = { id: "MaxBlob", data: new Blob([maxPayload]) }; -var emptyBufferSourceTest = { id: "EmptyBufferSource", data: new Uint8Array() }; -var smallBufferSourceTest = { id: "SmallBufferSource", data: CreateArrayBufferFromPayload(smallPayload) }; -var mediumBufferSourceTest = { id: "MediumBufferSource", data: CreateArrayBufferFromPayload(mediumPayload) }; -var largeBufferSourceTest = { id: "LargeBufferSource", data: CreateArrayBufferFromPayload(largePayload) }; -var maxBufferSourceTest = { id: "MaxBufferSource", data: CreateArrayBufferFromPayload(maxPayload) }; -var emptyFormDataTest = { id: "EmptyFormData", data: CreateEmptyFormDataPayload() }; -var smallFormDataTest = { id: "SmallFormData", data: CreateFormDataFromPayload(smallPayload) }; -var mediumFormDataTest = { id: "MediumFormData", data: CreateFormDataFromPayload(mediumPayload) }; -var largeFormDataTest = { id: "LargeFormData", data: CreateFormDataFromPayload(largePayload) }; -var smallSafeContentTypeEncodedTest = { id: "SmallSafeContentTypeEncoded", data: new Blob([smallPayload], { type: 'application/x-www-form-urlencoded' }) }; -var smallSafeContentTypeFormTest = { id: "SmallSafeContentTypeForm", data: new FormData() }; -var smallSafeContentTypeTextTest = { id: "SmallSafeContentTypeText", data: new Blob([smallPayload], { type: 'text/plain' }) }; -var smallCORSContentTypeTextTest = { id: "SmallCORSContentTypeText", data: new Blob([smallPayload], { type: 'text/html' }) }; +var noDataTest = { name: "NoData" }; +var nullDataTest = { name: "NullData", data: null }; +var undefinedDataTest = { name: "UndefinedData", data: undefined }; +var smallStringTest = { name: "SmallString", data: smallPayload }; +var mediumStringTest = { name: "MediumString", data: mediumPayload }; +var largeStringTest = { name: "LargeString", data: largePayload }; +var maxStringTest = { name: "MaxString", data: maxPayload }; +var emptyBlobTest = { name: "EmptyBlob", data: new Blob() }; +var smallBlobTest = { name: "SmallBlob", data: new Blob([smallPayload]) }; +var mediumBlobTest = { name: "MediumBlob", data: new Blob([mediumPayload]) }; +var largeBlobTest = { name: "LargeBlob", data: new Blob([largePayload]) }; +var maxBlobTest = { name: "MaxBlob", data: new Blob([maxPayload]) }; +var emptyBufferSourceTest = { name: "EmptyBufferSource", data: new Uint8Array() }; +var smallBufferSourceTest = { name: "SmallBufferSource", data: CreateArrayBufferFromPayload(smallPayload) }; +var mediumBufferSourceTest = { name: "MediumBufferSource", data: CreateArrayBufferFromPayload(mediumPayload) }; +var largeBufferSourceTest = { name: "LargeBufferSource", data: CreateArrayBufferFromPayload(largePayload) }; +var maxBufferSourceTest = { name: "MaxBufferSource", data: CreateArrayBufferFromPayload(maxPayload) }; +var emptyFormDataTest = { name: "EmptyFormData", data: CreateEmptyFormDataPayload() }; +var smallFormDataTest = { name: "SmallFormData", data: CreateFormDataFromPayload(smallPayload) }; +var mediumFormDataTest = { name: "MediumFormData", data: CreateFormDataFromPayload(mediumPayload) }; +var largeFormDataTest = { name: "LargeFormData", data: CreateFormDataFromPayload(largePayload) }; +var smallSafeContentTypeEncodedTest = { name: "SmallSafeContentTypeEncoded", data: new Blob([smallPayload], { type: 'application/x-www-form-urlencoded' }) }; +var smallSafeContentTypeFormTest = { name: "SmallSafeContentTypeForm", data: new FormData() }; +var smallSafeContentTypeTextTest = { name: "SmallSafeContentTypeText", data: new Blob([smallPayload], { type: 'text/plain' }) }; +var smallCORSContentTypeTextTest = { name: "SmallCORSContentTypeText", data: new Blob([smallPayload], { type: 'text/html' }) }; // We don't test maxFormData because the extra multipart separators make it difficult to // calculate a maxPayload. @@ -66,13 +66,6 @@ var sampleTests = [noDataTest, nullDataTest, undefinedDataTest, smallStringTest, var preflightTests = [smallCORSContentTypeTextTest]; -// Build a test lookup table, which is useful when instructing a web worker or an iframe -// to run a test, so that we don't have to marshal the entire test case across a process boundary. -var testLookup = {}; -allTests.forEach(function(testCase) { - testLookup[testCase.id] = testCase; -}); - // Helper function to create an ArrayBuffer representation of a string. function CreateArrayBufferFromPayload(payload) { var length = payload.length; @@ -105,76 +98,27 @@ function CreateFormDataFromPayload(payload) { return formData; } -// Initializes a session with a client-generated SID. -// A "session" is a run of one or more tests. It is used to batch several beacon -// tests in a way that isolates the server-side session state and makes it easy -// to poll the results of the tests in one request. -// testCases: The array of test cases participating in the session. -function initSession(testCases) { - return { - // Provides a unique session identifier to prevent mixing server-side data - // with other sessions. - id: self.token(), - // Dictionary of test name to live testCase object. - testCaseLookup: {}, - // Array of testCase objects for iteration. - testCases: [], - // Tracks the total number of tests in the session. - totalCount: testCases.length, - // Tracks the number of tests for which we have sent the beacon. - // When it reaches totalCount, we will start polling for results. - sentCount: 0, - // Tracks the number of tests for which we have verified the results. - // When it reaches sentCount, we will stop polling for results. - doneCount: 0, - // Helper to add a testCase to the session. - add: function add(testCase) { - this.testCases.push(testCase); - this.testCaseLookup[testCase.id] = testCase; - } - }; -} - // Schedules async_test's for each of the test cases, treating them as a single session, // and wires up the continueAfterSendingBeacon() and waitForResults() calls. -// The method looks for several "extension" functions in the global scope: -// - self.buildBaseUrl: if present, can change the base URL of a beacon target URL (this -// is the scheme, hostname, and port). -// - self.buildTargetUrl: if present, can modify a beacon target URL (for example wrap it). // Parameters: // testCases: An array of test cases. -// sendData [optional]: A function that sends the beacon. -function runTests(testCases, sendData = self.sendData) { - const session = initSession(testCases); - - testCases.forEach(function(testCase, testIndex) { - // Make a copy of the test case as we'll be storing some metadata on it, - // such as which session it belongs to. - const testCaseCopy = Object.assign({ session: session }, testCase); - - testCaseCopy.index = testIndex; - +// suffix [optional]: A string used for the suffix for each test case name. +// buildUrl [optional]: A function that returns a beacon URL given an id. +// sendData [optional]: A function that sends the beacon with given a URL and payload. +function runTests(testCases, suffix = '', buildUrl = self.buildUrl, sendData = self.sendData) { + for (const testCase of testCases) { + const id = token(); async_test((test) => { - // Save the testharness.js 'test' object, so that we only have one object - // to pass around. - testCaseCopy.test = test; - - // Extension point: generate the beacon URL. - var baseUrl = "http://{{host}}:{{ports[http][0]}}"; - if (self.buildBaseUrl) { - baseUrl = self.buildBaseUrl(baseUrl); - } - var targetUrl = `${baseUrl}/beacon/resources/beacon.py?cmd=store&sid=${session.id}&tid=${testCaseCopy.id}&tidx=${testIndex}`; - if (self.buildTargetUrl) { - targetUrl = self.buildTargetUrl(targetUrl); - } - // Attach the URL to the test object for debugging purposes. - testCaseCopy.url = targetUrl; - - assert_true(sendData(testCaseCopy), 'sendBeacon should succeed'); - waitForResult(testCaseCopy).then(() => test.done(), test.step_func((e) => {throw e;})); - }, `Verify 'navigator.sendbeacon()' successfully sends for variant: ${testCaseCopy.id}`); - }); + const url = buildUrl(id); + assert_true(sendData(url, testCase.data), 'sendBeacon should succeed'); + waitForResult(id).then(() => test.done(), test.step_func((e) => {throw e;})); + }, `Verify 'navigator.sendbeacon()' successfully sends for variant: ${testCase.name}${suffix}`); + }; +} + +function buildUrl(id) { + const baseUrl = "http://{{host}}:{{ports[http][0]}}"; + return `${baseUrl}/beacon/resources/beacon.py?cmd=store&id=${id}`; } // Sends the beacon for a single test. This step is factored into its own function so that @@ -183,15 +127,13 @@ function runTests(testCases, sendData = self.sendData) { // full testharness.js test context. Instead return 'false', and the main scope will fail // the test. // Returns the result of the 'sendbeacon()' function call, true or false. -function sendData(testCase) { - return self.navigator.sendBeacon(testCase.url, testCase.data); +function sendData(url, payload) { + return self.navigator.sendBeacon(url, payload); } // Poll the server for the test result. -async function waitForResult(testCase) { - const session = testCase.session; - const index = testCase.index; - const url = `resources/beacon.py?cmd=stat&sid=${session.id}&tidx_min=${index}&tidx_max=${index}`; +async function waitForResult(id) { + const url = `resources/beacon.py?cmd=stat&id=${id}`; for (let i = 0; i < 30; ++i) { const response = await fetch(url); const text = await response.text(); @@ -218,16 +160,10 @@ function runSendInIframeAndNavigateTests() { iframe.onload = function() { // Clear our onload handler to prevent re-running the tests as we navigate away. iframe.onload = null; - function sendData(testCase) { - return iframe.contentWindow.navigator.sendBeacon(testCase.url, testCase.data); - } - const tests = []; - for (const test of sampleTests) { - const copy = Object.assign({}, test); - copy.id = `${test.id}-NAVIGATE`; - tests.push(copy); + function sendData(url, payload) { + return iframe.contentWindow.navigator.sendBeacon(url, payload); } - runTests(tests, sendData); + runTests(sampleTests, '-NAVIGATE', self.buildUrl, sendData); // Now navigate ourselves. iframe.contentWindow.location = "http://{{host}}:{{ports[http][0]}}/"; }; diff --git a/tests/wpt/web-platform-tests/beacon/beacon-cors.sub.window.js b/tests/wpt/web-platform-tests/beacon/beacon-cors.sub.window.js index 4a8e4dfbc65..5543bddc5f6 100644 --- a/tests/wpt/web-platform-tests/beacon/beacon-cors.sub.window.js +++ b/tests/wpt/web-platform-tests/beacon/beacon-cors.sub.window.js @@ -8,15 +8,8 @@ // the beacon handler will return CORS headers. This test ensures that the // sendBeacon() succeeds in either case. [true, false].forEach(function(allowCors) { - // Implement the self.buildBaseUrl and self.buildTargetUrl extensions - // to change the target URL to use a cross-origin domain name. - self.buildBaseUrl = function(baseUrl) { - return "http://{{domains[www]}}:{{ports[http][0]}}"; - }; - // Implement the self.buildTargetUrl extension to append a directive - // to the handler, that it should return CORS headers, if 'allowCors' - // is true. - self.buildTargetUrl = function(targetUrl) { + function buildUrl(id) { + const baseUrl = "http://{{domains[www]}}:{{ports[http][0]}}"; // Note that 'allowCors=true' is not necessary for the sendBeacon() to reach // the server. Beacons use the HTTP POST method, which is a CORS-safelisted // method, and thus they do not trigger preflight. If the server does not @@ -27,16 +20,10 @@ // value of the sendBeacon() call, because the underlying fetch is asynchronous. // The "Beacon CORS" tests are merely testing that sendBeacon() to a cross- // origin URL *will* work regardless. - return allowCors ? `${targetUrl}&origin=http://{{host}}:{{ports[http][0]}}&credentials=true` : targetUrl; + const additionalQuery = allowCors ? "&origin=http://{{host}}:{{ports[http][0]}}&credentials=true" : ""; + return `${baseUrl}/beacon/resources/beacon.py?cmd=store&id=${id}${additionalQuery}` } - - const tests = []; - for (const test of sampleTests) { - const copy = Object.assign({}, test); - copy.id = `${test.id}-${allowCors ? "CORS-ALLOW" : "CORS-FORBID"}`; - tests.push(copy); - } - runTests(tests); + runTests(sampleTests, allowCors ? "-CORS-ALLOW" : "-CORS-FORBID", buildUrl); }); // Now test a cross-origin request that doesn't use a safelisted Content-Type and ensure @@ -44,24 +31,12 @@ // header is used there should be a preflight/options request and we should only succeed // send the payload if the proper CORS headers are used. { - // Implement the self.buildBaseUrl and self.buildTargetUrl extensions - // to change the target URL to use a cross-origin domain name. - self.buildBaseUrl = function (baseUrl) { - return "http://{{domains[www]}}:{{ports[http][0]}}"; - }; - - // Implement the self.buildTargetUrl extension to append a directive - // to the handler, that it should return CORS headers for the preflight we expect. - self.buildTargetUrl = function (targetUrl) { - return `${targetUrl}&origin=http://{{host}}:{{ports[http][0]}}&credentials=true&preflightExpected=true`; - } - const tests = []; - for (const test of preflightTests) { - const copy = Object.assign({}, test); - copy.id = `${test.id}-PREFLIGHT-ALLOW`; - tests.push(copy); + function buildUrl(id) { + const baseUrl = "http://{{domains[www]}}:{{ports[http][0]}}"; + const additionalQuery = "&origin=http://{{host}}:{{ports[http][0]}}&credentials=true&preflightExpected=true"; + return `${baseUrl}/beacon/resources/beacon.py?cmd=store&id=${id}${additionalQuery}` } - runTests(tests); + runTests(preflightTests, "-PREFLIGHT-ALLOW", buildUrl); } done(); diff --git a/tests/wpt/web-platform-tests/beacon/beacon-preflight-failure.sub.window.js b/tests/wpt/web-platform-tests/beacon/beacon-preflight-failure.sub.window.js index 27e6905a9bd..c5a2d813f17 100644 --- a/tests/wpt/web-platform-tests/beacon/beacon-preflight-failure.sub.window.js +++ b/tests/wpt/web-platform-tests/beacon/beacon-preflight-failure.sub.window.js @@ -2,13 +2,10 @@ // META: script=/common/get-host-info.sub.js promise_test(async (test) => { - const sid = token(); - const tid = token(); const origin = get_host_info().REMOTE_ORIGIN; - const store = - `${origin}/beacon/resources/beacon.py?cmd=store&sid=${sid}&tid=${tid}&tidx=0`; - const monitor = - `/beacon/resources/beacon.py?cmd=stat&sid=${sid}&tidx_min=0&tidx_max=0`; + const id = token(); + const store = `${origin}/beacon/resources/beacon.py?cmd=store&id=${id}`; + const monitor = `/beacon/resources/beacon.py?cmd=stat&id=${id}`; assert_true(navigator.sendBeacon(store, new Blob([], {type: 'x/y'}))); @@ -25,7 +22,7 @@ promise_test(async (test) => { } const expected = - JSON.stringify([{id: tid, error: 'Preflight not expected.'}]); + JSON.stringify([{error: 'Preflight not expected.'}]); assert_equals(actual, expected); }); diff --git a/tests/wpt/web-platform-tests/beacon/beacon-redirect.window.js b/tests/wpt/web-platform-tests/beacon/beacon-redirect.sub.window.js index 3a8aef3c742..fd23a45f86b 100644 --- a/tests/wpt/web-platform-tests/beacon/beacon-redirect.window.js +++ b/tests/wpt/web-platform-tests/beacon/beacon-redirect.sub.window.js @@ -8,18 +8,13 @@ // Note that status codes 307 and 308 are the only codes that will maintain POST data // through a redirect. [307, 308].forEach(function(status) { - // Implement the self.buildTargetUrl extension to inject a redirect to - // the sendBeacon target. - self.buildTargetUrl = function(targetUrl) { + function buildUrl(id) { + const baseUrl = "http://{{host}}:{{ports[http][0]}}"; + const targetUrl = `${baseUrl}/beacon/resources/beacon.py?cmd=store&id=${id}`; + return `/common/redirect.py?status=${status}&location=${encodeURIComponent(targetUrl)}`; - }; - const tests = []; - for (const test of sampleTests) { - const copy = Object.assign({}, test); - copy.id = `${test.id}-${status}`; - tests.push(copy); } - runTests(tests); + runTests(sampleTests, `-${status}`, buildUrl); }); done(); diff --git a/tests/wpt/web-platform-tests/beacon/resources/beacon.py b/tests/wpt/web-platform-tests/beacon/resources/beacon.py index 5f2553d3c4d..34b55b1a95b 100644 --- a/tests/wpt/web-platform-tests/beacon/resources/beacon.py +++ b/tests/wpt/web-platform-tests/beacon/resources/beacon.py @@ -1,7 +1,5 @@ import json -def build_stash_key(session_id, test_num): - return "%s_%s" % (session_id, test_num) def main(request, response): """Helper handler for Beacon tests. @@ -9,63 +7,50 @@ def main(request, response): It handles two forms of requests: STORE: - A URL with a query string of the form 'cmd=store&sid=<token>&tidx=<test_index>&tid=<test_name>'. + A URL with a query string of the form 'cmd=store&id=<token>'. - Stores the receipt of a sendBeacon() request along with its validation result, returning HTTP 200 OK. + Stores the receipt of a sendBeacon() request along with its validation + result, returning HTTP 200 OK. - Parameters: - tidx - the integer index of the test. - tid - a friendly identifier or name for the test, used when returning results. + if "preflightExpected" exists in the query, this handler responds to + CORS preflights. STAT: - A URL with a query string of the form 'cmd=stat&sid=<token>&tidx_min=<min_test_index>&tidx_max=<max_test_index>'. + A URL with a query string of the form 'cmd=stat&id=<token>'. - Retrieves the results of test with indices [min_test_index, max_test_index] and returns them as - a JSON array and HTTP 200 OK status code. Due to the eventual read-once nature of the stash, results for a given test - are only guaranteed to be returned once, though they may be returned multiple times. + Retrieves the results of test for the given id and returns them as a + JSON array and HTTP 200 OK status code. Due to the eventual read-once + nature of the stash, results for a given test are only guaranteed to be + returned once, though they may be returned multiple times. - Parameters: - tidx_min - the lower-bounding integer test index. - tidx_max - the upper-bounding integer test index. - - Example response body: - [{"id": "Test1", error: null}, {"id": "Test2", error: "some validation details"}] + Example response bodies: + - [{error: null}] + - [{error: "some validation details"}] + - [] Common parameters: cmd - the command, 'store' or 'stat'. - sid - session id used to provide isolation to a test run comprising multiple sendBeacon() - tests. + id - the unique identifier of the test. """ - session_id = request.GET.first("sid"); - command = request.GET.first("cmd").lower(); - - # Workaround to circumvent the limitation that cache keys - # can only be UUID's. - def wrap_key(key, path): - return (str(path), str(key)) - request.server.stash._wrap_key = wrap_key + id = request.GET.first("id") + command = request.GET.first("cmd").lower() # Append CORS headers if needed. if "origin" in request.GET: - response.headers.set("Access-Control-Allow-Origin", request.GET.first("origin")) + response.headers.set("Access-Control-Allow-Origin", + request.GET.first("origin")) if "credentials" in request.GET: - response.headers.set("Access-Control-Allow-Credentials", request.GET.first("credentials")) + response.headers.set("Access-Control-Allow-Credentials", + request.GET.first("credentials")) # Handle the 'store' and 'stat' commands. if command == "store": - # The test id is just used to make the results more human-readable. - test_id = request.GET.first("tid") - # The test index is used to build a predictable stash key, together - # with the unique session id, in order to retrieve a range of results - # later knowing the index range. - test_idx = request.GET.first("tidx") - test_data = { "id": test_id, "error": None } - - # Only store the actual POST requests, not any preflight/OPTIONS requests we may get. - if request.method == "POST": - test_data_key = build_stash_key(session_id, test_idx) + error = None + # Only store the actual POST requests, not any preflight/OPTIONS + # requests we may get. + if request.method == "POST": payload = "" if "Content-Type" in request.headers and \ "form-data" in request.headers["Content-Type"]: @@ -83,42 +68,38 @@ def main(request, response): if len(payload_parts) > 0: payload_size = int(payload_parts[0]) - # Confirm the payload size sent matches with the number of characters sent. + # Confirm the payload size sent matches with the number of + # characters sent. if payload_size != len(payload_parts[1]): - test_data["error"] = "expected %d characters but got %d" % (payload_size, len(payload_parts[1])) + error = "expected %d characters but got %d" % ( + payload_size, len(payload_parts[1])) else: # Confirm the payload contains the correct characters. for i in range(0, payload_size): if payload_parts[1][i] != "*": - test_data["error"] = "expected '*' at index %d but got '%s''" % (i, payload_parts[1][i]) + error = "expected '*' at index %d but got '%s''" % ( + i, payload_parts[1][i]) break # Store the result in the stash so that it can be retrieved # later with a 'stat' command. - request.server.stash.put(test_data_key, test_data) + request.server.stash.put(id, {"error": error}) elif request.method == "OPTIONS": - # If we expect a preflight, then add the cors headers we expect, otherwise log an error as we shouldn't - # send a preflight for all requests. + # If we expect a preflight, then add the cors headers we expect, + # otherwise log an error as we shouldn't send a preflight for all + # requests. if "preflightExpected" in request.GET: - response.headers.set("Access-Control-Allow-Headers", "content-type") + response.headers.set("Access-Control-Allow-Headers", + "content-type") response.headers.set("Access-Control-Allow-Methods", "POST") else: - test_data_key = build_stash_key(session_id, test_idx) - test_data["error"] = "Preflight not expected." - request.server.stash.put(test_data_key, test_data) + error = "Preflight not expected." + request.server.stash.put(id, {"error": error}) elif command == "stat": - test_idx_min = int(request.GET.first("tidx_min")) - test_idx_max = int(request.GET.first("tidx_max")) - - # For each result that has come in, append it to the response. - results = [] - for test_idx in range(test_idx_min, test_idx_max+1): # +1 because end is exclusive - test_data_key = build_stash_key(session_id, test_idx) - test_data = request.server.stash.take(test_data_key) - if test_data: - results.append(test_data) + test_data = request.server.stash.take(id) + results = [test_data] if test_data else [] response.headers.set("Content-Type", "text/plain") response.content = json.dumps(results) else: - response.status = 400 # BadRequest
\ No newline at end of file + response.status = 400 # BadRequest diff --git a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/none.https.html b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/none.https.html index e603753084c..54852596835 100644 --- a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/none.https.html +++ b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/none.https.html @@ -84,6 +84,8 @@ async_test(t => { assert_equals(win, null); }, `"require-corp" top-level noopener popup: navigating to "none" should succeed`); +// CORP is checked because COEP of the frame is "require-corp". The parent +// frame's COEP value doesn't matter. async_test(t => { const frame = document.createElement("iframe"); const id = token(); @@ -94,8 +96,33 @@ async_test(t => { t.done(); } })); - frame.src = `${HOST.HTTPS_NOTSAMESITE_ORIGIN}${BASE}/navigate-require-corp-same-site.sub.html?token=${id}`; + // REMOTE_ORIGIN is cross-origin, same-site. + frame.src = `${HOST.HTTPS_REMOTE_ORIGIN}${BASE}/navigate-require-corp-same-site.sub.html?token=${id}`; document.body.append(frame); -}, 'CORP: same-site is not checked.'); +}, 'CORP: same-site is checked and allowed.'); + +// CORP is checked because COEP of the frame is "require-corp". The parent +// frame's COEP value doesn't matter. +async_test(t => { + const frame = document.createElement("iframe"); + const id = token(); + t.add_cleanup(() => frame.remove()); + let loaded = false; + window.addEventListener('message', t.step_func((e) => { + if (e.data === id) { + loaded = true; + } + })); + t.step_timeout(() => { + // Make sure the iframe didn't load. See https://github.com/whatwg/html/issues/125 for why a + // timeout is used here. Long term all network error handling should be similar and have a + // reliable event. + assert_false(loaded); + t.done(); + }, 2000); + // NOTESAMESITE_ORIGIN is cross-origin, cross-site. + frame.src = `${HOST.HTTPS_NOTSAMESITE_ORIGIN}${BASE}/navigate-require-corp-same-site.sub.html?token=${id}`; + document.body.append(frame); +}, 'CORP: same-site is checked and blocked.'); </script> diff --git a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/resources/postback.html.headers b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/resources/postback.html.headers index 6604450991a..4e798cd9f5d 100644 --- a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/resources/postback.html.headers +++ b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/resources/postback.html.headers @@ -1 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: cross-origin diff --git a/tests/wpt/web-platform-tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers b/tests/wpt/web-platform-tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers index 6604450991a..4e798cd9f5d 100644 --- a/tests/wpt/web-platform-tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers +++ b/tests/wpt/web-platform-tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers @@ -1 +1,2 @@ Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: cross-origin diff --git a/tests/wpt/web-platform-tests/std-toast/META.yml b/tests/wpt/web-platform-tests/std-toast/META.yml deleted file mode 100644 index c54357a03f2..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/META.yml +++ /dev/null @@ -1,5 +0,0 @@ -spec: https://github.com/jackbsteinberg/std-toast -suggested_reviewers: - - domenic - - fergald - - jackbsteinberg diff --git a/tests/wpt/web-platform-tests/std-toast/actions.html b/tests/wpt/web-platform-tests/std-toast/actions.html deleted file mode 100644 index 6a80def0998..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/actions.html +++ /dev/null @@ -1,190 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: action tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> - -<script type="module"> -import { testActionToast, testToastElement, assertActionButtonOnToast } from './resources/helpers.js'; -import { showToast } from 'std:elements/toast'; - -testActionToast((toast) => { - assert_equals(toast.action.textContent, 'action'); -}, 'the action element gets properly captured with this.action'); - -testActionToast((toast) => { - toast.innerHTML = `<button slot='action'>new action</button>` - assert_equals(toast.action.textContent, 'new action'); -}, 'changing the action button changes this.action'); - -testToastElement((toast) => { - assert_equals(toast.action, null); -}, 'the action property of a toast without an action is null'); - -testToastElement((toast) => { - toast.innerHTML = `<button slot="action" id="first">first</button> - <button slot="action" id="second">second</button>`; - - assert_equals(toast.action, toast.querySelector('#first')); -}, 'toast action returns the first item with the action slot'); - -test(() => { - const toast = showToast('Message', {action: 'action'}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); -}, 'passing an action via showToast creates a button'); - -test(() => { - const actionMarkup = '<b>strong text</b>'; - const toast = showToast('Message', {action: actionMarkup}); - const actionButton = toast.querySelector('button'); - - assert_equals(actionButton.textContent, actionMarkup); - assert_equals(toast.querySelector('b'), null); -}, 'passing markup to the action option represents as text'); - -test(() => { - const toast = document.createElement('std-toast'); - toast.textContent = 'Message'; - toast.show({action: 'action'}); - const actionButton = toast.querySelector('button'); - - assert_equals(actionButton, null); -}, 'passing action option to show does not create a button'); - -test(() => { - const toast = showToast('Message', {action: null}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); - assert_equals(actionButton.textContent, 'null'); -}, 'passing non-string (null) as action option stringifies it and creates an action button'); - -test(() => { - const toast = showToast('Message', {action: false}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); - assert_equals(actionButton.textContent, 'false'); -}, 'passing non-string (false) as action option stringifies it and creates an action button'); - -test(() => { - const toast = showToast('Message', {action: 0}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); - assert_equals(actionButton.textContent, '0'); -}, 'passing non-string (0) as action option stringifies it and creates an action button'); - -test(() => { - const toast = showToast('Message', {action: 1}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); - assert_equals(actionButton.textContent, '1'); -}, 'passing non-string (1) as action option stringifies it and creates an action button'); - -test(() => { - const toast = showToast('Message', {action: {field: 'value'}}); - const actionButton = toast.querySelector('button'); - - assertActionButtonOnToast(actionButton, toast); - assert_equals(actionButton.textContent, '[object Object]'); -}, 'passing non-string ({field: value}) as action option stringifies it and creates an action button'); - -test(() => { - const toast = showToast('Message', {}); - const actionButton = toast.querySelector('button'); - - assert_equals(actionButton, null); -}, 'passing non-string (undefined) as action option does not create an action button'); - -testToastElement((toast) => { - const actionButton = document.createElement('button'); - actionButton.textContent = 'action'; - toast.action = actionButton; - - assertActionButtonOnToast(actionButton, toast); -}, 'setting the action on an actionless toast inserts the element into the slot'); - -testActionToast((toast, action) => { - const actionButton = document.createElement('button'); - actionButton.textContent = 'replacement'; - toast.action = actionButton; - - assert_false(document.contains(action)); - assertActionButtonOnToast(actionButton, toast); -}, 'resetting the action on an action toast changes the action element'); - -testToastElement((toast) => { - const text = document.createTextNode('some text'); - assert_throws_js(TypeError, () => { - toast.action = text; - }); -}, 'setting the action to an invalid type (Text node) throws an error'); - -testToastElement((toast) => { - const text = 'some text'; - assert_throws_js(TypeError, () => { - toast.action = text; - }); -}, 'setting the action to an invalid type (string) throws an error'); - -test(() => { - const actionButton = document.createElement('button'); - actionButton.textContent = 'action'; - const toast = showToast('Message', {action: actionButton}); - - assertActionButtonOnToast(actionButton, toast); -}, 'showToast can take an Element as the action parameter'); - -testActionToast((toast, action) => { - toast.action = null; - - assert_not_equals(toast.action, action); - assert_equals(toast.querySelector('button'), null); -}, 'setting toast.action to null removes the action from the toast'); - -testActionToast((toast, action) => { - const wrongAction = document.createElement('button'); - wrongAction.textContent = 'wrong'; - wrongAction.setAttribute('slot', 'action'); - toast.appendChild(wrongAction); - - const correctAction = document.createElement('button'); - correctAction.textContent = 'correct'; - toast.action = correctAction; - - assertActionButtonOnToast(correctAction, toast); -}, 'resetting toast.action on a toast with multiple actions slotted sets properly'); - -test(() => { - try { - Object.defineProperty(Element, Symbol.hasInstance, { - value: () => true, - configurable: true - }); - - const fakeElement = {}; - const toast = showToast('Message'); - assert_throws_js(TypeError, () => toast.action = fakeElement); - } finally { - delete Element[Symbol.hasInstance]; - } -}, 'spoofing element instance will not register as element to action setter'); - -test(() => { - const iframe = document.createElement('iframe'); - document.body.append(iframe); - iframe.contentDocument.body.innerHTML = '<div></div>'; - const elementFromAnotherFrame = iframe.contentDocument.querySelector('div'); - - // Should not throw: - const toast = showToast('Message'); - toast.action = elementFromAnotherFrame; -}, 'element from iframe instance will pass correctly to action without throwing an error'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/attributes.html b/tests/wpt/web-platform-tests/std-toast/attributes.html deleted file mode 100644 index 9b87280b668..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/attributes.html +++ /dev/null @@ -1,127 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: attribute tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> - -<script type="module"> -import { testToastElement, assertToastShown, assertToastNotShown, testToastElementAsync } from './resources/helpers.js'; - -testToastElement((toast) => { - toast.setAttribute('open', ''); - assertToastShown(toast); -}, 'setting `open` on a hidden toast shows the toast'); - -testToastElement((toast) => { - toast.setAttribute('open', false); - assertToastShown(toast); -}, 'setting `open` to false on a hidden toast shows the toast, because of string conversion'); - -testToastElement((toast) => { - toast.show(); - toast.setAttribute('open', 'test'); - assertToastShown(toast); -}, 'setting `open` on a shown toast does nothing'); - -testToastElement((toast) => { - toast.show(); - toast.setAttribute('open', 'test'); - toast.setAttribute('open', 'test'); - assertToastShown(toast); -}, 'resetting `open` on a shown toast does nothing'); - -testToastElement((toast) => { - toast.show(); - toast.setAttribute('open', false); - assertToastShown(toast); -}, 'setting `open` to false on a shown toast does nothing, because of string conversion'); - -testToastElement((toast) => { - toast.show(); - toast.removeAttribute('open'); - assertToastNotShown(toast); -}, 'removing `open` hides the toast'); - -testToastElement((toast) => { - toast.show(); - assert_true(toast.hasAttribute('open')); -}, 'showing the toast adds open attribute'); - -testToastElement((toast) => { - toast.show(); - toast.hide(); - assert_false(toast.hasAttribute('open')); -}, 'hiding the toast removes open attribute'); - -testToastElement((toast) => { - toast.toggleAttribute('open'); - assert_true(toast.hasAttribute('open')); -}, 'toggling `open` on a hidden toast sets the open attribute'); - -testToastElement((toast) => { - toast.toggleAttribute('open'); - toast.toggleAttribute('open'); - assert_false(toast.hasAttribute('open')); -}, 'toggling `open` twice leaves the toast with no open attribute'); - -testToastElement((toast) => { - assert_false(toast.open); -}, 'the `toast.open` boolean is false for a hidden toast'); - -testToastElement((toast) => { - toast.show(); - assert_true(toast.open); -}, 'the `toast.open` boolean is true for a shown toast'); - -testToastElement((toast) => { - toast.open = true; - assertToastShown(toast); - assert_equals(toast.getAttribute('open'), ''); -}, 'setting `toast.open` to true on a hidden toast will show the toast'); - -testToastElement((toast) => { - toast.show(); - toast.open = false; - assertToastNotShown(toast); -}, 'setting `toast.open` to false on a shown toast will hide the toast'); - -testToastElement((toast) => { - toast.open = 'truthy!'; - assertToastShown(toast); - assert_equals(toast.getAttribute('open'), ''); -}, 'setting `toast.open` to some truthy value on a hidden toast will show the toast'); - -testToastElement((toast) => { - toast.show(); - toast.open = ''; - assertToastNotShown(toast); -}, 'setting `toast.open` to some falsy value on a shown toast will hide the toast'); - -testToastElementAsync((t, toast) => { - toast.toggleAttribute('open', true); - - t.step_timeout(() => { - assertToastShown(toast); - t.done(); - }, 2000); -}, 'toggling open attribute does not start timeout'); - -testToastElement((toast) => { - const permitted_properties = ['constructor', 'show', 'hide', 'toggle', 'open', 'action', 'closeButton', 'type']; - assert_array_equals(permitted_properties.sort(), Object.getOwnPropertyNames(toast.__proto__).sort()); -}, 'toast only exposes certain properties'); - -testToastElement((toast) => { - assert_false(toast.hasAttribute('type')); - assert_equals(toast.type, ''); -}, 'default type is empty string without attribute present'); - -testToastElement((toast) => { - toast.type = 'info'; - assert_equals(toast.type, ''); - assert_equals(toast.getAttribute('type'), 'info'); -}, 'info was briefly a valid type, but no longer is, so it will return empty string'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/closebutton.html b/tests/wpt/web-platform-tests/std-toast/closebutton.html deleted file mode 100644 index d53c78aca5d..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/closebutton.html +++ /dev/null @@ -1,124 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: closebutton tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> - -<script type="module"> -import { showToast } from 'std:elements/toast'; -import { testToastElement } from './resources/helpers.js'; - -testToastElement((toast) => { - toast.setAttribute('closebutton', ''); - - assert_true(toast.closeButton); -}, 'the closeButton property returns true with an empty attribute'); - -testToastElement((toast) => { - toast.setAttribute('closebutton', 'dismiss'); - - assert_equals(toast.closeButton, 'dismiss'); -}, 'the closeButton property returns the set attribute value'); - -testToastElement((toast) => { - assert_false(toast.closeButton); -}, 'the closeButton property returns false with no attribute'); - -testToastElement((toast) => { - toast.setAttribute('closebutton', ''); - assert_true(toast.closeButton); - - toast.setAttribute('closebutton', 'dismiss'); - assert_equals(toast.closeButton, 'dismiss'); - - toast.removeAttribute('closebutton'); - assert_false(toast.closeButton); -}, 'the closeButton property changes when the attribute changes'); - -testToastElement((toast) => { - toast.closeButton = 'dismiss'; - - assert_equals(toast.getAttribute('closebutton'), 'dismiss'); -}, 'setting the closeButton property to any string changes the attribute to that string'); - -testToastElement((toast) => { - toast.closeButton = ''; - - assert_equals(toast.getAttribute('closebutton'), ''); -}, 'setting the closeButton property to empty string changes the attribute to empty string'); - -testToastElement((toast) => { - toast.closeButton = true; - - assert_equals(toast.getAttribute('closebutton'), ''); -}, 'setting the closeButton property to true changes the attribute to empty string'); - -testToastElement((toast) => { - toast.closeButton = false; - - assert_false(toast.hasAttribute('closebutton')); -}, 'setting the closeButton property to false removes the attribute'); - -testToastElement((toast) => { - toast.closeButton = undefined; - - assert_equals(toast.getAttribute('closebutton'), 'undefined'); -}, 'setting the closeButton property to undefined stringifies and sets to that'); - -testToastElement((toast) => { - toast.closeButton = null; - - assert_equals(toast.getAttribute('closebutton'), 'null'); -}, 'setting the closeButton property to null stringifies and sets to that'); - -testToastElement((toast) => { - toast.closeButton = {}; - - assert_equals(toast.getAttribute('closebutton'), '[object Object]'); -}, 'setting the closeButton property to {} stringifies and sets to [object Object]'); - -test(() => { - const toast = showToast('Message', { closeButton: true }); - - assert_equals(toast.getAttribute('closebutton'), ''); -}, 'setting the showToast closeButton option to true sets the closebutton attribute to empty string'); - -test(() => { - const toast = showToast('Message', { closeButton: 'dismiss' }); - - assert_equals(toast.getAttribute('closebutton'), 'dismiss'); -}, 'setting the showToast closeButton option to some string sets that string as the closebutton attribute'); - -test(() => { - const toast = showToast('Message', { closeButton: '' }); - - assert_equals(toast.getAttribute('closebutton'), ''); -}, 'setting the showToast closeButton option to empty string sets the closebutton attribute to empty string'); - -test(() => { - const toast = showToast('Message', { closeButton: {} }); - - assert_equals(toast.getAttribute('closebutton'), '[object Object]'); -}, 'setting the showToast closeButton option to {} sets the closebutton attribute to [object Object]'); - -test(() => { - const toast = showToast('Message', { closeButton: document.createElement('span') }); - - assert_equals(toast.getAttribute('closebutton'), '[object HTMLSpanElement]'); -}, 'passing an HTML element into the closeButton option of showToast stringifies and sets it to the closebutton attribute'); - -test(() => { - const toast = showToast('Message', { closeButton: false }); - - assert_false(toast.hasAttribute('closebutton')); -}, 'setting the showToast closeButton option to false does not put a close button on the toast'); - -test(() => { - const toast = showToast('Message'); - - assert_false(toast.hasAttribute('closebutton')); -}, 'calling showToast without the closeButton option does not put a closebutton on the toast'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/events-open.html b/tests/wpt/web-platform-tests/std-toast/events-open.html deleted file mode 100644 index a49414d2fce..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/events-open.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: event (open) tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> - -<script type="module"> -import { testToastElement, EventCollector } from './resources/helpers.js'; - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('show', counter.getCallback()); - toast.open = true; - - assert_equals(counter.getCount(), 1); -}, 'setting open to true on a hidden toast triggers the `show` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.open = true; - toast.addEventListener('show', counter.getCallback()); - toast.open = true; - - assert_equals(counter.getCount(), 0); -}, 'setting open to true on a shown toast does not trigger the `show` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('hide', counter.getCallback()); - toast.open = false; - - assert_equals(counter.getCount(), 0); -}, 'setting open to false on a hidden toast does not trigger the `hide` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.show(); - toast.addEventListener('hide', counter.getCallback()); - toast.open = false; - - assert_equals(counter.getCount(), 1); -}, 'setting open to false on a shown toast triggers the `hide` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('show', counter.getCallback()); - toast.open = true; - toast.open = true; - - assert_equals(counter.getCount(), 1); -}, 'setting open to true twice only triggers the `show` event once'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.show(); - toast.addEventListener('hide', counter.getCallback()); - toast.open = false; - toast.open = false; - - assert_equals(counter.getCount(), 1); -}, 'setting open to false twice only triggers the `hide` event once'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/events-showhide.html b/tests/wpt/web-platform-tests/std-toast/events-showhide.html deleted file mode 100644 index 547f742f713..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/events-showhide.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: event (show/hide) tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> - -<script type="module"> -import { testToastElement, EventCollector } from './resources/helpers.js'; - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('show', counter.getCallback()); - toast.show(); - - assert_equals(counter.getCount(), 1); -}, 'calling `show()` on a hidden toast triggers the `show` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.show(); - toast.addEventListener('show', counter.getCallback()); - toast.show(); - - assert_equals(counter.getCount(), 0); -}, 'calling `show()` on a shown toast does not trigger the `show` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('hide', counter.getCallback()); - toast.hide(); - - assert_equals(counter.getCount(), 0); -}, 'calling `hide()` on a hidden toast does not trigger the `hide` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.show(); - toast.addEventListener('hide', counter.getCallback()); - toast.hide(); - - assert_equals(counter.getCount(), 1); -}, 'calling `hide()` on a shown toast triggers the `hide` event'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.addEventListener('show', counter.getCallback()); - toast.show(); - toast.show(); - - assert_equals(counter.getCount(), 1); -}, 'calling `show()` twice only triggers the `show` event once'); - -testToastElement((toast) => { - const counter = new EventCollector(); - - toast.show(); - toast.addEventListener('hide', counter.getCallback()); - toast.hide(); - toast.hide(); - - assert_equals(counter.getCount(), 1); -}, 'calling `hide()` twice only triggers the `hide` event once'); - -testToastElement((toast) => { - const events = new EventCollector(); - - toast.addEventListener('show', events.getCallback()); - - toast.show(); - toast.hide(); - toast.show(); - - assert_equals(events.getCount(), 2); - assert_not_equals(events.getEvents()[0], events.getEvents()[1]); -}, "separate openings trigger different `show` events"); - -testToastElement((toast) => { - const events = new EventCollector(); - - toast.addEventListener('hide', events.getCallback()); - - toast.show(); - toast.hide(); - toast.show(); - toast.hide(); - - assert_equals(events.getCount(), 2); - assert_not_equals(events.getEvents()[0], events.getEvents()[1]); -}, "separate closings trigger different `hide` events"); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/methods.html b/tests/wpt/web-platform-tests/std-toast/methods.html deleted file mode 100644 index 981b9fba434..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/methods.html +++ /dev/null @@ -1,126 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: method tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main></main> -<div></div> - -<script type="module"> -import { testToastElement, assertToastShown, assertToastNotShown, testToastElementAsync } from './resources/helpers.js'; - -testToastElement((toast) => { - toast.show(); - - assertToastShown(toast); -}, 'calling `show()` on a hidden toast opens and displays it'); - -testToastElement((toast) => { - toast.toggleAttribute('open'); - toast.show(); - - assertToastShown(toast); -}, 'calling `show()` on a shown toast does nothing'); - -testToastElement((toast) => { - toast.toggleAttribute('open'); - toast.hide(); - - assertToastNotShown(toast); -}, 'calling `hide()` on a shown toast hides the toast'); - -testToastElement((toast) => { - toast.hide(); - - assertToastNotShown(toast); -}, 'calling `hide()` on a hidden toast does nothing'); - -testToastElement((toast) => { - toast.toggle(); - - assertToastShown(toast); -}, 'calling `toggle()` on a hidden toast shows the toast'); - -testToastElement((toast) => { - toast.show(); - toast.toggle(); - - assertToastNotShown(toast); -}, 'calling `toggle()` on a shown toast hides the toast'); - -testToastElement((toast) => { - toast.toggle(true); - - assertToastShown(toast); -}, 'calling `toggle()` with `force` parameter set to true on a hidden opens the toast'); - -testToastElement((toast) => { - toast.show(); - toast.toggle(true); - - assertToastShown(toast); -}, 'calling `toggle()` with `force` parameter set to true on a shown toast does not close the toast'); - -testToastElement((toast) => { - toast.toggle(false); - - assertToastNotShown(toast); -}, 'calling `toggle()` with `force` parameter set to false on a hidden toast does not open the toast'); - -testToastElement((toast) => { - toast.show(); - toast.toggle(false); - - assertToastNotShown(toast); -}, 'calling `toggle()` with `force` parameter set to false on a shown toast closes the toast'); - -testToastElementAsync((t, toast) => { - toast.show({duration: 50}); - - // time = 49 - t.step_timeout(() => { - assertToastShown(toast); - toast.show({duration: 50}); - - // time = 98 - t.step_timeout(() => { - assertToastShown(toast); - - // time = 99 - t.step_timeout(() => { - assertToastNotShown(toast); - t.done(); - }, 1000); - }, 49); - }, 49); -}, 'calling `show()` twice resets the timeout'); - -testToastElementAsync((t, toast) => { - toast.show({duration: 50}); - - // time = 48 - t.step_timeout(() => { - assertToastShown(toast); - toast.hide(); - - // time = 49 - t.step_timeout(() => { - assertToastNotShown(toast); - - // time = 50 - t.step_timeout(() => { - toast.show({duration: 2}); - - // time = 51 - t.step_timeout(() => { - assertToastShown(toast); - toast.hide(); - t.done(); - }, 1); - }, 1); - }, 1); - }, 48); -}, 'calling `hide()` clears the timeout'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/options.html b/tests/wpt/web-platform-tests/std-toast/options.html deleted file mode 100644 index 0383d71f9ae..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/options.html +++ /dev/null @@ -1,129 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<meta name="timeout" content="long"> -<title>Toast: option tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<body> -</body> - -<script type="module"> -import { showToast, StdToastElement } from 'std:elements/toast'; -import { assertToastNotShown, assertToastShown } from './resources/helpers.js'; - -// message -test(() => { - const toast = new StdToastElement('test'); - document.body.appendChild(toast); - - assert_equals(toast.textContent, 'test'); -}, 'passing test string as message sets the message properly'); - -test(() => { - const toast = new StdToastElement('<p>rich text</p>'); - document.body.appendChild(toast); - - assert_equals(toast.textContent, '<p>rich text</p>'); - assert_equals(toast.querySelector('p'), null); -}, 'passing markup to the constructor does not pass through the markup behaviors'); - -test(() => { - const toast = new StdToastElement(false); - document.body.appendChild(toast); - - assert_equals(toast.textContent, 'false'); -}), 'passing false as message converts to the string `false`'; - -test(() => { - const toast = new StdToastElement(); - document.body.appendChild(toast); - - assert_equals(toast.textContent, ''); -}, 'passing nothing as message sets the message to the empty string'); - -test(() => { - const toast = new StdToastElement(undefined); - document.body.appendChild(toast); - - assert_equals(toast.textContent, ''); -}, 'passing `undefined` as message sets the message to the empty string'); - -test(() => { - const toast = new StdToastElement(''); - document.body.appendChild(toast); - - assert_equals(toast.textContent, ''); -}, 'passing empty string as message sets the message to the empty string'); - -test(() => { - const toastString = '<std-toast id="test">test</std-toast>'; - document.body.innerHTML = toastString; - const toast = document.body.querySelector('#test'); - - assert_equals(toast.textContent, 'test'); -}, 'HTML created toast has `test` as its text content'); - -// duration -async_test(t => { - const toast = showToast('message'); - - t.step_timeout(() => { - assertToastShown(toast); - }, 2999); - - t.step_timeout(() => { - assertToastNotShown(toast); - t.done(); - }, 3000); - - t.add_cleanup(function() { - toast.remove(); - }); -}, 'showToast closes after default duration of 3000ms'); -// FIXME: find a way to virtualize time instead of waiting 3000ms -// BUG: https://github.com/web-platform-tests/wpt/issues/17489 - -async_test(t => { - const toast = showToast('message', {duration: 50}); - - t.step_timeout(() => { - assertToastShown(toast); - }, 49); - - t.step_timeout(() => { - assertToastNotShown(toast); - t.done(); - }, 50); - - t.add_cleanup(function() { - toast.remove(); - }); -}, 'showToast closes after user specified 50ms'); - -async_test(t => { - const toast = showToast('message', {duration: Infinity}); - - t.step_timeout(() => { - assertToastShown(toast); - t.done(); - }, 50); - - t.add_cleanup(function() { - toast.remove(); - }); -}, 'passing Infinity as the duration leaves the toast open for at least 50ms'); - -test(() => { - assert_throws_js(RangeError, () => { - const toast = showToast('Message', {duration: 0}); - }); -}, 'setting the duration to 0 throws a RangeError'); - -test(() => { - assert_throws_js(RangeError, () => { - const toast = showToast('Message', {duration: -5}); - }); -}, 'setting the duration to a negative number throws a RangeError'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting-expected.html b/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting-expected.html deleted file mode 100644 index b4b365c7a9d..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting-expected.html +++ /dev/null @@ -1,8 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: slotting test reference</title> -<script type="module"> -import 'std:elements/toast'; -</script> -<p>Pass if the toast is displayed with the action button last.</p> -<std-toast open>First. Second. <button>Last.</button></std-toast> diff --git a/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting.html b/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting.html deleted file mode 100644 index 4d6f5038f2d..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/ref-tests/toast-slotting.html +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: slotting test</title> -<link rel="help" href="https://github.com/jackbsteinberg/std-toast"> -<meta name="assert" content="Toast slots action button behind any text"> -<link rel="match" href="toast-slotting-expected.html"> -<script type="module"> -import 'std:elements/toast'; -</script> -<p>Pass if the toast is displayed with the action button last.</p> -<std-toast open>First. <button slot="action">Last.</button> Second. </std-toast>
\ No newline at end of file diff --git a/tests/wpt/web-platform-tests/std-toast/reflection.html b/tests/wpt/web-platform-tests/std-toast/reflection.html deleted file mode 100644 index 36cbaf65228..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/reflection.html +++ /dev/null @@ -1,24 +0,0 @@ -<!doctype html> -<title>HTML5 reflection tests: std-toast</title> -<meta name=timeout content=long> - -<div id=log></div> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/html/dom/original-harness.js"></script> -<script src="/html/dom/new-harness.js"></script> - -<script type="module"> -import 'std:elements/toast'; - -const toastElement = { - 'std-toast': { - open: 'boolean', - type: {type: 'enum', keywords: ['success', 'error', 'warning']}, - }, -}; - -mergeElements(toastElement); -</script> -<script src="/html/dom/reflection.js" defer></script> diff --git a/tests/wpt/web-platform-tests/std-toast/resources/helpers.js b/tests/wpt/web-platform-tests/std-toast/resources/helpers.js deleted file mode 100644 index 256f0c88040..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/resources/helpers.js +++ /dev/null @@ -1,101 +0,0 @@ -import { showToast, StdToastElement } from 'std:elements/toast'; - -// helper functions to keep tests from bleeding into each other - -const runTest = (testFn, name, toast, action) => { - try { - test(() => { - testFn(toast, action); - }, name); - } finally { - toast.remove(); - } -}; - -const runTestAsync = (testFn, name, toast) => { - async_test(t => { - testFn(t, toast); - t.add_cleanup(() => { - toast.remove(); - }); - }, name); -}; - -export const testToastElement = (testFn, name) => { - const toast = new StdToastElement('Message', {}); - document.querySelector('main').appendChild(toast); - - runTest(testFn, name, toast); -}; - -export const testToastElementAsync = (testFn, name) => { - const toast = new StdToastElement('Message', {}); - document.querySelector('main').appendChild(toast); - - runTestAsync(testFn, name, toast); -}; - -export const testShowToast = (testFn, name) => { - const toast = showToast("message"); - - runTest(testFn, name, toast); -}; - -export const testActionToast = (testFn, name) => { - const toast = new StdToastElement('Message', {}); - const action = document.createElement('button'); - action.setAttribute('slot', 'action'); - action.textContent = 'action'; - toast.appendChild(action); - document.querySelector('main').appendChild(toast); - - runTest(testFn, name, toast, action); -}; - -export const assertToastShown = (toast) => { - assert_not_equals(window.getComputedStyle(toast).display, 'none'); - assert_true(toast.hasAttribute('open')); - assert_true(toast.open); -}; - -export const assertToastNotShown = (toast) => { - assert_equals(window.getComputedStyle(toast).display, 'none'); - assert_false(toast.hasAttribute('open')); - assert_false(toast.open); -}; - -export const assertActionButtonOnToast = (action, toast) => { - assert_equals(toast.action, action); - assert_equals(action.getAttribute('slot'), 'action'); - assert_equals(action, toast.querySelector('button')); -}; - -export const assertComputedStyleMapsEqual = (element1, element2) => { - assert_greater_than(element1.computedStyleMap().size, 0); - for (const [styleProperty, baseStyleValues] of element1.computedStyleMap()) { - const refStyleValues = element2.computedStyleMap().getAll(styleProperty); - assert_equals(baseStyleValues.length, refStyleValues.length, `${styleProperty} length`); - - for (let i = 0; i < baseStyleValues.length; ++i) { - const baseStyleValue = baseStyleValues[i]; - const refStyleValue = refStyleValues[i]; - assert_equals(baseStyleValue.toString(), refStyleValue.toString(), `diff at value ${styleProperty}`); - } - } -} - -export class EventCollector { - events = []; - - getCallback() { - return (e) => {this.events.push(e)}; - } - - getCount() { - return this.events.length; - } - - getEvents() { - return this.events; - } -} diff --git a/tests/wpt/web-platform-tests/std-toast/show-toast.html b/tests/wpt/web-platform-tests/std-toast/show-toast.html deleted file mode 100644 index 50cdc2c06dd..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/show-toast.html +++ /dev/null @@ -1,63 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: showToast tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<body> -</body> - -<script type="module"> -import { showToast, StdToastElement } from 'std:elements/toast'; -import { testShowToast, assertToastNotShown, assertToastShown } from './resources/helpers.js'; - -testShowToast((toast) => { - assert_true(toast != null); - assert_true(toast instanceof StdToastElement); -}, 'showToast creates and returns a toast'); - -testShowToast((toast) => { - assert_true(document.querySelector('std-toast') === toast); -}, 'showToast puts the toast in the DOM'); - -testShowToast((toast) => { - assertToastShown(toast); -}, 'showToast displays the toast by default'); - -testShowToast((toast) => { - toast.hide(); - - assertToastNotShown(toast); -}, 'hiding showToast immediately does not display it'); - -testShowToast((toast) => { - toast.show(); - - assertToastShown(toast); -}, 'calling show after showToast does nothing'); - -testShowToast((toast) => { - let toast2; - try { - toast2 = showToast('message2'); - - assert_not_equals(toast, toast2); - } - finally { - toast2.remove(); - } -}, 'calling showToast multiple times creates multiple different toasts'); - -test(() => { - const toast = showToast('test'); - assert_equals(toast.textContent, 'test'); -}, 'showToast created toast has `test` as its text content'); - -test(() => { - const toast = showToast('<p>rich text</p>'); - - assert_equals(toast.textContent, '<p>rich text</p>'); - assert_equals(toast.querySelector('p'), null); -}, 'passing markup to showToast does not pass through the markup behaviors'); -</script> diff --git a/tests/wpt/web-platform-tests/std-toast/styles.html b/tests/wpt/web-platform-tests/std-toast/styles.html deleted file mode 100644 index 1db8620485d..00000000000 --- a/tests/wpt/web-platform-tests/std-toast/styles.html +++ /dev/null @@ -1,100 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Toast: style tests</title> - -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> - -<main> -</main> - -<script type="module"> -import { testToastElement, assertComputedStyleMapsEqual } from './resources/helpers.js'; - -testToastElement((toast) => { - toast.open = true; - - const mockToast = document.createElement('span'); - mockToast.id = 'mock-toast-open'; - mockToast.textContent = 'Message'; - - const mockStyler = document.createElement('style'); - mockStyler.textContent = ` - #mock-toast-open { - position: fixed; - bottom: 1em; - right: 1em; - border: solid; - padding: 1em; - background: white; - color: black; - z-index: 1; - }`; - - document.querySelector('main').appendChild(mockStyler); - document.querySelector('main').appendChild(mockToast); - - assertComputedStyleMapsEqual(toast, mockToast); -}, 'the computed style map of an open unstyled toast is the same as a span given toast defaults'); - -testToastElement((toast) => { - const mockToast = document.createElement('span'); - mockToast.id = 'mock-toast-hidden'; - mockToast.textContent = 'Message'; - - const mockStyler = document.createElement('style'); - mockStyler.textContent = ` - #mock-toast-hidden { - position: fixed; - bottom: 1em; - right: 1em; - border: solid; - padding: 1em; - background: white; - color: black; - z-index: 1; - display: none; - }`; - - document.querySelector('main').appendChild(mockStyler); - document.querySelector('main').appendChild(mockToast); - - assertComputedStyleMapsEqual(toast, mockToast); -}, 'the computed style map of a closed unstyled toast is the same as a span given toast defaults'); - -testToastElement((toast) => { - toast.type = 'error'; - - const styles = window.getComputedStyle(toast); - assert_equals(styles.borderColor, 'rgb(255, 0, 0)'); -}, 'changing type to error changes the border color to red'); - -testToastElement((toast) => { - toast.type = 'warning'; - - const styles = window.getComputedStyle(toast); - assert_equals(styles.borderColor, 'rgb(255, 165, 0)'); -}, 'changing type to warning changes the border color to orange'); - -testToastElement((toast) => { - toast.type = 'success'; - - const styles = window.getComputedStyle(toast); - assert_equals(styles.borderColor, 'rgb(0, 128, 0)'); -}, 'changing type to success changes the border color to green'); - -testToastElement((toast) => { - const styler = document.createElement('style'); - styler.append(` - [type=error i] { - border-color: pink; - } - `); - document.querySelector('main').appendChild(styler); - - toast.type = 'error'; - - const styles = window.getComputedStyle(toast); - assert_equals(styles.borderColor, 'rgb(255, 192, 203)'); -}, 'outside styles can set type styles'); -</script> diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-insertDTMF.https.html b/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-insertDTMF.https.html index ac27c5139cc..71cfe70171f 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-insertDTMF.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDTMFSender-insertDTMF.https.html @@ -53,17 +53,15 @@ All other characters (and only those other characters) MUST be considered unrecognized. */ - promise_test(t => { - return createDtmfSender() - .then(dtmfSender => { - dtmfSender.insertDTMF(''); - dtmfSender.insertDTMF('012345689'); - dtmfSender.insertDTMF('ABCD'); - dtmfSender.insertDTMF('abcd'); - dtmfSender.insertDTMF('#*'); - dtmfSender.insertDTMF(','); - dtmfSender.insertDTMF('0123456789ABCDabcd#*,'); - }); + promise_test(async t => { + const dtmfSender = await createDtmfSender(); + dtmfSender.insertDTMF(''); + dtmfSender.insertDTMF('012345689'); + dtmfSender.insertDTMF('ABCD'); + dtmfSender.insertDTMF('abcd'); + dtmfSender.insertDTMF('#*'); + dtmfSender.insertDTMF(','); + dtmfSender.insertDTMF('0123456789ABCDabcd#*,'); }, 'insertDTMF() should succeed if tones contains valid DTMF characters'); @@ -72,21 +70,19 @@ 6. If tones contains any unrecognized characters, throw an InvalidCharacterError. */ - promise_test(t => { - return createDtmfSender() - .then(dtmfSender => { - assert_throws_dom('InvalidCharacterError', () => - // 'F' is invalid - dtmfSender.insertDTMF('123FFABC')); - - assert_throws_dom('InvalidCharacterError', () => - // 'E' is invalid - dtmfSender.insertDTMF('E')); - - assert_throws_dom('InvalidCharacterError', () => - // ' ' is invalid - dtmfSender.insertDTMF('# *')); - }); + promise_test(async t => { + const dtmfSender = await createDtmfSender(); + assert_throws_dom('InvalidCharacterError', () => + // 'F' is invalid + dtmfSender.insertDTMF('123FFABC')); + + assert_throws_dom('InvalidCharacterError', () => + // 'E' is invalid + dtmfSender.insertDTMF('E')); + + assert_throws_dom('InvalidCharacterError', () => + // ' ' is invalid + dtmfSender.insertDTMF('# *')); }, 'insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters'); /* @@ -152,37 +148,29 @@ 7. Set the object's toneBuffer attribute to tones. */ - promise_test(t => { - return createDtmfSender() - .then(dtmfSender => { - dtmfSender.insertDTMF('123'); - assert_equals(dtmfSender.toneBuffer, '123'); - - dtmfSender.insertDTMF('ABC'); - assert_equals(dtmfSender.toneBuffer, 'ABC'); - - dtmfSender.insertDTMF('bcd'); - assert_equals(dtmfSender.toneBuffer, 'BCD'); - }); + promise_test(async t => { + const dtmfSender = await createDtmfSender(); + dtmfSender.insertDTMF('123'); + assert_equals(dtmfSender.toneBuffer, '123'); + + dtmfSender.insertDTMF('ABC'); + assert_equals(dtmfSender.toneBuffer, 'ABC'); + + dtmfSender.insertDTMF('bcd'); + assert_equals(dtmfSender.toneBuffer, 'BCD'); }, 'insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden'); - promise_test(t => { - let dtmfSender; - let sender; - let pc = new RTCPeerConnection(); + promise_test(async t => { + const pc = new RTCPeerConnection(); t.add_cleanup(() => pc.close()); - return getTrackFromUserMedia('audio') - .then(([track, mediaStream]) => { - sender = pc.addTrack(track, mediaStream); - return pc.createOffer(); - }).then(offer => { - pc.setLocalDescription(offer); - dtmfSender = sender.dtmf; - pc.removeTrack(sender); - pc.close(); - assert_throws_dom('InvalidStateError', () => - dtmfSender.insertDTMF('123')); - }); + const [track, mediaStream] = await getTrackFromUserMedia('audio'); + const sender = pc.addTrack(track, mediaStream); + await pc.setLocalDescription(await pc.createOffer()); + const dtmfSender = sender.dtmf; + pc.removeTrack(sender); + pc.close(); + assert_throws_dom('InvalidStateError', () => + dtmfSender.insertDTMF('123')); }, 'insertDTMF() after remove and close should reject'); </script> diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-operations.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-operations.https.html new file mode 100644 index 00000000000..e88c8b28172 --- /dev/null +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-operations.https.html @@ -0,0 +1,211 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +'use strict'; + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + pc1.addTransceiver("video"); + const offer = await pc1.createOffer(); + await pc1.setLocalDescription(offer); + const {candidate} = await new Promise(r => pc1.onicecandidate = r); + try { + await pc2.addIceCandidate(candidate); + assert_unreached("Control. Must not succeed"); + } catch (e) { + assert_equals(e.name, "InvalidStateError"); + } + const p = pc2.setRemoteDescription(offer); + await pc2.addIceCandidate(candidate); + await p; +}, "addIceCandidate chains onto SRD, fails before"); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + pc1.addTransceiver("video"); + await Promise.all([ + pc1.createOffer(), + pc1.setLocalDescription({type: "offer"}) + ]); + await Promise.all([ + pc2.setRemoteDescription(pc1.localDescription), + pc2.createAnswer(), + pc2.setLocalDescription({type: "answer"}) + ]); + await pc1.setRemoteDescription(pc2.localDescription); +}, "Pack operations queue with implicit offer and answer"); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + const state = (pc, s) => new Promise(r => pc.onsignalingstatechange = + () => pc.signalingState == s && r()); + pc1.addTransceiver("video"); + pc1.createOffer(); + pc1.setLocalDescription({type: "offer"}); + await state(pc1, "have-local-offer"); + pc2.setRemoteDescription(pc1.localDescription); + pc2.createAnswer(); + pc2.setLocalDescription({type: "answer"}); + await state(pc2, "stable"); + await pc1.setRemoteDescription(pc2.localDescription); +}, "Negotiate solely by operations queue and signaling state"); + +// Helpers to test APIs "return a promise rejected with a newly created" error. +// Strictly speaking this means already-rejected upon return. +function promiseState(p) { + const t = {}; + return Promise.race([p, t]) + .then(v => (v === t)? "pending" : "fulfilled", () => "rejected"); +} + +// However, to allow promises to be used in implementations, this helper adds +// some slack: returning a pending promise will pass, provided it is rejected +// before the end of the current run of the event loop (i.e. on microtask queue +// before next task). +async function promiseStateFinal(p) { + for (let i = 0; i < 20; i++) { + await promiseState(p); + } + return promiseState(p); +} + +promise_test(async t => { + assert_equals(await promiseState(Promise.resolve()), "fulfilled"); + assert_equals(await promiseState(Promise.reject()), "rejected"); + assert_equals(await promiseState(new Promise(() => {})), "pending"); +}, "promiseState helper works"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const p = pc.setLocalDescription({type: "offer", sdp: "blah"}); + const haveState = promiseStateFinal(p); + try { + await p; + assert_unreached("Control. Must not succeed"); + } catch (e) { + assert_equals(e.name, "InvalidModificationError"); + } + assert_equals(await haveState, "rejected", "promise rejected on same task"); +}, "Operations chain must run first operation's sync part synchronously"); + +// Helper builds on above test to check if operations queue is empty or not. +async function isOperationsChainEmpty(pc) { + const type = pc.signalingState == "have-remote-offer" ? "answer" : "offer"; + const p = pc.setLocalDescription({type, sdp: "blah"}); + const state = await promiseStateFinal(p); + try { + await p; + assert_unreached("Control. Must not succeed"); + } catch (e) { + assert_equals(e.name, "InvalidModificationError", "isOperationsChainEmpty"); + } + return state == "rejected"; +} + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + assert_true(await isOperationsChainEmpty(pc), "Empty to start"); +}, "isOperationsChainEmpty detects empty"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + const p = await pc.createOffer(); + try { + await pc.setLocalDescription({type: "offer", sdp: "blah"}); + assert_unreached("Control. Must not succeed"); + } catch (e) { + assert_equals(e.name, "InvalidModificationError"); + } +}, "SLD(offer) must validate against LastCreatedOffer early (prerequisite)"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + await pc.setRemoteDescription(await pc.createOffer()); + try { + await pc.setLocalDescription({type: "offer", sdp: "blah"}); + assert_unreached("Control. Must not succeed"); + } catch (e) { + assert_equals(e.name, "InvalidModificationError"); + } +}, "SLD(offer) must validate input before signaling state (prerequisite)"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + const p = pc.createOffer(); + assert_true(!await isOperationsChainEmpty(pc), "Non-empty queue"); + await p; +}, "createOffer uses operations chain"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + await pc.setRemoteDescription(await pc.createOffer()); + const p = pc.createAnswer(); + assert_true(!await isOperationsChainEmpty(pc), "Non-empty queue"); + await p; +}, "createAnswer uses operations chain"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + + const offer = await pc.createOffer(); + const p = pc.setLocalDescription(offer); + assert_true(!await isOperationsChainEmpty(pc), "Non-empty queue"); + await p; +}, "setLocalDescription uses operations chain"); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.createDataChannel("dummy"); + + const offer = await pc.createOffer(); + assert_true(await isOperationsChainEmpty(pc), "Empty after settled"); + const p = pc.setRemoteDescription(offer); + assert_true(!await isOperationsChainEmpty(pc), "Non-empty queue"); + await p; +}, "setRemoteDescription uses operations chain"); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + pc1.addTransceiver("video"); + const offer = await pc1.createOffer(); + await pc1.setLocalDescription(offer); + const {candidate} = await new Promise(r => pc1.onicecandidate = r); + await pc2.setRemoteDescription(offer); + const p = pc2.addIceCandidate(candidate); + assert_true(!await isOperationsChainEmpty(pc2), "Non-empty queue"); + await p; +}, "addIceCandidate uses operations chain"); + +</script> diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html index 0cce78bfbca..5a7a76319a0 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html @@ -7,7 +7,7 @@ <script> "use strict"; -const kSmallTimeoutMs = 10; +const kSmallTimeoutMs = 100; promise_test(async t => { const offerer = new RTCPeerConnection(); @@ -34,6 +34,7 @@ promise_test(async t => { t.add_cleanup(() => offerer.close()); const transceiver = offerer.addTransceiver('audio'); + assert_equals(transceiver.mid, null); await offerer.setLocalDescription(); assert_not_equals(transceiver.mid, null); }, "Parameterless SLD() in 'stable' assigns transceiver.mid"); @@ -110,20 +111,25 @@ promise_test(async t => { promise_test(async t => { const offerer = new RTCPeerConnection(); offerer.close(); - - offerer.setLocalDescription().then(t.step_func(() => assert_not_reached())); - await new Promise(resolve => t.step_timeout(resolve, kSmallTimeoutMs)); -}, "Parameterless SLD() never resolves if already closed"); + try { + await offerer.setLocalDescription(); + assert_not_reached(); + } catch (e) { + assert_equals(e.name, "InvalidStateError"); + } +}, "Parameterless SLD() rejects with InvalidStateError if already closed"); promise_test(async t => { const offerer = new RTCPeerConnection(); t.add_cleanup(() => offerer.close()); - offerer.setLocalDescription().then(t.step_func(() => assert_not_reached())); + const p = Promise.race([ + offerer.setLocalDescription(), + new Promise(r => t.step_timeout(() => r("timeout"), kSmallTimeoutMs)) + ]); offerer.close(); - await new Promise(resolve => t.step_timeout(resolve, kSmallTimeoutMs)); -}, "Parameterless SLD() never resolves if closed while pending"); - + assert_equals(await p, "timeout"); +}, "Parameterless SLD() never settles if closed while pending"); promise_test(async t => { const offerer = new RTCPeerConnection(); @@ -139,4 +145,26 @@ promise_test(async t => { await offerer.setRemoteDescription(answerer.currentLocalDescription); }, "Parameterless SLD() in a full O/A exchange succeeds"); -</script>
\ No newline at end of file +promise_test(async t => { + const answerer = new RTCPeerConnection(); + try { + await answerer.setRemoteDescription(); + assert_not_reached(); + } catch (e) { + assert_equals(e.name, "TypeError"); + } +}, "Parameterless SRD() rejects with TypeError."); + +promise_test(async t => { + const offerer = new RTCPeerConnection(); + const {sdp} = await offerer.createOffer(); + new RTCSessionDescription({type: "offer", sdp}); + try { + new RTCSessionDescription({sdp}); + assert_not_reached(); + } catch (e) { + assert_equals(e.name, "TypeError"); + } +}, "RTCSessionDescription constructed without type throws TypeError"); + +</script> |