diff options
53 files changed, 1758 insertions, 331 deletions
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 53229d83310..c51c6d3a49f 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -237342,7 +237342,7 @@ [] ], "support.js": [ - "d3b2bb7d1212dd6de0379bf2dce0b23e45f7c7cb", + "8dbfa6f1e37d7631bf5f69b9da9b906876c5d2cf", [] ] }, @@ -279916,7 +279916,7 @@ [] ], "testcommon.js": [ - "b4fde4b967de2eb67cb3e0819c3a896375e861f9", + "7d63d2c49bce5152d765ac62728f749f622bde2a", [] ] } @@ -305255,7 +305255,7 @@ [] ], "numeric-testcommon.js": [ - "56022d06399df48b48d72ef71169578034a5f86c", + "996250d359dc676e001bb1aebfacae98c263e41a", [] ], "parsing-testcommon.js": [ @@ -315475,10 +315475,6 @@ "6604450991a122e3e241e40b1b9e0516c525389d", [] ], - "dedicated-worker.js": [ - "5d46edcde24c1854c19069d967038c493d7e24f0", - [] - ], "iframe.html": [ "a6b74ad924aa108e15603544f7b0a80a3e18940b", [] @@ -315538,6 +315534,10 @@ "sw.js": [ "57f0b41ba5b5ff6318e1e4913dfd13bdb1f237a4", [] + ], + "universal-worker.js": [ + "5d46edcde24c1854c19069d967038c493d7e24f0", + [] ] }, "sandbox.https.html.headers": [ @@ -324888,7 +324888,7 @@ [] ], "construct-stylesheets.idl": [ - "fca2a3e2887a192f737b4ce05edc52810b2cd7a9", + "35121866f66eaa8b6663480d1a4cb72c1cf8fd1e", [] ], "cookie-store.idl": [ @@ -328375,7 +328375,7 @@ }, "script-tests": { "FileSystemBaseHandle-IndexedDB.js": [ - "d7403ff5ea6d649d2b36870a5add0730f528a1ea", + "855e52f04ddf2f4f8641524010216c6e8c7cdda7", [] ], "FileSystemBaseHandle-postMessage-BroadcastChannel.js": [ @@ -337717,7 +337717,7 @@ [] ], "nfc-mock.js": [ - "7832a8231efb01f277960afc91adf01cfe3e3ac6", + "14bb8fdada399999efb67576481efa8881af48f3", [] ], "sensor.mojom.js": [ @@ -347603,7 +347603,7 @@ [] ], "revlist.py": [ - "c4cbc2943b7ce02ef2a58f65d34ab717bfb0c981", + "1893fdefa8346e8f969e41789df6e3ddd8540629", [] ], "run.py": [ @@ -349915,7 +349915,7 @@ ], "resources": { "nfc-helpers.js": [ - "5bec071dfa7ad65fe4181a897ebe91912ee94476", + "b1753ddd1b3c5fb70b5ee4d99500623e3fdbdbfd", [] ], "support-iframe.html": [ @@ -365657,6 +365657,181 @@ {} ] ], + "transaction-scheduling-across-connections.any.js": [ + "92d098d29c937c84b7bc9dd1219f126db0b7e585", + [ + "IndexedDB/transaction-scheduling-across-connections.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-across-connections.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-across-databases.any.js": [ + "064444175867ca528d0d90ea0be40d573561ca88", + [ + "IndexedDB/transaction-scheduling-across-databases.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-across-databases.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-mixed-scopes.any.js": [ + "5f04a6a288d23c29a7663ccfcdb32c932d573831", + [ + "IndexedDB/transaction-scheduling-mixed-scopes.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-mixed-scopes.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-ordering.any.js": [ + "9f47e5c58ca3961d83263c7d90da597b83e06ceb", + [ + "IndexedDB/transaction-scheduling-ordering.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-ordering.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-ro-waits-for-rw.any.js": [ + "dca08b820888f13c00cdb5a8a61badac884fac21", + [ + "IndexedDB/transaction-scheduling-ro-waits-for-rw.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-ro-waits-for-rw.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-rw-scopes.any.js": [ + "7c6f61614b0689d3090222872379c1269559ec4c", + [ + "IndexedDB/transaction-scheduling-rw-scopes.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-rw-scopes.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], + "transaction-scheduling-within-database.any.js": [ + "10dd8b6d7ac5ed9dd4399a04dada2f5e88b827d8", + [ + "IndexedDB/transaction-scheduling-within-database.any.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ], + [ + "IndexedDB/transaction-scheduling-within-database.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support.js" + ] + ] + } + ] + ], "transaction_bubble-and-capture.htm": [ "bffa9307ccf3c7738639eb243cbf2d3ae984cb5d", [ @@ -379148,7 +379323,7 @@ }, "nonce-hiding": { "nonces.html": [ - "b023d060323d9d9f366ffdb53159a6f25ab24065", + "7ee10a7b29e5a54918a75037ded0e5bd087f601a", [ null, {} @@ -383914,6 +384089,13 @@ {} ] ], + "AnimationEffect-updateTiming.tentative.html": [ + "de6953c761facd400a37572419e3c97f42b4cfed", + [ + null, + {} + ] + ], "CSSAnimation-animationName.tentative.html": [ "370d5ef85e27c2e83deb54522a31da9deb8b556c", [ @@ -383936,7 +384118,7 @@ ] ], "CSSAnimation-effect.tentative.html": [ - "bbf35d5113a9c3d1e4dba7318f649494c88feb4c", + "95a904187204286a49a17377d3201f4918128566", [ null, { @@ -383966,7 +384148,7 @@ ] ], "CSSAnimation-pausing.tentative.html": [ - "2b6e6853b4178f90e820a16a74a5d63524123d32", + "156a1afa964de12e4a983c032f9b526b5cdf625d", [ null, {} @@ -384015,7 +384197,14 @@ ] ], "KeyframeEffect-getKeyframes.tentative.html": [ - "591cc15a7eda8279ec5e9af529f8e6a06b7caa6c", + "f7d767dea8ca15589a53fae7952bb15e383ccd22", + [ + null, + {} + ] + ], + "KeyframeEffect-setKeyframes.tentative.html": [ + "7d8f845413a38daae9bcc9d6ce251e44cda582cb", [ null, {} @@ -402871,7 +403060,7 @@ ] ], "round-function.html": [ - "236b9a9a8a32e691c5b5b0ea6df66995ec1e4a10", + "b1e950efe7238fcc08b9423dca88e51383f8f7d3", [ null, {} @@ -431087,7 +431276,7 @@ ] ], "dedicated-worker-cache-storage.https.html": [ - "2559de839a304dce0c2700dc4f8ee0002de04332", + "dced705206fd02ede82ef4c3ed29bbd8f5f1ea2c", [ null, {} @@ -431202,6 +431391,13 @@ {} ] ], + "service-worker-cache-storage.https.html": [ + "873f06ce4ffbf83bca2ac4dbdc04e5b5bf92abb6", + [ + null, + {} + ] + ], "srcdoc.https.html": [ "3fbba961b2736ed8c9fb973d61dfac5e54267c40", [ @@ -549877,6 +550073,13 @@ null, {} ] + ], + "suspended-context-messageport.https.html": [ + "5f5b10a251f41fd29f694564a717587f8a5a0bad", + [ + null, + {} + ] ] }, "the-biquadfilternode-interface": { @@ -550616,7 +550819,7 @@ ] ], "createcredential-badargs-authnrselection.https.html": [ - "5da0745734ffbfbcd0d1658e4f4c1914d9940611", + "9497a001f0f4726ac628178983e8ce2625b25e88", [ null, { @@ -550636,7 +550839,7 @@ ] ], "createcredential-badargs-rp.https.html": [ - "cbd86b8f083e3d1d3b28842b9fa5759047cfac1e", + "8886cc15c92e0ae98f0c65d6d1daa92cb93acfb7", [ null, { @@ -550656,7 +550859,7 @@ ] ], "createcredential-excludecredentials.https.html": [ - "3a5af481fcac6cd1f9f0e1e95caab7ba7a7facb4", + "2b1eec19b7b3a806150d13c77d8cfd1ea01973a6", [ null, { @@ -550666,7 +550869,7 @@ ] ], "createcredential-extensions.https.html": [ - "036200dbbf949e7d0b274e44cc88e7aef1366cb8", + "46cab3051b4924a2cb9cf1d7a2df46046b7b2f23", [ null, { @@ -550686,7 +550889,7 @@ ] ], "createcredential-pubkeycredparams.https.html": [ - "c845a90687576a2d33b7f459c293aa74a15c1fb9", + "d1df7952d6766744280b460a18d2e561a5527e5d", [ null, { diff --git a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-002.html.ini b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-002.html.ini new file mode 100644 index 00000000000..f64b45fea6b --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-002.html.ini @@ -0,0 +1,4 @@ +[hit-test-floats-002.html] + [Hit test float] + expected: FAIL + 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 new file mode 100644 index 00000000000..4bfb0c2053a --- /dev/null +++ b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-004.html.ini @@ -0,0 +1,4 @@ +[hit-test-floats-004.html] + [Miss float below something else] + expected: FAIL + diff --git a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini b/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini deleted file mode 100644 index baa9f1a7541..00000000000 --- a/tests/wpt/metadata/css/CSS2/floats/hit-test-floats-005.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[hit-test-floats-005.html] - [Miss clipped float] - expected: FAIL - diff --git a/tests/wpt/metadata/css/css-animations/AnimationEffect-updateTiming.tentative.html.ini b/tests/wpt/metadata/css/css-animations/AnimationEffect-updateTiming.tentative.html.ini new file mode 100644 index 00000000000..963b484697e --- /dev/null +++ b/tests/wpt/metadata/css/css-animations/AnimationEffect-updateTiming.tentative.html.ini @@ -0,0 +1,16 @@ +[AnimationEffect-updateTiming.tentative.html] + [AnimationEffect.updateTiming({ delay, fill }) causes changes to the animation-delay and animation-fill-mode to be ignored] + expected: FAIL + + [AnimationEffect.updateTiming({ duration }) causes changes to the animation-duration to be ignored] + expected: FAIL + + [AnimationEffect.updateTiming({ iterations, direction }) causes changes to the animation-iteration-count and animation-direction to be ignored] + expected: FAIL + + [AnimationEffect properties that do not map to animation-* properties should not be changed when animation-* style is updated] + expected: FAIL + + [AnimationEffect.updateTiming() does override to changes from animation-* properties if there is an error] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-animations/CSSAnimation-effect.tentative.html.ini b/tests/wpt/metadata/css/css-animations/CSSAnimation-effect.tentative.html.ini index 92a8142c0e2..9b844b4399e 100644 --- a/tests/wpt/metadata/css/css-animations/CSSAnimation-effect.tentative.html.ini +++ b/tests/wpt/metadata/css/css-animations/CSSAnimation-effect.tentative.html.ini @@ -17,3 +17,6 @@ [Setting a null effect on a running animation fires an animationend event] expected: FAIL + [Replacing the effect of a CSSAnimation causes subsequent changes to corresponding animation-* properties to be ignored] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-animations/CSSAnimation-pausing.tentative.html.ini b/tests/wpt/metadata/css/css-animations/CSSAnimation-pausing.tentative.html.ini index 2682df5da60..0662ba6816b 100644 --- a/tests/wpt/metadata/css/css-animations/CSSAnimation-pausing.tentative.html.ini +++ b/tests/wpt/metadata/css/css-animations/CSSAnimation-pausing.tentative.html.ini @@ -17,3 +17,21 @@ [play() is overridden by later setting "animation-play-state: paused"] expected: FAIL + [reverse() overrides animation-play-state when it starts playing the animation] + expected: FAIL + + [Setting the startTime to non-null does NOT override the animation-play-state if the animation is already running] + expected: FAIL + + [reverse() does NOT override animation-play-state if the animation is already running] + expected: FAIL + + [Setting the startTime to null overrides animation-play-state if the animation is already running] + expected: FAIL + + [Setting the startTime to non-null overrides animation-play-state if the animation is paused] + expected: FAIL + + [play() does NOT override the animation-play-state if there was an error] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-animations/KeyframeEffect-getKeyframes.tentative.html.ini b/tests/wpt/metadata/css/css-animations/KeyframeEffect-getKeyframes.tentative.html.ini index 52c4783152b..08053516bf1 100644 --- a/tests/wpt/metadata/css/css-animations/KeyframeEffect-getKeyframes.tentative.html.ini +++ b/tests/wpt/metadata/css/css-animations/KeyframeEffect-getKeyframes.tentative.html.ini @@ -71,3 +71,6 @@ [KeyframeEffect.getKeyframes() returns expected values for animations with CSS variables as keyframe values in a shorthand property] expected: FAIL + [KeyframeEffect.getKeyframes() reflects changes to @keyframes rules] + expected: FAIL + diff --git a/tests/wpt/metadata/css/css-animations/KeyframeEffect-setKeyframes.tentative.html.ini b/tests/wpt/metadata/css/css-animations/KeyframeEffect-setKeyframes.tentative.html.ini new file mode 100644 index 00000000000..55cfd751ecb --- /dev/null +++ b/tests/wpt/metadata/css/css-animations/KeyframeEffect-setKeyframes.tentative.html.ini @@ -0,0 +1,10 @@ +[KeyframeEffect-setKeyframes.tentative.html] + [KeyframeEffect.setKeyframes() causes subsequent changes to animation-timing-function to be ignored] + expected: FAIL + + [KeyframeEffect.setKeyframes() causes subsequent changes to @keyframes rules to be ignored] + expected: FAIL + + [KeyframeEffect.setKeyframes() should NOT cause subsequent changes to @keyframes rules to be ignored if it threw] + 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 70a00a101f6..e35a452a186 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: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/css/css-values/round-function.html.ini b/tests/wpt/metadata/css/css-values/round-function.html.ini index b272ffc2ac6..bde64751406 100644 --- a/tests/wpt/metadata/css/css-values/round-function.html.ini +++ b/tests/wpt/metadata/css/css-values/round-function.html.ini @@ -335,3 +335,63 @@ [round(to-zero, -18px, 10px) should be used-value-equivalent to -10px] expected: FAIL + [round(to-zero, 5, infinity) should equal 0⁺.] + expected: FAIL + + [round(up, -1, infinity should equal 0⁻.] + expected: FAIL + + [round(to-zero, -5, infinity) should equal 0⁻.] + expected: FAIL + + [round(up, -1 * 0, infinity should equal 0⁻.] + expected: FAIL + + [round(up, 0, infinity) should equal 0⁺.] + expected: FAIL + + [round(down, -1, infinity) should equal -Infinity.] + expected: FAIL + + [round(down, -1 * 0, infinity) should equal 0⁻.] + expected: FAIL + + [round(infinity, 5) should equal +Infinity.] + expected: FAIL + + [round(-infinity, 5) should equal -Infinity.] + expected: FAIL + + [round(down, 0, infinity) should equal 0⁺.] + expected: FAIL + + [round(-infinity, -5) should equal -Infinity.] + expected: FAIL + + [round(down, 1, infinity) should equal 0⁺.] + expected: FAIL + + [round(5, infinity) should equal 0⁺.] + expected: FAIL + + [round(up, 1, infinity) should equal +Infinity.] + expected: FAIL + + [round(infinity, -5) should equal +Infinity.] + expected: FAIL + + [round(5, -infinity) should equal 0⁺.] + expected: FAIL + + [round(to-zero, -5, -infinity) should equal 0⁻.] + expected: FAIL + + [round(to-zero, 5, -infinity) should equal 0⁺.] + expected: FAIL + + [round(-5, -infinity) should equal 0⁻.] + expected: FAIL + + [round(-5, infinity) should equal 0⁻.] + 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 new file mode 100644 index 00000000000..4c79907309b --- /dev/null +++ b/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini @@ -0,0 +1,4 @@ +[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 c884dc82eab..628b1fab770 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,6 +2,3 @@ [listeners are called when <iframe> is resized] expected: FAIL - [listeners are called correct number of times] - 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 597ed32e119..b01cf71e9c7 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,24 @@ [fetch(): separate response Content-Type: text/plain ] expected: NOTRUN - [<iframe>: combined response Content-Type: text/html;" text/plain] + [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] expected: FAIL - [<iframe>: separate response Content-Type: text/plain */*;charset=gbk] + [<iframe>: combined response Content-Type: text/html;x=" text/plain] expected: FAIL - [<iframe>: combined response Content-Type: text/html */*] + [<iframe>: combined response Content-Type: */* text/html] expected: FAIL - [<iframe>: separate response Content-Type: text/html */*;charset=gbk] + [<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html] expected: FAIL - [<iframe>: combined response Content-Type: text/html;x=" text/plain] + [<iframe>: separate response Content-Type: text/html;" text/plain] + expected: FAIL + + [<iframe>: separate response Content-Type: text/plain */*] + expected: FAIL + + [<iframe>: separate response Content-Type: text/html;x=" 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..d2df9b78483 100644 --- a/tests/wpt/metadata/fetch/content-type/script.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/script.window.js.ini @@ -56,6 +56,3 @@ [separate text/javascript x/x] expected: FAIL - [separate text/javascript;charset=windows-1252 text/javascript] - 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 cc50d2d2e03..30e1b851fd4 100644 --- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,9 +11,3 @@ [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] - expected: FAIL - - [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_3.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini deleted file mode 100644 index 51f8272a6de..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_3.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini index 6852d7663de..c12c0f8ae48 100644 --- a/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini +++ b/tests/wpt/metadata/html/interaction/focus/the-autofocus-attribute/skip-document-with-fragment.html.ini @@ -1,8 +1,4 @@ [skip-document-with-fragment.html] - expected: TIMEOUT [Autofocus elements in iframed documents with URL fragments should be skipped.] expected: FAIL - [Autofocus elements in top-level browsing context's documents with URI fragments should be skipped.] - expected: TIMEOUT - 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 ca40f8b0d74..f606d929563 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 @@ -32,3 +32,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 42281 more errors.\n\tMax AbsError of 1.9986916780471802e+0 at index of 17995.\n\t[17995\]\t9.9994289875030518e-1\t-9.9874877929687500e-1\t1.9986916780471802e+0\t2.0011956154322119e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 12348.\n\t[12348\]\t9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-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 44043 more errors.\n\tMax AbsError of 1.9962286949157715e+0 at index of 32177.\n\t[32177\]\t9.9879217147827148e-1\t-9.9743652343750000e-1\t1.9962286949157715e+0\t2.0013591321441684e+0\t3.0517578125000000e-5\n\tMax RelError of Infinity at index of 14112.\n\t[14112\]\t-9.5105654001235962e-1\t0.0000000000000000e+0\t9.5105654001235962e-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 9513f7b9674..6537c0f6d97 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 @@ -170,3 +170,9 @@ [X SNR (-254.56109005477157 dB) is not greater than or equal to 65.737. Got -254.56109005477157.] 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-1.5346258564356873e+24\t-7.3546999692916870e-1\t1.5346258564356873e+24\t2.0865920606459265e+24\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-3.0465973817666023e+24\t-9.8956179618835449e-1\t3.0465973817666023e+24\t3.0787338329972360e+24\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 3.0465973817666023e+24 at index of 38059.\n\tMax RelError of 3.0787338329972360e+24 at index of 38059.\n] + expected: FAIL + + [X SNR (-447.224261749694 dB) is not greater than or equal to 65.737. Got -447.224261749694.] + expected: FAIL + diff --git a/tests/wpt/metadata/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html.ini b/tests/wpt/metadata/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html.ini new file mode 100644 index 00000000000..e6fc13c33df --- /dev/null +++ b/tests/wpt/metadata/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html.ini @@ -0,0 +1,10 @@ +[suspended-context-messageport.https.html] + [offline before start] + expected: FAIL + + [offline on complete] + expected: FAIL + + [realtime suspended] + expected: FAIL + diff --git a/tests/wpt/web-platform-tests/IndexedDB/support.js b/tests/wpt/web-platform-tests/IndexedDB/support.js index d3b2bb7d121..8dbfa6f1e37 100644 --- a/tests/wpt/web-platform-tests/IndexedDB/support.js +++ b/tests/wpt/web-platform-tests/IndexedDB/support.js @@ -101,6 +101,16 @@ function assert_key_equals(actual, expected, description) { assert_equals(indexedDB.cmp(actual, expected), 0, description); } +// Usage: +// indexeddb_test( +// (test_object, db_connection, upgrade_tx, open_request) => { +// // Database creation logic. +// }, +// (test_object, db_connection, open_request) => { +// // Test logic. +// test_object.done(); +// }, +// 'Test case description'); function indexeddb_test(upgrade_func, open_func, description, options) { async_test(function(t) { options = Object.assign({upgrade_will_abort: false}, options); @@ -189,3 +199,13 @@ function keep_alive(tx, store_name) { keepSpinning = false; }; } + +// Returns a new function. After it is called |count| times, |func| +// will be called. +function barrier_func(count, func) { + let n = 0; + return () => { + if (++n === count) + func(); + }; +} diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-connections.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-connections.any.js new file mode 100644 index 00000000000..92d098d29c9 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-connections.any.js @@ -0,0 +1,72 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + }, + + (t, db1) => { + // Open a second connection to the same database. + const open_request = indexedDB.open(db1.name); + open_request.onerror = t.unreached_func('open() should succeed'); + open_request.onupgradeneeded = + t.unreached_func('second connection should not upgrade'); + open_request.onsuccess = t.step_func(() => { + const db2 = open_request.result; + t.add_cleanup(() => { db2.close(); }); + + const transaction1 = db1.transaction('store', 'readwrite'); + transaction1.onabort = t.unreached_func('transaction1 should complete'); + + const transaction2 = db2.transaction('store', 'readwrite'); + transaction2.onabort = t.unreached_func('transaction2 should complete'); + + let transaction1PutSuccess = false; + let transaction1Complete = false; + let transaction2PutSuccess = false; + + // Keep transaction1 alive for a while and ensure transaction2 + // doesn't start. + + let count = 0; + (function doTransaction1Put() { + const request = transaction1.objectStore('store').put(1, count++); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(evt => { + transaction1PutSuccess = true; + if (count < 5) { + doTransaction1Put(); + } + }); + }()); + + transaction1.oncomplete = t.step_func(evt => { + transaction1Complete = true; + assert_false( + transaction2PutSuccess, + 'transaction1 should complete before transaction2 put succeeds'); + }); + + const request = transaction2.objectStore('store').put(2, 0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(evt => { + transaction2PutSuccess = true; + assert_true( + transaction1Complete, + 'transaction2 put should not succeed before transaction1 completes'); + }); + + transaction2.oncomplete = t.step_func_done(evt => { + assert_true( + transaction1PutSuccess, + 'transaction1 put should succeed before transaction2 runs'); + assert_true( + transaction1Complete, + 'transaction1 should complete before transaction2 runs'); + assert_true( + transaction2PutSuccess, + 'transaction2 put should succeed before transaction2 completes'); + }); + }); + }, + "Check that readwrite transactions with overlapping scopes do not run in parallel."); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-databases.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-databases.any.js new file mode 100644 index 00000000000..06444417586 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-across-databases.any.js @@ -0,0 +1,72 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + }, + + (t, db1) => { + // Open a second database. + const db2name = db1.name + '-2'; + const delete_request = indexedDB.deleteDatabase(db2name); + delete_request.onerror = t.unreached_func('deleteDatabase() should succeed'); + const open_request = indexedDB.open(db2name, 1); + open_request.onerror = t.unreached_func('open() should succeed'); + open_request.onupgradeneeded = t.step_func(() => { + const db2 = open_request.result; + const store = db2.createObjectStore('store'); + }); + open_request.onsuccess = t.step_func(() => { + const db2 = open_request.result; + t.add_cleanup(() => { + db2.close(); + indexedDB.deleteDatabase(db2.name); + }); + + let transaction1PutSuccess = false; + let transaction2PutSuccess = false; + + const onTransactionComplete = barrier_func(2, t.step_func_done(() => { + assert_true(transaction1PutSuccess, + 'transaction1 should have executed at least one request'); + assert_true(transaction2PutSuccess, + 'transaction1 should have executed at least one request'); + })); + + + const transaction1 = db1.transaction('store', 'readwrite'); + transaction1.onabort = t.unreached_func('transaction1 should complete'); + transaction1.oncomplete = t.step_func(onTransactionComplete); + + const transaction2 = db2.transaction('store', 'readwrite'); + transaction2.onabort = t.unreached_func('transaction2 should complete'); + transaction2.oncomplete = t.step_func(onTransactionComplete); + + // Keep both transactions alive until each has reported at least one + // successful operation. + + function doTransaction1Put() { + const request = transaction1.objectStore('store').put(0, 0); + request.onerror = t.unreached_func('put request should succeed'); + request.onsuccess = t.step_func(() => { + transaction1PutSuccess = true; + if (!transaction2PutSuccess) + doTransaction1Put(); + }); + } + + function doTransaction2Put() { + const request = transaction2.objectStore('store').put(0, 0); + request.onerror = t.unreached_func('put request should succeed'); + request.onsuccess = t.step_func(() => { + transaction2PutSuccess = true; + if (!transaction1PutSuccess) + doTransaction2Put(); + }); + } + + doTransaction1Put(); + doTransaction2Put(); + }); + }, + "Check that transactions in different databases can run in parallel."); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-mixed-scopes.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-mixed-scopes.any.js new file mode 100644 index 00000000000..5f04a6a288d --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-mixed-scopes.any.js @@ -0,0 +1,63 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + db.createObjectStore('a'); + db.createObjectStore('b'); + db.createObjectStore('c'); + }, + + (t, db) => { + let transaction1Started = false; + let transaction1Complete = false; + let transaction2Started = false; + let transaction2Complete = false; + let transaction3Started = false; + let transaction3Complete = false; + + const transaction1 = db.transaction(['a'], 'readonly'); + let request = transaction1.objectStore('a').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + transaction1Started = true; + }); + transaction1.onabort = t.unreached_func('transaction1 should complete'); + transaction1.oncomplete = t.step_func(() => { + transaction1Complete = true; + assert_false(transaction2Started); + assert_false(transaction3Started); + }); + + + // transaction2 overlaps with transaction1, so must wait until transaction1 + // completes. + const transaction2 = db.transaction(['a', 'b'], 'readwrite'); + request = transaction2.objectStore('a').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + assert_true(transaction1Complete); + transaction2Started = true; + }); + transaction2.onabort = t.unreached_func('transaction2 should complete'); + transaction2.oncomplete = t.step_func(() => { + transaction2Complete = true; + assert_false(transaction3Started); + }); + + // transaction3 overlaps with transaction2, so must wait until transaction2 + // completes even though it does not overlap with transaction1. + const transaction3 = db.transaction(['b', 'c'], 'readonly'); + request = transaction3.objectStore('b').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + assert_true(transaction1Complete); + assert_true(transaction2Complete); + transaction3Started = true; + }); + transaction3.onabort = t.unreached_func('transaction3 should complete'); + transaction3.oncomplete = t.step_func_done(() => { + transaction3Complete = true; + }); + }, + "Check that scope restrictions on mixed transactions are enforced."); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ordering.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ordering.any.js new file mode 100644 index 00000000000..9f47e5c58ca --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ordering.any.js @@ -0,0 +1,40 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + }, + + (t, db) => { + // Create in order tx1, tx2. + const tx1 = db.transaction('store', 'readwrite'); + const tx2 = db.transaction('store', 'readwrite'); + + // Use in order tx2, tx1. + tx2.objectStore('store').get(0); + tx1.objectStore('store').get(0); + + const order = []; + const done = barrier_func(2, t.step_func_done(() => { + // IndexedDB Spec: + // https://w3c.github.io/IndexedDB/#transaction-scheduling + // + // If multiple "readwrite" transactions are attempting to + // access the same object store (i.e. if they have overlapping + // scope), the transaction that was created first must be the + // transaction which gets access to the object store first. + // + assert_array_equals(order, [1, 2]); + })); + + tx1.oncomplete = t.step_func(e => { + order.push(1); + done(); + }); + + tx2.oncomplete = t.step_func(e => { + order.push(2); + done(); + }); + }, + "Verify Indexed DB transactions are ordered per spec"); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ro-waits-for-rw.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ro-waits-for-rw.any.js new file mode 100644 index 00000000000..dca08b82088 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-ro-waits-for-rw.any.js @@ -0,0 +1,26 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + store.put('value', 'key'); + }, + + (t, db) => { + const transaction1 = db.transaction('store', 'readwrite'); + transaction1.onabort = t.unreached_func('transaction1 should not abort'); + + const transaction2 = db.transaction('store', 'readonly'); + transaction2.onabort = t.unreached_func('transaction2 should not abort'); + + const request = transaction1.objectStore('store').put('new value', 'key'); + request.onerror = t.unreached_func('request should not fail'); + + const request2 = transaction2.objectStore('store').get('key'); + request2.onerror = t.unreached_func('request2 should not fail'); + request2.onsuccess = t.step_func_done(evt => { + assert_equals(request2.result, 'new value', + 'Request should see new value.'); + }); + }, + "readonly transaction should see the result of a previous readwrite transaction"); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-rw-scopes.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-rw-scopes.any.js new file mode 100644 index 00000000000..7c6f61614b0 --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-rw-scopes.any.js @@ -0,0 +1,63 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + db.createObjectStore('a'); + db.createObjectStore('b'); + db.createObjectStore('c'); + }, + + (t, db) => { + let transaction1Started = false; + let transaction1Complete = false; + let transaction2Started = false; + let transaction2Complete = false; + let transaction3Started = false; + let transaction3Complete = false; + + const transaction1 = db.transaction(['a'], 'readwrite'); + let request = transaction1.objectStore('a').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + transaction1Started = true; + }); + transaction1.onabort = t.unreached_func('transaction1 should complete'); + transaction1.oncomplete = t.step_func(() => { + transaction1Complete = true; + assert_false(transaction2Started); + assert_false(transaction3Started); + }); + + + // transaction2 overlaps with transaction1, so must wait until transaction1 + // completes. + const transaction2 = db.transaction(['a', 'b'], 'readwrite'); + request = transaction2.objectStore('a').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + assert_true(transaction1Complete); + transaction2Started = true; + }); + transaction2.onabort = t.unreached_func('transaction2 should complete'); + transaction2.oncomplete = t.step_func(() => { + transaction2Complete = true; + assert_false(transaction3Started); + }); + + // transaction3 overlaps with transaction2, so must wait until transaction2 + // completes even though it does not overlap with transaction1. + const transaction3 = db.transaction(['b', 'c'], 'readwrite'); + request = transaction3.objectStore('b').get(0); + request.onerror = t.unreached_func('request should succeed'); + request.onsuccess = t.step_func(() => { + assert_true(transaction1Complete); + assert_true(transaction2Complete); + transaction3Started = true; + }); + transaction3.onabort = t.unreached_func('transaction3 should complete'); + transaction3.oncomplete = t.step_func_done(() => { + transaction3Complete = true; + }); + }, + "Check that scope restrictions on read-write transactions are enforced."); diff --git a/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-within-database.any.js b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-within-database.any.js new file mode 100644 index 00000000000..10dd8b6d7ac --- /dev/null +++ b/tests/wpt/web-platform-tests/IndexedDB/transaction-scheduling-within-database.any.js @@ -0,0 +1,55 @@ +// META: script=support.js + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + store.put('value', 'key'); + }, + + (t, db) => { + let transaction1GetSuccess = false; + let transaction2GetSuccess = false; + + const onTransactionComplete = barrier_func(2, t.step_func_done(() => { + assert_true(transaction1GetSuccess, + 'transaction1 should have executed at least one request'); + assert_true(transaction2GetSuccess, + 'transaction1 should have executed at least one request'); + })); + + const transaction1 = db.transaction('store', 'readonly'); + transaction1.onabort = t.unreached_func('transaction1 should not abort'); + transaction1.oncomplete = t.step_func(onTransactionComplete); + + const transaction2 = db.transaction('store', 'readonly'); + transaction2.onabort = t.unreached_func('transaction2 should not abort'); + transaction2.oncomplete = t.step_func(onTransactionComplete); + + // Keep both transactions alive until each has reported at least one + // successful operation + + function doTransaction1Get() { + const request = transaction1.objectStore('store').get('key'); + request.onerror = t.unreached_func('request should not fail'); + request.onsuccess = t.step_func(() => { + transaction1GetSuccess = true; + if (!transaction2GetSuccess) + doTransaction1Get(); + }); + } + + function doTransaction2Get() { + // NOTE: No logging since execution order is not deterministic. + const request = transaction2.objectStore('store').get('key'); + request.onerror = t.unreached_func('request should not fail'); + request.onsuccess = t.step_func(() => { + transaction2GetSuccess = true; + if (!transaction1GetSuccess) + doTransaction2Get(); + }); + } + + doTransaction1Get(); + doTransaction2Get(); + }, + 'Check that read-only transactions within a database can run in parallel.'); diff --git a/tests/wpt/web-platform-tests/content-security-policy/nonce-hiding/nonces.html b/tests/wpt/web-platform-tests/content-security-policy/nonce-hiding/nonces.html index b023d060323..7ee10a7b29e 100644 --- a/tests/wpt/web-platform-tests/content-security-policy/nonce-hiding/nonces.html +++ b/tests/wpt/web-platform-tests/content-security-policy/nonce-hiding/nonces.html @@ -3,30 +3,62 @@ <script src="/resources/testharnessreport.js"></script> <div id=log></div> <script> -[["meh", ""], - ["div", ""], - ["script", ""], - ["meh", "http://www.w3.org/2000/svg"], - ["svg", "http://www.w3.org/2000/svg"], - ["script", "http://www.w3.org/2000/svg"]].forEach(([localName, namespace]) => { - test(t => { - const element = namespace === "" ? document.createElement(localName) : document.createElementNS(namespace, localName); - t.add_cleanup(() => element.remove()); - assert_equals(element.nonce, "", "Initial IDL attribute value"); - element.setAttribute("nonce", "x"); - assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); - assert_equals(element.getAttribute("nonce"), "x", "Content attribute is modified after content attribute set"); - document.body.appendChild(element); - assert_equals(element.nonce, "x", "IDL attribute is unchanged after element insertion"); - assert_equals(element.getAttribute("nonce"), "", "Content attribute is changed after element insertion"); - }, `Basic nonce tests for ${localName} in ${namespace === "" ? "HTML" : "SVG"} namespace`); - - test(t => { - const element = namespace === "" ? document.createElement(localName) : document.createElementNS(namespace, localName); - element.setAttribute("nonce", "x"); - assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); - element.removeAttribute("nonce"); - assert_equals(element.nonce, "", "IDL attribute is empty after content attribute removal"); - }, `Ensure that removal of content attribute does not affect IDL attribute for ${localName} in ${namespace === "" ? "HTML" : "SVG"} namespace`); -}); + const namespace_url= { + "HTML": "http://www.w3.org/1999/xhtml", + "SVG": "http://www.w3.org/2000/svg", + } + const test_cases = [ + ["meh" , "HTML"], + ["div" , "HTML"], + ["script" , "HTML"], + ["meh" , "SVG"], + ["svg" , "SVG"], + ["script" , "SVG"], + ]; + + test_cases.forEach(([localName, namespace]) => { + test(t => { + const element = document.createElementNS(namespace_url[namespace], localName); + t.add_cleanup(() => element.remove()); + assert_equals(element.nonce, "", "Initial IDL attribute value"); + assert_equals(element.getAttribute("nonce"), null, "Initial content attribute"); + + element.setAttribute("nonce", "x"); + assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); + assert_equals(element.getAttribute("nonce"), "x", "Content attribute is modified after content attribute set"); + + document.body.appendChild(element); + assert_equals(element.nonce, "x", "IDL attribute is unchanged after element insertion"); + assert_equals(element.getAttribute("nonce"), "", "Content attribute is changed after element insertion"); + }, `Basic nonce tests for ${localName} in ${namespace} namespace`); + + test(t => { + const element = document.createElementNS(namespace_url[namespace], localName); + t.add_cleanup(() => element.remove()); + element.setAttribute("nonce", "x"); + assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); + + element.removeAttribute("nonce"); + assert_equals(element.nonce, "", "IDL attribute is empty after content attribute removal"); + }, `Ensure that removal of content attribute does not affect IDL attribute for ${localName} in ${namespace} namespace`); + + test(t => { + const element = document.createElementNS(namespace_url[namespace], localName); + t.add_cleanup(() => element.remove()); + assert_equals(element.nonce, ""); + assert_equals(element.getAttribute("nonce"), null); + + element.setAttribute("nonce", ""); + assert_equals(element.nonce, ""); + assert_equals(element.getAttribute("nonce"), ""); + + document.body.appendChild(element); + assert_equals(element.nonce, ""); + assert_equals(element.getAttribute("nonce"), ""); + + element.removeAttribute("nonce"); + assert_equals(element.nonce, ""); + assert_equals(element.getAttribute("nonce"), null); + }, `Test empty nonces for ${localName} in ${namespace} namespace`); + }); </script> diff --git a/tests/wpt/web-platform-tests/css/css-animations/AnimationEffect-updateTiming.tentative.html b/tests/wpt/web-platform-tests/css/css-animations/AnimationEffect-updateTiming.tentative.html new file mode 100644 index 00000000000..de6953c761f --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-animations/AnimationEffect-updateTiming.tentative.html @@ -0,0 +1,179 @@ +<!doctype html> +<meta charset=utf-8> +<title>AnimationEffect.updateTiming() for CSS animations</title> +<!-- TODO: Add a more specific link for this once it is specified. --> +<link rel="help" href="https://drafts.csswg.org/css-animations-2/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/testcommon.js"></script> +<style> +@keyframes anim-empty { } +</style> +<body> +<div id="log"></div> +<script> +"use strict"; + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ duration: 2 * MS_PER_SEC }); + + div.style.animationDuration = '4s'; + div.style.animationDelay = '6s'; + getComputedStyle(div).animationDuration; + + assert_equals( + animation.effect.getTiming().duration, + 2 * MS_PER_SEC, + 'Duration should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().delay, + 6 * MS_PER_SEC, + 'Delay should be the value set by style' + ); +}, 'AnimationEffect.updateTiming({ duration }) causes changes to the' + + ' animation-duration to be ignored'); + +// The above test covers duration (with delay as a control). The remaining +// properties are: +// +// iterations - animation-iteration-count +// direction - animation-direction +// delay - animation-delay +// fill - animation-fill-mode +// +// Which we test in two batches, overriding two properties each time and using +// the remaining two properties as control values to check they are NOT +// overridden. + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ iterations: 2, direction: 'reverse' }); + + div.style.animationIterationCount = '4'; + div.style.animationDirection = 'alternate'; + div.style.animationDelay = '6s'; + div.style.animationFillMode = 'both'; + getComputedStyle(div).animationIterationCount; + + assert_equals( + animation.effect.getTiming().iterations, + 2, + 'Iterations should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().direction, + 'reverse', + 'Direction should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().delay, + 6 * MS_PER_SEC, + 'Delay should be the value set by style' + ); + assert_equals( + animation.effect.getTiming().fill, + 'both', + 'Fill should be the value set by style' + ); +}, 'AnimationEffect.updateTiming({ iterations, direction }) causes changes to' + + ' the animation-iteration-count and animation-direction to be ignored'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ delay: 2 * MS_PER_SEC, fill: 'both' }); + + div.style.animationDelay = '4s'; + div.style.animationFillMode = 'forwards'; + div.style.animationIterationCount = '6'; + div.style.animationDirection = 'reverse'; + getComputedStyle(div).animationDelay; + + assert_equals( + animation.effect.getTiming().delay, + 2 * MS_PER_SEC, + 'Delay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().fill, + 'both', + 'Fill should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().iterations, + 6, + 'Iterations should be the value set by style' + ); + assert_equals( + animation.effect.getTiming().direction, + 'reverse', + 'Direction should be the value set by style' + ); +}, 'AnimationEffect.updateTiming({ delay, fill }) causes changes to' + + ' the animation-delay and animation-fill-mode to be ignored'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + assert_throws_js(TypeError, () => { + animation.effect.updateTiming({ duration: 2 * MS_PER_SEC, iterations: -1 }); + }, 'Negative iteration count should cause an error to be thrown'); + + div.style.animationDuration = '4s'; + getComputedStyle(div).animationDuration; + + assert_equals( + animation.effect.getTiming().duration, + 4 * MS_PER_SEC, + 'Duration should be the value set by style' + ); +}, 'AnimationEffect.updateTiming() does override to changes from animation-*' + + ' properties if there is an error'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ + easing: 'steps(4)', + endDelay: 2 * MS_PER_SEC, + iterationStart: 4, + }); + + div.style.animationDuration = '6s'; + div.style.animationTimingFunction = 'ease-in'; + getComputedStyle(div).animationDuration; + + assert_equals( + animation.effect.getTiming().easing, + 'steps(4)', + 'endDelay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().endDelay, + 2 * MS_PER_SEC, + 'endDelay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().iterationStart, + 4, + 'iterationStart should be the value set by style' + ); +}, 'AnimationEffect properties that do not map to animation-* properties' + + ' should not be changed when animation-* style is updated'); + +</script> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-effect.tentative.html b/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-effect.tentative.html index bbf35d5113a..95a90418720 100644 --- a/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-effect.tentative.html +++ b/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-effect.tentative.html @@ -128,4 +128,82 @@ promise_test(async t => { }, 'After replacing a finished animation\'s effect with a longer one ' + 'it fires an animationstart event'); +test(t => { + const div = addDiv(t); + + // Create custom keyframes so we can tweak them + const stylesheet = document.styleSheets[0]; + const keyframes = '@keyframes anim-custom { to { left: 100px } }'; + const ruleIndex = stylesheet.insertRule(keyframes, 0); + const keyframesRule = stylesheet.cssRules[ruleIndex]; + + t.add_cleanup(function() { + stylesheet.deleteRule(ruleIndex); + }); + + div.style.animation = 'anim-custom 100s'; + + // Replace the effect + const animation = div.getAnimations()[0]; + animation.effect = new KeyframeEffect( + div, + { left: '200px' }, + 200 * MS_PER_SEC + ); + + // Update the timing properties + div.style.animationDuration = '4s'; + div.style.animationIterationCount = '6'; + div.style.animationDirection = 'reverse'; + div.style.animationDelay = '8s'; + div.style.animationFillMode = 'both'; + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationDuration; + + // Update the keyframes + keyframesRule.deleteRule(0); + keyframesRule.appendRule('to { left: 300px }'); + + // Check nothing (except the play state) changed + assert_equals( + animation.effect.getTiming().duration, + 200 * MS_PER_SEC, + 'duration should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().iterations, + 1, + 'iterations should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().direction, + 'normal', + 'direction should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().delay, + 0, + 'delay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().fill, + 'auto', + 'fill should be the value set by the API' + ); + assert_equals( + animation.effect.getKeyframes()[0].left, + '200px', + 'keyframes should be the value set by the API' + ); + + // Unlike the other properties animation-play-state maps to the Animation + // not the KeyframeEffect so it should be overridden. + assert_equals( + animation.playState, + 'paused', + 'play state should be the value set by style' + ); +}, 'Replacing the effect of a CSSAnimation causes subsequent changes to' + + ' corresponding animation-* properties to be ignored'); + </script> diff --git a/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-pausing.tentative.html b/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-pausing.tentative.html index 2b6e6853b41..156a1afa964 100644 --- a/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-pausing.tentative.html +++ b/tests/wpt/web-platform-tests/css/css-animations/CSSAnimation-pausing.tentative.html @@ -16,129 +16,218 @@ <script> 'use strict'; -const getMarginLeft = cs => parseFloat(cs.marginLeft); - promise_test(async t => { const div = addDiv(t); - const cs = getComputedStyle(div); div.style.animation = 'anim 1000s paused'; + const animation = div.getAnimations()[0]; - assert_equals(getMarginLeft(cs), 0, - 'Initial value of margin-left is zero'); animation.play(); await animation.ready; await waitForNextFrame(); - assert_greater_than(getMarginLeft(cs), 0, - 'Playing value of margin-left is greater than zero'); + assert_equals( + animation.playState, + 'running', + 'Play state is running after calling play()' + ); + + // Flip the animation-play-state back and forth to check it has no effect + + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; + + assert_equals( + animation.playState, + 'running', + 'Should still be running even after flipping the animation-play-state' + ); }, 'play() overrides animation-play-state'); promise_test(async t => { const div = addDiv(t); - const cs = getComputedStyle(div); - div.style.animation = 'anim 1000s paused'; + div.style.animation = 'anim 100s infinite paused'; + const animation = div.getAnimations()[0]; - assert_equals(getMarginLeft(cs), 0, - 'Initial value of margin-left is zero'); + animation.playbackRate = -1; + animation.currentTime = -1; + assert_throws_dom('InvalidStateError', () => { + animation.play(); + }, 'Trying to play a reversed infinite animation should throw'); + + assert_equals( + animation.playState, + 'paused', + 'Animation should still be paused' + ); + + animation.playbackRate = 1; + div.style.animationPlayState = 'running'; + + assert_equals( + animation.playState, + 'running', + 'Changing the animation-play-state should play the animation' + ); +}, 'play() does NOT override the animation-play-state if there was an error'); + +promise_test(async t => { + const div = addDiv(t); + div.style.animation = 'anim 1000s paused'; + + const animation = div.getAnimations()[0]; animation.pause(); + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; await animation.ready; await waitForNextFrame(); - assert_equals(cs.animationPlayState, 'running', - 'animation-play-state is running'); - assert_equals(getMarginLeft(cs), 0, - 'Paused value of margin-left is zero'); + assert_equals(animation.playState, 'paused', 'playState is paused '); + + // Flip the animation-play-state back and forth to check it has no effect + + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; + + assert_equals( + animation.playState, + 'paused', + 'Should still be paused even after flipping the animation-play-state' + ); }, 'pause() overrides animation-play-state'); promise_test(async t => { const div = addDiv(t); - const cs = getComputedStyle(div); - div.style.animation = 'anim 1000s paused'; + div.style.animation = 'anim 100s paused'; + const animation = div.getAnimations()[0]; - assert_equals(getMarginLeft(cs), 0, - 'Initial value of margin-left is zero'); - animation.play(); + animation.reverse(); - await animation.ready; + assert_equals( + animation.playState, + 'running', + 'Play state is running after calling reverse()' + ); - div.style.animationPlayState = 'running'; - cs.animationPlayState; // Trigger style resolution - await waitForNextFrame(); + // Flip the animation-play-state back and forth to check it has no effect - assert_equals(cs.animationPlayState, 'running', - 'animation-play-state is running'); + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; div.style.animationPlayState = 'paused'; - await animation.ready; + getComputedStyle(div).animationPlayState; - assert_equals(cs.animationPlayState, 'paused', - 'animation-play-state is paused'); - const previousAnimVal = getMarginLeft(cs); - await waitForNextFrame(); - - assert_equals(getMarginLeft(cs), previousAnimVal, - 'Animated value of margin-left does not change when' - + ' paused by style'); -}, 'play() is overridden by later setting "animation-play-state: paused"'); + assert_equals( + animation.playState, + 'running', + 'Should still be running even after flipping the animation-play-state' + ); +}, 'reverse() overrides animation-play-state when it starts playing the' + + ' animation'); promise_test(async t => { const div = addDiv(t); - const cs = getComputedStyle(div); - div.style.animation = 'anim 1000s'; + div.style.animation = 'anim 100s'; + const animation = div.getAnimations()[0]; - assert_equals(getMarginLeft(cs), 0, - 'Initial value of margin-left is zero'); + animation.reverse(); + + assert_equals( + animation.playState, + 'running', + 'Play state is running after calling reverse()' + ); - // Set the specified style first. If implementations fail to - // apply the style changes first, they will ignore the redundant - // call to play() and fail to correctly override the pause style. div.style.animationPlayState = 'paused'; - animation.play(); - const previousAnimVal = getMarginLeft(cs); + getComputedStyle(div).animationPlayState; - await animation.ready; - await waitForNextFrame(); + assert_equals( + animation.playState, + 'paused', + 'Should be paused after changing the animation-play-state' + ); +}, 'reverse() does NOT override animation-play-state if the animation is' + + ' already running'); + +promise_test(async t => { + const div = addDiv(t); + div.style.animation = 'anim 100s'; + + const animation = div.getAnimations()[0]; + animation.startTime = null; + + assert_equals( + animation.playState, + 'paused', + 'Play state is paused after setting the start time to null' + ); + + // Flip the animation-play-state back and forth to check it has no effect + + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; - assert_equals(cs.animationPlayState, 'paused', - 'animation-play-state is paused'); - assert_greater_than(getMarginLeft(cs), previousAnimVal, - 'Playing value of margin-left is increasing'); -}, 'play() flushes pending changes to animation-play-state first'); + assert_equals( + animation.playState, + 'paused', + 'Should still be paused even after flipping the animation-play-state' + ); +}, 'Setting the startTime to null overrides animation-play-state if the' + + ' animation is already running'); promise_test(async t => { const div = addDiv(t); - const cs = getComputedStyle(div); - div.style.animation = 'anim 1000s paused'; + div.style.animation = 'anim 100s paused'; + const animation = div.getAnimations()[0]; - assert_equals(getMarginLeft(cs), 0, - 'Initial value of margin-left is zero'); - - // Unlike the previous test for play(), since calling pause() is sticky, - // we'll apply it even if the underlying style also says we're paused. - // - // We would like to test that implementations flush styles before running - // pause() but actually there's no style we can currently set that will - // change the behavior of pause(). That may change in the future - // (e.g. if we introduce animation-timeline or animation-playback-rate etc.). - // - // For now this just serves as a sanity check that we do the same thing - // even if we set style before calling the API. + animation.startTime = document.timeline.currentTime; + + assert_equals( + animation.playState, + 'running', + 'Play state is running after setting the start time to non-null' + ); + + // Flip the animation-play-state back and forth to check it has no effect + div.style.animationPlayState = 'running'; - animation.pause(); - const previousAnimVal = getMarginLeft(cs); + getComputedStyle(div).animationPlayState; + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; - await animation.ready; - await waitForNextFrame(); + assert_equals( + animation.playState, + 'running', + 'Should still be running even after flipping the animation-play-state' + ); +}, 'Setting the startTime to non-null overrides animation-play-state if the' + + ' animation is paused'); + +promise_test(async t => { + const div = addDiv(t); + div.style.animation = 'anim 100s'; + + const animation = div.getAnimations()[0]; + animation.startTime = document.timeline.currentTime; + + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; - assert_equals(cs.animationPlayState, 'running', - 'animation-play-state is running'); - assert_equals(getMarginLeft(cs), previousAnimVal, - 'Paused value of margin-left does not change'); -}, 'pause() applies pending changes to animation-play-state first'); -// (Note that we can't actually test for this; see comment above, in test-body.) + assert_equals( + animation.playState, + 'paused', + 'Should be paused after changing the animation-play-state' + ); +}, 'Setting the startTime to non-null does NOT override the' + + ' animation-play-state if the animation is already running'); promise_test(async t => { const div = addDiv(t, { style: 'animation: anim 1000s' }); diff --git a/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative.html b/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative.html index 591cc15a7ed..f7d767dea8c 100644 --- a/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative.html +++ b/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-getKeyframes.tentative.html @@ -164,20 +164,6 @@ const getKeyframes = elem => elem.getAnimations()[0].effect.getKeyframes(); -const assert_frames_equal = (a, b, name) => { - assert_equals(Object.keys(a).sort().toString(), - Object.keys(b).sort().toString(), - "properties on " + name); - for (const p in a) { - if (p === 'offset' || p === 'computedOffset') { - assert_approx_equals(a[p], b[p], 0.00001, - "value for '" + p + "' on " + name); - } else { - assert_equals(a[p], b[p], "value for '" + p + "' on " + name); - } - } -}; - // animation-timing-function values to test with, where the value // is exactly the same as its serialization, sorted by the order // getKeyframes() will group frames with the same easing function @@ -221,11 +207,9 @@ test(t => { test(t => { const div = addDiv(t); - div.style.animation = 'anim-simple 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", @@ -233,10 +217,7 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", color: "rgb(255, 255, 255)", composite: "auto" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for a simple' + ' animation'); @@ -292,11 +273,9 @@ test(t => { test(t => { const div = addDiv(t); - div.style.animation = 'anim-simple-shorthand 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -306,21 +285,16 @@ test(t => { marginBottom: "16px", marginLeft: "16px", marginRight: "16px", marginTop: "16px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for a simple' + ' animation that specifies a single shorthand property'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-omit-to 100s'; div.style.color = 'rgb(255, 255, 255)'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -328,21 +302,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(255, 255, 255)" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with a 0% keyframe and no 100% keyframe'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-omit-from 100s'; div.style.color = 'rgb(255, 255, 255)'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -350,21 +319,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(0, 0, 255)" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with a 100% keyframe and no 0% keyframe'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-omit-from-to 100s'; div.style.color = 'rgb(255, 255, 255)'; - const frames = getKeyframes(div); - assert_equals(frames.length, 3, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -374,21 +338,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(255, 255, 255)" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with no 0% or 100% keyframe but with a 50% keyframe'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-partially-omit-to 100s'; div.style.marginTop = '250px'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -396,21 +355,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", marginTop: '250px', marginBottom: '200px' }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with a partially complete 100% keyframe (because the ' + '!important rule is ignored)'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-different-props 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 4, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -422,21 +376,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(255, 255, 255)", marginTop: "16px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with different properties on different keyframes, all ' + 'with the same easing function'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-different-props-and-easing 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 4, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "linear", composite: "auto", @@ -448,21 +397,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(255, 255, 255)", marginTop: "16px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with different properties on different keyframes, with ' + 'a different easing function on each'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-merge-offset 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -470,21 +414,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(255, 255, 255)", marginTop: "16px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with multiple keyframes for the same time, and all with ' + 'the same easing function'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-merge-offset-and-easing 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 3, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "steps(1)", composite: "auto", @@ -495,21 +434,16 @@ test(t => { color: "rgb(255, 255, 255)", fontSize: "32px", marginTop: "16px", paddingLeft: "4px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with multiple keyframes for the same time and with ' + 'different easing functions'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-no-merge-equiv-easing 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 3, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "steps(1)", composite: "auto", @@ -519,21 +453,16 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", marginTop: "20px", marginRight: "20px", marginBottom: "20px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for an ' + 'animation with multiple keyframes for the same time and with ' + 'different but equivalent easing functions'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-overriding 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 6, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -549,10 +478,7 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", paddingTop: "70px" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected frames for ' + 'overlapping keyframes'); @@ -561,11 +487,9 @@ test(t => { test(t => { const div = addDiv(t); - div.style.animation = 'anim-filter 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -573,20 +497,15 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", filter: "blur(5px) sepia(60%) saturate(30%)" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with filter properties and missing keyframes'); test(t => { const div = addDiv(t); - div.style.animation = 'anim-filter-drop-shadow 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -594,10 +513,7 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", filter: "drop-shadow(rgb(255, 0, 0) 50px 30px 10px)" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animation with drop-shadow of filter property'); @@ -607,14 +523,12 @@ test(t => { test(t => { const div = addDiv(t); - div.style.textShadow = '1px 1px 2px rgb(0, 0, 0), ' + '0 0 16px rgb(0, 0, 255), ' + '0 0 3.2px rgb(0, 0, 255)'; div.style.animation = 'anim-text-shadow 100s'; - const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); + const frames = getKeyframes(div); const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", @@ -624,10 +538,7 @@ test(t => { { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", textShadow: "none" }, ]; - - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with text-shadow properties and missing keyframes'); @@ -673,17 +584,13 @@ test(t => { const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); - const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", transform: "none" }, { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", transform: "translate(100px)" }, ]; - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with CSS variables as keyframe values'); @@ -693,8 +600,6 @@ test(t => { const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); - const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", marginBottom: "0px", @@ -707,9 +612,7 @@ test(t => { marginRight: "100px", marginTop: "100px" }, ]; - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with CSS variables as keyframe values in a shorthand property'); @@ -719,17 +622,13 @@ test(t => { const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); - const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", color: "rgb(0, 0, 0)" }, { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", color: "rgb(0, 255, 0)" }, ]; - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with a CSS variable which is overriden by the value in keyframe'); @@ -739,19 +638,63 @@ test(t => { const frames = getKeyframes(div); - assert_equals(frames.length, 2, "number of frames"); - const expected = [ { offset: 0, computedOffset: 0, easing: "ease", composite: "auto", transform: "translate(100px)" }, { offset: 1, computedOffset: 1, easing: "ease", composite: "auto", transform: "none" }, ]; - for (let i = 0; i < frames.length; i++) { - assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i); - } + assert_frame_lists_equal(frames, expected); }, 'KeyframeEffect.getKeyframes() returns expected values for ' + 'animations with only custom property in a keyframe'); +test(t => { + const div = addDiv(t); + + // Add custom @keyframes rule + const stylesheet = document.styleSheets[0]; + const keyframes = '@keyframes anim-custom { to { left: 100px } }'; + const ruleIndex = stylesheet.insertRule(keyframes, 0); + const keyframesRule = stylesheet.cssRules[ruleIndex]; + + t.add_cleanup(function() { + stylesheet.deleteRule(ruleIndex); + }); + + div.style.animation = 'anim-custom 100s'; + + // Sanity check the initial result + let frames = getKeyframes(div); + assert_frames_equal( + frames[frames.length - 1], + { + offset: 1, + computedOffset: 1, + easing: 'ease', + composite: 'auto', + left: '100px', + }, + 'Keyframes reflect the initial @keyframes rule' + ); + + // Update the @keyframes rule + keyframesRule.deleteRule(0); + keyframesRule.appendRule('to { left: 200px }'); + + // Check the result from getKeyframes() is updated + frames = getKeyframes(div); + assert_frames_equal( + frames[frames.length - 1], + { + offset: 1, + computedOffset: 1, + easing: 'ease', + composite: 'auto', + left: '200px', + }, + 'Keyframes reflects the updated @keyframes rule' + ); +}, 'KeyframeEffect.getKeyframes() reflects changes to @keyframes rules'); + </script> </body> diff --git a/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative.html b/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative.html new file mode 100644 index 00000000000..7d8f845413a --- /dev/null +++ b/tests/wpt/web-platform-tests/css/css-animations/KeyframeEffect-setKeyframes.tentative.html @@ -0,0 +1,122 @@ +<!doctype html> +<meta charset=utf-8> +<title>KeyframeEffect.setKeyframes() for CSS animations</title> +<!-- TODO: Add a more specific link for this once it is specified. --> +<link rel="help" href="https://drafts.csswg.org/css-animations-2/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/testcommon.js"></script> +<style> +@keyframes anim-simple { + from { left: 0px } + to { left: 100px } +} +</style> +<body> +<div id="log"></div> +<script> +"use strict"; + +// Note that the sanity check that getKeyframes() normally DOES return the +// updated keyframes is contained in KeyframeEffect-getKeyframes.html. +test(t => { + const div = addDiv(t); + + // Add custom @keyframes rule + const stylesheet = document.styleSheets[0]; + const keyframes = '@keyframes anim-custom { to { left: 100px } }'; + const ruleIndex = stylesheet.insertRule(keyframes, 0); + const keyframesRule = stylesheet.cssRules[ruleIndex]; + + t.add_cleanup(function() { + stylesheet.deleteRule(ruleIndex); + }); + + div.style.animation = 'anim-custom 100s'; + + // Update the keyframes via the API + const animation = div.getAnimations()[0]; + animation.effect.setKeyframes({ left: '200px' }); + + // Then update them via style + keyframesRule.deleteRule(0); + keyframesRule.appendRule('to { left: 300px }'); + + // The result should be the keyframes as set by the API, not via style. + const frames = animation.effect.getKeyframes(); + assert_frames_equal( + frames[frames.length - 1], + { + offset: null, + computedOffset: 1, + easing: 'linear', + composite: 'auto', + left: '200px', + }, + 'Keyframes reflect the value set via setKeyframes' + ); +}, 'KeyframeEffect.setKeyframes() causes subsequent changes to @keyframes' + + ' rules to be ignored'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-simple 100s'; + + const animation = div.getAnimations()[0]; + assert_equals(animation.effect.getKeyframes()[0].easing, 'ease'); + + animation.effect.setKeyframes({ left: ['200px', '300px'] }); + assert_equals(animation.effect.getKeyframes()[0].easing, 'linear'); + + div.style.animationTimingFunction = 'ease-in'; + getComputedStyle(div).animationTimingFunction; + + assert_equals( + animation.effect.getKeyframes()[0].easing, + 'linear', + 'Easing should be the easing set by the API' + ); +}, 'KeyframeEffect.setKeyframes() causes subsequent changes to' + + ' animation-timing-function to be ignored'); + +test(t => { + const div = addDiv(t); + + const stylesheet = document.styleSheets[0]; + const keyframes = '@keyframes anim-custom { to { left: 100px } }'; + const ruleIndex = stylesheet.insertRule(keyframes, 0); + const keyframesRule = stylesheet.cssRules[ruleIndex]; + + t.add_cleanup(function() { + stylesheet.deleteRule(ruleIndex); + }); + + div.style.animation = 'anim-custom 100s'; + + // Try updating in a way that throws an error + const animation = div.getAnimations()[0]; + assert_throws_js(TypeError, () => { + animation.effect.setKeyframes({ left: '200px', offset: 'yer' }); + }); + + keyframesRule.deleteRule(0); + keyframesRule.appendRule('to { left: 300px }'); + + // The result should be the keyframes as set via style. + const frames = animation.effect.getKeyframes(); + assert_frames_equal( + frames[frames.length - 1], + { + offset: 1, + computedOffset: 1, + easing: 'ease', + composite: 'auto', + left: '300px', + }, + 'Keyframes reflect the value set via style' + ); +}, 'KeyframeEffect.setKeyframes() should NOT cause subsequent changes to' + + ' @keyframes rules to be ignored if it threw'); + +</script> +</body> diff --git a/tests/wpt/web-platform-tests/css/css-animations/support/testcommon.js b/tests/wpt/web-platform-tests/css/css-animations/support/testcommon.js index b4fde4b967d..7d63d2c49bc 100644 --- a/tests/wpt/web-platform-tests/css/css-animations/support/testcommon.js +++ b/tests/wpt/web-platform-tests/css/css-animations/support/testcommon.js @@ -36,6 +36,55 @@ function assert_time_equals_literal(actual, expected, description) { assert_approx_equals(actual, expected, TIME_PRECISION, description); } +/* + * Compare two keyframes + */ +function assert_frames_equal(actual, expected, name) { + // TODO: Make this skip the 'composite' member when it is not specified in + // `expected` or when the implementation does not support it. + assert_array_equals( + Object.keys(actual).sort(), + Object.keys(expected).sort(), + `properties on ${name} should match` + ); + + for (const prop in actual) { + if ( + // 'offset' can be null + (prop === 'offset' && typeof actual[prop] === 'number') || + prop === 'computedOffset' + ) { + assert_approx_equals( + actual[prop], + expected[prop], + 0.00001, + "value for '" + prop + "' on " + name + ); + } else { + assert_equals( + actual[prop], + expected[prop], + `value for '${prop}' on ${name} should match` + ); + } + } +} + +/* + * Compare two lists of keyframes + */ +function assert_frame_lists_equal(actual, expected) { + assert_equals( + actual.length, + expected.length, + 'Number of keyframes should match' + ); + + for (let i = 0; i < actual.length; i++) { + assert_frames_equal(actual[i], expected[i], `Keyframe #${i}`); + } +} + /** * Appends a div to the document body. * diff --git a/tests/wpt/web-platform-tests/css/css-values/round-function.html b/tests/wpt/web-platform-tests/css/css-values/round-function.html index 236b9a9a8a3..b1e950efe72 100644 --- a/tests/wpt/web-platform-tests/css/css-values/round-function.html +++ b/tests/wpt/web-platform-tests/css/css-values/round-function.html @@ -1,5 +1,6 @@ <!doctype html> <title>round() function</title> +<meta charset=utf-8> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="../support/numeric-testcommon.js"></script> diff --git a/tests/wpt/web-platform-tests/css/support/numeric-testcommon.js b/tests/wpt/web-platform-tests/css/support/numeric-testcommon.js index 56022d06399..996250d359d 100644 --- a/tests/wpt/web-platform-tests/css/support/numeric-testcommon.js +++ b/tests/wpt/web-platform-tests/css/support/numeric-testcommon.js @@ -35,16 +35,20 @@ function test_math_used(testString, expectedString, {base="123px", msg, prop="le All of these expect the testString to evaluate to a <number>. */ function test_plus_infinity(testString) { - test_math_used(`calc(1px * ${testString})`, "calc(infinity * 1px)"); + test_math_used(`calc(1px * ${testString})`, "calc(infinity * 1px)", + {msg:`${testString} should equal +Infinity.`}); } function test_minus_infinity(testString) { - test_math_used(`calc(1px * ${testString})`, "calc(-infinity * 1px)"); + test_math_used(`calc(1px * ${testString})`, "calc(-infinity * 1px)", + {msg:`${testString} should equal -Infinity.`}); } function test_plus_zero(testString) { - test_math_used(`calc(1px / ${testString})`, "calc(infinity * 1px)"); + test_math_used(`calc(1px / ${testString})`, "calc(infinity * 1px)", + {msg:`${testString} should equal 0⁺.`}); } function test_minus_zero(testString) { - test_math_used(`calc(1px / ${testString})`, "calc(-infinity * 1px)"); + test_math_used(`calc(1px / ${testString})`, "calc(-infinity * 1px)", + {msg:`${testString} should equal 0⁻.`}); } function test_nan(testString) { // Make sure that it's NaN, not an infinity, diff --git a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/dedicated-worker-cache-storage.https.html b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/dedicated-worker-cache-storage.https.html index 2559de839a3..dced705206f 100644 --- a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/dedicated-worker-cache-storage.https.html +++ b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/dedicated-worker-cache-storage.https.html @@ -5,6 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> <script> +// See also: ./shared-worker-cache-storage.https.html function remote(path) { const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN; @@ -12,11 +13,11 @@ function remote(path) { } const iframe_path = "./resources/iframe.html?pipe="; -const dedicated_worker_path = "./dedicated-worker.js?pipe="; +const dedicated_worker_path = "./universal-worker.js?pipe="; const ressource_path = "/images/blue.png?pipe="; const coep_header= { - "coep-none" : "|header(Cross-Origin-Embedder-Policy,none)", + "coep-none" : "", "coep-require-corp" : "|header(Cross-Origin-Embedder-Policy,require-corp)", } @@ -107,7 +108,7 @@ function check( iframe.contentWindow.postMessage(iframe_eval); const {data} = await iframe_response; - assert_equals(data == "success", loaded); + assert_equals(data === "success", loaded); }, `${iframe_coep} ${worker_coep} ${response_corp}`) } diff --git a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/dedicated-worker.js b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/universal-worker.js index 5d46edcde24..5d46edcde24 100644 --- a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/dedicated-worker.js +++ b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/resources/universal-worker.js diff --git a/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/service-worker-cache-storage.https.html b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/service-worker-cache-storage.https.html new file mode 100644 index 00000000000..873f06ce4ff --- /dev/null +++ b/tests/wpt/web-platform-tests/html/cross-origin-embedder-policy/service-worker-cache-storage.https.html @@ -0,0 +1,117 @@ +<!doctype html> +<html> +<title> Check enforcement of COEP in a ServiceWorker using CacheStorage. </title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +<script> +// See also: ./dedicated-worker-cache-storage.https.html + +function remote(path) { + const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN; + return new URL(path, REMOTE_ORIGIN); +} + +const iframe_path = "./resources/iframe.html?pipe="; +const service_worker_path = "./resources/universal-worker.js?pipe="; +const ressource_path = "/images/blue.png?pipe="; + +const coep_header= { + "coep-none" : "", + "coep-require-corp" : "|header(Cross-Origin-Embedder-Policy,require-corp)", +} + +const corp_header = { + "corp-undefined" : "", + "corp-cross-origin" : "|header(Cross-Origin-Resource-Policy,cross-origin)", +} + +// Send a message to the |worker| and wait for its response. +function executeCommandInServiceWorker(worker, command) { + const channel = new MessageChannel(); + const response = new Promise(resolve => channel.port1.onmessage = resolve); + worker.postMessage(command, [ channel.port2 ]); + return response; +} + +// Check enforcement of COEP in a ServiceWorker using CacheStorage. +// +// 1) Fetch a response from a document with COEP:none. Store it in the +// CacheStorage. The response is cross-origin without any CORS header. +// 2) From a ServiceWorker, retrieve the response from the CacheStorage. +// +// Test parameters: +// - |worker_coep| the COEP header of the ServiceWorker's script response. +// - |response_corp| the CORP header of the response. +// +// Test expectations: +// |loaded| is true whenever the worker is able to fetch the response from +// the CacheStorage. According to the specification: +// https://mikewest.github.io/corpp/#initialize-embedder-policy-for-global +// it must be false when: +// - |worker_coep| is 'coep-require-corp' and +// - |response-corp| is 'corp-undefined'. +function check( + // Test parameters: + worker_coep, + response_corp, + + // Test expectations: + loaded) { + + promise_test(async (t) => { + // 1) Fetch a response from a document with COEP:none. Store it in the + // CacheStorage. The response is cross-origin without any CORS header. + const resource_path = ressource_path + corp_header[response_corp]; + const resource_url = remote(resource_path); + const fetch_request = new Request(resource_url, {mode: 'no-cors'}); + const cache = await caches.open('v1'); + const fetch_response = await fetch(fetch_request); + await cache.put(fetch_request, fetch_response); + + // 2) Start a ServiceWorker. + const SCOPE= new URL(location.href).pathname; + const service_worker_allowed = `|header(service-worker-allowed,${SCOPE})`; + const SCRIPT = + service_worker_path + + coep_header[worker_coep] + + service_worker_allowed; + + const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE); + add_completion_callback(() => reg.unregister()); + + // Start talking to the ServiceWorker, no matter its state. + const worker = reg.installing || reg.waiting || reg.active; + + // 3) From the service worker, try to retrieve the response from the + // CacheStorage. + const response = executeCommandInServiceWorker(worker, ` + (async function() { + const cache = await caches.open('v1'); + const request = new Request('${resource_url}', { + mode: 'no-cors' + }); + try { + const response = await cache.match(request); + message.ports[0].postMessage('success'); + } catch(error) { + message.ports[0].postMessage('error'); + } + })() + `); + const {data} = await response; + assert_equals(data === "success", loaded); + }, `A ServiceWorker with ${worker_coep} use CacheStorage to get a ${response_corp} response.`) +} + +// ------------------------------------------------------ +// worker_coep , response_corp , loaded +// ------------------------------------------------------ +check("coep-none" , "corp-undefined" , true); +check("coep-none" , "corp-cross-origin" , true); +check("coep-require-corp" , "corp-undefined" , false); +check("coep-require-corp" , "corp-cross-origin" , true); + +</script> +</html> diff --git a/tests/wpt/web-platform-tests/interfaces/construct-stylesheets.idl b/tests/wpt/web-platform-tests/interfaces/construct-stylesheets.idl index fca2a3e2887..35121866f66 100644 --- a/tests/wpt/web-platform-tests/interfaces/construct-stylesheets.idl +++ b/tests/wpt/web-platform-tests/interfaces/construct-stylesheets.idl @@ -16,6 +16,6 @@ dictionary CSSStyleSheetInit { boolean disabled = false; }; -partial interface DocumentOrShadowRoot { +partial interface mixin DocumentOrShadowRoot { attribute FrozenArray<CSSStyleSheet> adoptedStyleSheets; }; diff --git a/tests/wpt/web-platform-tests/native-file-system/script-tests/FileSystemBaseHandle-IndexedDB.js b/tests/wpt/web-platform-tests/native-file-system/script-tests/FileSystemBaseHandle-IndexedDB.js index d7403ff5ea6..855e52f04dd 100644 --- a/tests/wpt/web-platform-tests/native-file-system/script-tests/FileSystemBaseHandle-IndexedDB.js +++ b/tests/wpt/web-platform-tests/native-file-system/script-tests/FileSystemBaseHandle-IndexedDB.js @@ -100,3 +100,27 @@ directory_test(async (t, root_dir) => { assert_equals(result.length, value.length); await assert_equals_cloned_handles(result, value); }, 'Store handle in IndexedDB and read using a cursor.'); + +directory_test(async (t, root_dir) => { + const handles = await create_file_system_handles(t, root_dir); + + const db = await createDatabase(t, db => { + const store = db.createObjectStore('store', {keyPath: 'key'}); + }); + t.add_cleanup(() => deleteAllDatabases(t)); + + const value = handles; + let tx = db.transaction('store', 'readwrite'); + let store = tx.objectStore('store'); + await promiseForRequest(t, store.put({key: 'key', value})); + await promiseForTransaction(t, tx); + + tx = db.transaction('store', 'readonly'); + store = tx.objectStore('store'); + const result = await promiseForRequest(t, store.get('key')); + await promiseForTransaction(t, tx); + + assert_true(Array.isArray(result.value), 'Result should be an array'); + assert_equals(result.value.length, value.length); + await assert_equals_cloned_handles(result.value, value); +}, 'Store handle in IndexedDB using inline keys.'); diff --git a/tests/wpt/web-platform-tests/resources/chromium/nfc-mock.js b/tests/wpt/web-platform-tests/resources/chromium/nfc-mock.js index 7832a8231ef..14bb8fdada3 100644 --- a/tests/wpt/web-platform-tests/resources/chromium/nfc-mock.js +++ b/tests/wpt/web-platform-tests/resources/chromium/nfc-mock.js @@ -26,6 +26,10 @@ function toMojoNDEFRecord(record) { nfcRecord.recordType = record.recordType; nfcRecord.mediaType = record.mediaType; nfcRecord.id = record.id; + if (record.recordType == 'text') { + nfcRecord.encoding = record.encoding == null? 'utf-8': record.encoding; + nfcRecord.lang = record.lang == null? 'en': record.lang; + } nfcRecord.data = toByteArray(record.data); if (record.data != null && record.data.records !== undefined) { // |record.data| may be an NDEFMessageInit, i.e. the payload is a message. @@ -72,6 +76,17 @@ function compareNDEFRecords(providedRecord, receivedRecord) { assert_not_equals(providedRecord.recordType, 'empty'); + if (providedRecord.recordType == 'text') { + assert_equals( + providedRecord.encoding == null? 'utf-8': providedRecord.encoding, + receivedRecord.encoding); + assert_equals(providedRecord.lang == null? 'en': providedRecord.lang, + receivedRecord.lang); + } else { + assert_equals(null, receivedRecord.encoding); + assert_equals(null, receivedRecord.lang); + } + assert_array_equals(toByteArray(providedRecord.data), new Uint8Array(receivedRecord.data)); } diff --git a/tests/wpt/web-platform-tests/tools/wpt/revlist.py b/tests/wpt/web-platform-tests/tools/wpt/revlist.py index c4cbc2943b7..1893fdefa83 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/revlist.py +++ b/tests/wpt/web-platform-tests/tools/wpt/revlist.py @@ -106,11 +106,14 @@ def get_parser(): type=int, help="maximum number of revisions to be returned by " "the command") + parser.add_argument("--verbose", action="store_true", help="debug logging") return parser def run_rev_list(**kwargs): # type: (**Any) -> None + if kwargs.get('verbose'): + logger.setLevel(logging.DEBUG) # "epoch_threshold" is a safety margin. After this time it is fine to # assume that any tags are created and pushed. epoch_threshold = 600 diff --git a/tests/wpt/web-platform-tests/web-nfc/resources/nfc-helpers.js b/tests/wpt/web-platform-tests/web-nfc/resources/nfc-helpers.js index 5bec071dfa7..b1753ddd1b3 100644 --- a/tests/wpt/web-platform-tests/web-nfc/resources/nfc-helpers.js +++ b/tests/wpt/web-platform-tests/web-nfc/resources/nfc-helpers.js @@ -192,7 +192,8 @@ function assertWebNDEFMessagesEqual(message, expectedMessage) { assert_equals(record.recordType, expectedRecord.recordType); assert_equals(record.mediaType, expectedRecord.mediaType); assert_equals(record.id, expectedRecord.id); - + assert_equals(record.encoding, expectedRecord.encoding); + assert_equals(record.lang, expectedRecord.lang); // Compares record data assert_array_equals(new Uint8Array(record.data), new Uint8Array(expectedRecord.data)); diff --git a/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html b/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html new file mode 100644 index 00000000000..5f5b10a251f --- /dev/null +++ b/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html @@ -0,0 +1,51 @@ +<!doctype html> +<title>Test MessagePort while AudioContext is not running</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +const get_node_and_message = async (context) => { + const node = new AudioWorkletNode(context, 'port-processor'); + return new Promise((resolve) => { + node.port.onmessage = (event) => resolve({node: node, event: event}); + }); +}; +const ping_for_message = async (node) => { + return new Promise((resolve) => { + node.port.onmessage = resolve; + node.port.postMessage('ping'); + }); +}; +const modulePath = 'processors/port-processor.js'; + +promise_test(async () => { + const realtime = new AudioContext(); + await realtime.audioWorklet.addModule(modulePath); + await realtime.suspend(); + const currentTime = realtime.currentTime; + let {node, event} = await get_node_and_message(realtime); + assert_equals(event.data.timeStamp, currentTime, 'created message time'); + event = await ping_for_message(node); + assert_equals(event.data.timeStamp, currentTime, 'pong time'); +}, 'realtime suspended'); + +let offline; +promise_test(async () => { + offline = new OfflineAudioContext({length: 128 + 1, sampleRate: 16384}); + await offline.audioWorklet.addModule(modulePath); + assert_equals(offline.currentTime, 0, 'time before start'); + let {node, event} = await get_node_and_message(offline); + assert_equals(event.data.timeStamp, 0, 'created time before start'); + event = await ping_for_message(node); + assert_equals(event.data.timeStamp, 0, 'pong time before start'); +}, 'offline before start'); + +promise_test(async () => { + await offline.startRendering(); + const expected = 2 * 128 / offline.sampleRate; + assert_equals(offline.currentTime, expected, 'time on complete'); + let {node, event} = await get_node_and_message(offline); + assert_equals(event.data.timeStamp, expected, "created time on complete"); + event = await ping_for_message(node); + assert_equals(event.data.timeStamp, expected, "pong time on complete"); +}, 'offline on complete'); +</script> diff --git a/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-authnrselection.https.html b/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-authnrselection.https.html index 5da0745734f..9497a001f0f 100644 --- a/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-authnrselection.https.html +++ b/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-authnrselection.https.html @@ -46,8 +46,6 @@ standardSetup(function() { authnrSelBadUvNull.userVerification = null; // authenticatorSelection bad values - new CreateCredentialsTest("options.publicKey.authenticatorSelection", []).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty array", TypeError); - new CreateCredentialsTest("options.publicKey.authenticatorSelection", null).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is null", TypeError); new CreateCredentialsTest("options.publicKey.authenticatorSelection", "").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty string", TypeError); new CreateCredentialsTest("options.publicKey.authenticatorSelection", "none").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is string", TypeError); @@ -65,10 +63,6 @@ standardSetup(function() { new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkTrue) .modify("options.publicKey.timeout", 300) .runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey true", "NotAllowedError"); - new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkBadString) - .modify("options.publicKey.timeout", 300) - .runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey is string", TypeError); - // TODO: not sure if rk is "boolean" or "truthy"; add test cases if it should only accept boolean values // authenticatorSelection bad userVerification values new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty string", TypeError); diff --git a/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-rp.https.html b/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-rp.https.html index cbd86b8f083..8886cc15c92 100644 --- a/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-rp.https.html +++ b/tests/wpt/web-platform-tests/webauthn/createcredential-badargs-rp.https.html @@ -21,7 +21,6 @@ standardSetup(function() { new CreateCredentialsTest("options.publicKey.rp", {}).runTest("Bad rp: rp is empty object", TypeError); // // rp.id - new CreateCredentialsTest("options.publicKey.rp.id", {}).runTest("Bad rp: id is object", TypeError); new CreateCredentialsTest("options.publicKey.rp.id", null).runTest("Bad rp: id is null", "SecurityError"); new CreateCredentialsTest("options.publicKey.rp.id", "").runTest("Bad rp: id is empty String", "SecurityError"); new CreateCredentialsTest("options.publicKey.rp.id", "invalid domain.com").runTest("Bad rp: id is invalid domain (has space)", "SecurityError"); @@ -30,17 +29,10 @@ standardSetup(function() { // // rp.name new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", TypeError); - new CreateCredentialsTest("options.publicKey.rp.name", {}).runTest("Bad rp: name is object", TypeError); - new CreateCredentialsTest("options.publicKey.rp.name", null).runTest("Bad rp: name is null", TypeError); - new CreateCredentialsTest("options.publicKey.rp.name", "").runTest("Bad rp: name is empty String", TypeError); - // // rp.icon - new CreateCredentialsTest("options.publicKey.rp.icon", {}).runTest("Bad rp: icon is object", TypeError); - new CreateCredentialsTest("options.publicKey.rp.icon", null).runTest("Bad rp: icon is null", TypeError); - new CreateCredentialsTest("options.publicKey.rp.icon", "").runTest("Bad rp: icon is empty String", TypeError); + // rp.icon new CreateCredentialsTest("options.publicKey.rp.icon", "http://fidoalliance.co.nz/testimages/catimage.png") .runTest("Bad rp: icon is insecure", "SecurityError"); - // // TODO: unicode tests for icon URL (see also: USVString) }); /* JSHINT */ diff --git a/tests/wpt/web-platform-tests/webauthn/createcredential-excludecredentials.https.html b/tests/wpt/web-platform-tests/webauthn/createcredential-excludecredentials.https.html index 3a5af481fca..2b1eec19b7b 100644 --- a/tests/wpt/web-platform-tests/webauthn/createcredential-excludecredentials.https.html +++ b/tests/wpt/web-platform-tests/webauthn/createcredential-excludecredentials.https.html @@ -45,7 +45,7 @@ standardSetup(function() { } }; var p = createCredential(args); - return promise_rejects_dom(t, "NotAllowedError", p, "expected to fail on excluded credenetial"); + return promise_rejects_dom(t, "InvalidStateError", p, "expected to fail on excluded credential"); }); }, "exclude existing credential"); diff --git a/tests/wpt/web-platform-tests/webauthn/createcredential-extensions.https.html b/tests/wpt/web-platform-tests/webauthn/createcredential-extensions.https.html index 036200dbbf9..46cab3051b4 100644 --- a/tests/wpt/web-platform-tests/webauthn/createcredential-extensions.https.html +++ b/tests/wpt/web-platform-tests/webauthn/createcredential-extensions.https.html @@ -21,15 +21,6 @@ standardSetup(function() { // bad extension values new CreateCredentialsTest("options.publicKey.extensions", "hi mom").runTest("Bad extensions: extensions is string", TypeError); - new CreateCredentialsTest("options.publicKey.extensions", null).runTest("Bad extensions: extensions is null", TypeError); - new CreateCredentialsTest("options.publicKey.extensions", []).runTest("Bad extensions: extensions is empty Array", TypeError); - new CreateCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0)).runTest("Bad extensions: extensions is empty ArrayBuffer", TypeError); - var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar" - new CreateCredentialsTest("options.publicKey.extensions", {foo: badJson}).runTest("Bad extensions: malformatted JSON", TypeError); - new CreateCredentialsTest("options.publicKey.extensions", {foo: dummyExtension}).runTest("Bad extensions: JavaScript object", TypeError); - var badExtId = {}; - badExtId[createRandomString(65)] = dummyExtension; - new CreateCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension}).runTest("Bad extensions: extension ID too long", TypeError); // phony extensions // TODO: not sure if this should pass or fail diff --git a/tests/wpt/web-platform-tests/webauthn/createcredential-pubkeycredparams.https.html b/tests/wpt/web-platform-tests/webauthn/createcredential-pubkeycredparams.https.html index c845a906875..d1df7952d67 100644 --- a/tests/wpt/web-platform-tests/webauthn/createcredential-pubkeycredparams.https.html +++ b/tests/wpt/web-platform-tests/webauthn/createcredential-pubkeycredparams.https.html @@ -42,10 +42,10 @@ standardSetup(function() { new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyObj]).runTest("Bad pubKeyCredParams: first param has bad type (empty object)", TypeError); new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlg]) .modify("options.publicKey.timeout", 300) - .runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotSupportedError"); + .runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotAllowedError"); new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlgZero]) .modify("options.publicKey.timeout", 300) - .runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotSupportedError"); + .runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotAllowedError"); // TODO: come back to this when mock authenticators support multiple cryptos so that we can test the preference ranking // function verifyEC256(res) { |