diff --git a/test/fixtures/wpt/FileAPI/BlobURL/cross-partition-navigation.tentative.https.html b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition-navigation.tentative.https.html new file mode 100644 index 00000000000000..80d3f6818b4d82 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition-navigation.tentative.https.html @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html index c75ce07d054eb7..5cdaad5f0af2d5 100644 --- a/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html +++ b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html @@ -13,31 +13,54 @@ - + \ No newline at end of file diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js b/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js index 6dc44e8e156cce..57a85624340e56 100644 --- a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js +++ b/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js @@ -290,14 +290,22 @@ test_blob(function() { new Int16Array([0x4150, 0x5353]), new Uint32Array([0x53534150]), new Int32Array([0x53534150]), - new Float16Array([2.65625, 58.59375]), new Float32Array([0xD341500000]) ]); }, { - expected: "PASSPASSPASSPASSPASSPASSPASSPASS", + expected: "PASSPASSPASSPASSPASSPASSPASS", type: "", desc: "Passing typed arrays as elements of the blobParts array should work." }); +test_blob(function() { + return new Blob([ + new Float16Array([2.65625, 58.59375]) + ]); +}, { + expected: "PASS", + type: "", + desc: "Passing a Float16Array as element of the blobParts array should work." +}); test_blob(function() { return new Blob([ // 0x535 3415053534150 diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js index d06e3170782b7c..88c4f4d26cc0b2 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js @@ -7,6 +7,7 @@ reader.onload = this.step_func(function(evt) { assert_equals(reader.result.byteLength, 4, "The byteLength is 4"); assert_true(reader.result instanceof ArrayBuffer, "The result is instanceof ArrayBuffer"); + assert_array_equals(new Uint8Array(reader.result), [84, 69, 83, 84]); assert_equals(reader.readyState, reader.DONE); this.done(); }); diff --git a/test/fixtures/wpt/FileAPI/support/Blob.js b/test/fixtures/wpt/FileAPI/support/Blob.js index 2c249746858918..e8a52425a17085 100644 --- a/test/fixtures/wpt/FileAPI/support/Blob.js +++ b/test/fixtures/wpt/FileAPI/support/Blob.js @@ -5,23 +5,16 @@ self.test_blob = (fn, expectations) => { type = expectations.type, desc = expectations.desc; - var t = async_test(desc); - t.step(function() { + promise_test(async (t) => { var blob = fn(); assert_true(blob instanceof Blob); assert_false(blob instanceof File); assert_equals(blob.type, type); assert_equals(blob.size, expected.length); - var fr = new FileReader(); - fr.onload = t.step_func_done(function(event) { - assert_equals(this.result, expected); - }, fr); - fr.onerror = t.step_func(function(e) { - assert_unreached("got error event on FileReader"); - }); - fr.readAsText(blob, "UTF-8"); - }); + const text = await blob.text(); + assert_equals(text, expected); + }, desc); } self.test_blob_binary = (fn, expectations) => { @@ -29,25 +22,18 @@ self.test_blob_binary = (fn, expectations) => { type = expectations.type, desc = expectations.desc; - var t = async_test(desc); - t.step(function() { + promise_test(async (t) => { var blob = fn(); assert_true(blob instanceof Blob); assert_false(blob instanceof File); assert_equals(blob.type, type); assert_equals(blob.size, expected.length); - var fr = new FileReader(); - fr.onload = t.step_func_done(function(event) { - assert_true(this.result instanceof ArrayBuffer, - "Result should be an ArrayBuffer"); - assert_array_equals(new Uint8Array(this.result), expected); - }, fr); - fr.onerror = t.step_func(function(e) { - assert_unreached("got error event on FileReader"); - }); - fr.readAsArrayBuffer(blob); - }); + const ab = await blob.arrayBuffer(); + assert_true(ab instanceof ArrayBuffer, + "Result should be an ArrayBuffer"); + assert_array_equals(new Uint8Array(ab), expected); + }, desc); } // Assert that two TypedArray objects have the same byte values diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index eacd81cd69f712..1c67432d7c01e3 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -10,32 +10,32 @@ See [test/wpt](../../wpt/README.md) for information on how these tests are run. Last update: -- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common -- compression: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/compression -- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console +- common: https://github.com/web-platform-tests/wpt/tree/d8da9d4d1d/common +- compression: https://github.com/web-platform-tests/wpt/tree/da8d6860b2/compression +- console: https://github.com/web-platform-tests/wpt/tree/e48251b778/console - dom/abort: https://github.com/web-platform-tests/wpt/tree/0143fe244b/dom/abort -- dom/events: https://github.com/web-platform-tests/wpt/tree/0a811c5161/dom/events -- encoding: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/encoding +- dom/events: https://github.com/web-platform-tests/wpt/tree/922a7fe9a4/dom/events +- encoding: https://github.com/web-platform-tests/wpt/tree/1ac8deee08/encoding - fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources -- FileAPI: https://github.com/web-platform-tests/wpt/tree/cceaf3628d/FileAPI -- hr-time: https://github.com/web-platform-tests/wpt/tree/34cafd797e/hr-time +- FileAPI: https://github.com/web-platform-tests/wpt/tree/f389d335f2/FileAPI +- hr-time: https://github.com/web-platform-tests/wpt/tree/614e81711c/hr-time - html/webappapis/atob: https://github.com/web-platform-tests/wpt/tree/f267e1dca6/html/webappapis/atob -- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing -- html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/47d3fb280c/html/webappapis/structured-clone -- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/5873f2d8f1/html/webappapis/timers -- interfaces: https://github.com/web-platform-tests/wpt/tree/e90ece61d6/interfaces -- performance-timeline: https://github.com/web-platform-tests/wpt/tree/17ebc3aea0/performance-timeline -- resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing -- resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources -- streams: https://github.com/web-platform-tests/wpt/tree/2bd26e124c/streams -- url: https://github.com/web-platform-tests/wpt/tree/6a39784534/url +- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/22ecfc9bac/html/webappapis/microtask-queuing +- html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/c29dcddf37/html/webappapis/structured-clone +- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/f161ff1fa3/html/webappapis/timers +- interfaces: https://github.com/web-platform-tests/wpt/tree/ce686591dc/interfaces +- performance-timeline: https://github.com/web-platform-tests/wpt/tree/94caab7038/performance-timeline +- resource-timing: https://github.com/web-platform-tests/wpt/tree/7bb012885c/resource-timing +- resources: https://github.com/web-platform-tests/wpt/tree/783e382187/resources +- streams: https://github.com/web-platform-tests/wpt/tree/699dbdae30/streams +- url: https://github.com/web-platform-tests/wpt/tree/08519e73d1/url - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing -- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi -- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/203d2ac459/WebCryptoAPI +- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/f427091001/wasm/jsapi +- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/28456b73ca/wasm/webapi +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/4f0be15407/WebCryptoAPI - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions -- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/e97fac4791/webmessaging/broadcastchannel -- webstorage: https://github.com/web-platform-tests/wpt/tree/9dafa89214/webstorage +- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel +- webstorage: https://github.com/web-platform-tests/wpt/tree/1291340aaa/webstorage [Web Platform Tests]: https://github.com/web-platform-tests/wpt [`git node wpt`]: https://github.com/nodejs/node-core-utils/blob/main/docs/git-node.md#git-node-wpt diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js new file mode 100644 index 00000000000000..423d399f19def4 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDH.https.any.js @@ -0,0 +1,10 @@ +// META: title=WebCryptoAPI: importKey() for Failures +// META: timeout=long +// META: script=../util/helpers.js +// META: script=ec_importKey_failures_fixtures.js +// META: script=importKey_failures.js + +// Setup: define the correct behaviors that should be sought, and create +// helper functions that generate all possible test parameters for +// different situations. +run_test(["ECDH"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js new file mode 100644 index 00000000000000..527940798a42a5 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_ECDSA.https.any.js @@ -0,0 +1,10 @@ +// META: title=WebCryptoAPI: importKey() for Failures +// META: timeout=long +// META: script=../util/helpers.js +// META: script=ec_importKey_failures_fixtures.js +// META: script=importKey_failures.js + +// Setup: define the correct behaviors that should be sought, and create +// helper functions that generate all possible test parameters for +// different situations. +run_test(["ECDSA"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js new file mode 100644 index 00000000000000..796db364c2e2dc --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey_failures_fixtures.js @@ -0,0 +1,203 @@ +// Setup: define the correct behaviors that should be sought, and create +// helper functions that generate all possible test parameters for +// different situations. +function getValidKeyData(algorithm) { + return validKeyData[algorithm.namedCurve]; +} + +function getBadKeyLengthData(algorithm) { + return badKeyLengthData[algorithm.namedCurve]; +} + +function getMissingJWKFieldKeyData(algorithm) { + // The curve doesn't affect when testing for missing JWK fields. + return missingJWKFieldKeyData["P-521"]; +} + +function getMismatchedJWKKeyData(algorithm) { + // TODO: Implement test cases where the public key doesn't match the private key. + return []; +} + +var validKeyData = { + "P-521": [ + { + format: "spki", + data: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + }, + { + format: "raw", + data: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + }, + { + format:"pkcs8", + data: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-521", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + } + ], + "P-256": [ + { + format: "spki", + data: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + }, + { + format: "raw", + data: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-256", + x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE", + y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", + d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" + } + }, + ], + "P-384": [ + { + format: "spki", + data: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + }, + { + format: "raw", + data: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-384", + x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1", + y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", + d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" + } + } + ] +}; + +// Removed just the last byte. +var badKeyLengthData = { + "P-521": [ + { + format: "spki", + data: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), + }, + { + format: "raw", + data: new Uint8Array([4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), + }, + { + format:"pkcs8", + data: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-521", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + } + ], + "P-256": [ + { + format: "spki", + data: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), + }, + { + format: "raw", + data: new Uint8Array([4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-256", + x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXd", + y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", + d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" + } + }, + ], + "P-384": [ + { + format: "spki", + data: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), + }, + { + format: "raw", + data: new Uint8Array([4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172]), + }, + { + format: "jwk", + data: { + kty: "EC", + crv: "P-384", + x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ", + y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", + d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" + } + } + ] +}; + +var missingJWKFieldKeyData = { + "P-521": [ + { + param: "x", + data: { + kty: "EC", + crv: "P-521", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + }, + { + param: "kty", + data: { + crv: "P-521", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + }, + { + param: "crv", + data: { + kty: "EC", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + } + ] +}; diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js similarity index 86% rename from test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js rename to test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js index ebdb73616d6581..bba48401e616a5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/importKey_failures.js @@ -20,8 +20,10 @@ function run_test(algorithmNames) { var allTestVectors = [ // Parameters that should work for importKey / exportKey {name: "Ed25519", privateUsages: ["sign"], publicUsages: ["verify"]}, {name: "Ed448", privateUsages: ["sign"], publicUsages: ["verify"]}, + {name: "ECDSA", privateUsages: ["sign"], publicUsages: ["verify"]}, {name: "X25519", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}, {name: "X448", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}, + {name: "ECDH", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []} ]; var testVectors = []; @@ -109,6 +111,10 @@ function run_test(algorithmNames) { return []; } + function isPrivateKey(data) { + return data.d !== undefined; + } + // Now test for properly handling errors // - Unsupported algorithm // - Bad usages for algorithm @@ -121,8 +127,8 @@ function run_test(algorithmNames) { // due to SyntaxError testVectors.forEach(function(vector) { var name = vector.name; - validKeyData.forEach(function(test) { - allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + getValidKeyData(algorithm).forEach(function(test) { invalidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, usages, extractable, "SyntaxError", "Bad usages"); @@ -136,8 +142,8 @@ function run_test(algorithmNames) { // Should fail due to SyntaxError testVectors.forEach(function(vector) { var name = vector.name; - validKeyData.filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && test.data.d)).forEach(function(test) { - allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + getValidKeyData(algorithm).filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && isPrivateKey(test.data))).forEach(function(test) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, [/* Empty usages */], extractable, "SyntaxError", "Empty usages"); }); @@ -145,11 +151,11 @@ function run_test(algorithmNames) { }); }); - // Algorithms normalize okay, usages ok. The length of the key must thouw a DataError exception. + // Algorithms normalize okay, usages ok. The length of the key must throw a DataError exception. testVectors.forEach(function(vector) { var name = vector.name; - badKeyLengthData.forEach(function(test) { - allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + getBadKeyLengthData(algorithm).forEach(function(test) { allValidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, usages, extractable, "DataError", "Bad key length"); @@ -159,11 +165,11 @@ function run_test(algorithmNames) { }); }); - // Algorithms normalize okay, usages ok and valid key. The lack of the mandatory JWK parameter must throw a syntax error. + // Algorithms normalize okay, usages ok and valid key. The lack of the mandatory JWK parameter must throw a DataError exception. testVectors.forEach(function(vector) { var name = vector.name; - missingJWKFieldKeyData.forEach(function(test) { - allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + getMissingJWKFieldKeyData(algorithm).forEach(function(test) { allValidUsages(validUsages(vector, 'jwk', test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError('jwk', algorithm, test.data, name, usages, extractable, "DataError", "Missing JWK '" + test.param + "' parameter"); @@ -176,8 +182,8 @@ function run_test(algorithmNames) { // Algorithms normalize okay, usages ok and valid key. The public key is not compatible with the private key. testVectors.forEach(function(vector) { var name = vector.name; - invalidJWKKeyData.forEach(function(data) { - allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + getMismatchedJWKKeyData(algorithm).forEach(function(data) { allValidUsages(vector.privateUsages).forEach(function(usages) { [true].forEach(function(extractable) { testError('jwk', algorithm, data, name, usages, extractable, "DataError", "Invalid key pair"); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js index 7453a3a55052b3..e07b796df83d19 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed25519.https.any.js @@ -1,110 +1,7 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js -// META: script=okp_importKey_failures.js - -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. -var validKeyData = [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]) - }, - { - format: "raw", - data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) - }, - { - format: "jwk", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed25519", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - }, - }, -]; - -// Removed just the last byte. -var badKeyLengthData = [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168]) - }, - { - format: "raw", - data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) - }, - { - format: "jwk", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", - kty: "OKP" - } - }, - { - format: "jwk", - data: { - crv: "Ed25519", - x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPc", - kty: "OKP" - } - }, -]; - -var missingJWKFieldKeyData = [ - { - param: "x", - data: { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - kty: "OKP" - }, - }, - { - param: "kty", - data: { - crv: "Ed25519", - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - }, - }, - { - param: "crv", - data: { - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - kty: "OKP" - }, - } -]; - -// The public key doesn't match the private key. -var invalidJWKKeyData = [ - { - crv: "Ed25519", - d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", - x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - kty: "OKP" - }, -]; +// META: script=okp_importKey_failures_fixtures.js +// META: script=importKey_failures.js run_test(["Ed25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js index db2d47827af329..8ff3de5c79d3ab 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js @@ -1,111 +1,8 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js -// META: script=okp_importKey_failures.js +// META: script=okp_importKey_failures_fixtures.js +// META: script=importKey_failures.js -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. -var validKeyData = [ - { - format: "spki", - data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]), - }, - { - format: "raw", - data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), - }, - { - format: "jwk", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed448", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, -]; - -// Removed just the last byte. -var badKeyLengthData = [ - { - format: "spki", - data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29]), - }, - { - format: "raw", - data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), - }, - { - format: "jwk", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "Ed448", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalq", - kty: "OKP" - }, - }, -]; - -var missingJWKFieldKeyData = [ - { - param: "x", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - kty: "OKP" - } - }, - { - param: "kty", - data: { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - } - }, - { - param: "crv", - data: { - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", - kty: "OKP" - } - } -]; - -// The public key doesn't match the private key. -var invalidJWKKeyData = [ - { - crv: "Ed448", - d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", - x: "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA", - kty: "OKP" - }, -]; run_test(["Ed448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js index d4d099f7656033..a0116bee888512 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.js @@ -1,110 +1,8 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js -// META: script=okp_importKey_failures.js +// META: script=okp_importKey_failures_fixtures.js +// META: script=importKey_failures.js -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. -var validKeyData = [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]), - }, - { - format: "raw", - data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), - }, - { - format: "jwk", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X25519", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, -]; - -// Removed just the last byte. -var badKeyLengthData = [ - { - format: "spki", - data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255]), - }, - { - format: "raw", - data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), - }, - { - format: "jwk", - data: { - crv: "X25519", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lw", - kty: "OKP" - } - }, - { - format: "jwk", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - }, -]; - -var missingJWKFieldKeyData = [ - { - param: "x", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - kty: "OKP" - }, - }, - { - param: "kty", - data: { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - }, - }, - { - param: "crv", - data: { - x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", - kty: "OKP" - }, - } -]; - -// The public key doesn't match the private key. -var invalidJWKKeyData = [ - { - crv: "X25519", - d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", - x: "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo", - kty: "OKP" - }, -]; run_test(["X25519"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js index d8ac902e672566..eccce68fac731c 100644 --- a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js @@ -1,111 +1,8 @@ // META: title=WebCryptoAPI: importKey() for Failures // META: timeout=long // META: script=../util/helpers.js -// META: script=okp_importKey_failures.js +// META: script=okp_importKey_failures_fixtures.js +// META: script=importKey_failures.js -// Setup: define the correct behaviors that should be sought, and create -// helper functions that generate all possible test parameters for -// different situations. -var validKeyData = [ - { - format: "spki", - data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]), - }, - { - format: "raw", - data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), - }, - { - format: "jwk", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X448", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, -]; - -// Removed just the last byte. -var badKeyLengthData = [ - { - format: "spki", - data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), - }, - { - format: "pkcs8", - data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146]), - }, - { - format: "raw", - data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), - }, - { - format: "jwk", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - }, - }, - { - format: "jwk", - data: { - crv: "X448", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm", - kty: "OKP" - }, - }, -]; - -var missingJWKFieldKeyData = [ - { - param: "x", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - kty: "OKP" - } - }, - { - param: "kty", - data: { - crv: "X448", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - } - }, - { - param: "crv", - data: { - x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", - kty: "OKP" - } - } -]; - -// The public key doesn't match the private key. -var invalidJWKKeyData = [ - { - - crv: "X448", - kty: "OKP", - d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", - x: "mwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3+A5TLEH6A", - }, -]; run_test(["X448"]); diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js new file mode 100644 index 00000000000000..88f552291cdf6b --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures_fixtures.js @@ -0,0 +1,414 @@ +// Setup: define the correct behaviors that should be sought, and create +// helper functions that generate all possible test parameters for +// different situations. +function getValidKeyData(algorithm) { + return validKeyData[algorithm.name]; +} + +function getBadKeyLengthData(algorithm) { + return badKeyLengthData[algorithm.name]; +} + +function getMissingJWKFieldKeyData(algorithm) { + return missingJWKFieldKeyData[algorithm.name]; +} + +function getMismatchedJWKKeyData(algorithm) { + return mismatchedJWKKeyData[algorithm.name]; +} + +var validKeyData = { + "Ed25519": [ + { + format: "spki", + data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) + }, + { + format: "pkcs8", + data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]) + }, + { + format: "raw", + data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]) + }, + { + format: "jwk", + data: { + crv: "Ed25519", + d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", + x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "Ed25519", + x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", + kty: "OKP" + }, + } + ], + "Ed448": [ + { + format: "spki", + data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]), + }, + { + format: "raw", + data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]), + }, + { + format: "jwk", + data: { + crv: "Ed448", + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "Ed448", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", + kty: "OKP" + }, + }, + ], + "X25519": [ + { + format: "spki", + data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]), + }, + { + format: "raw", + data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]), + }, + { + format: "jwk", + data: { + crv: "X25519", + d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "X25519", + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", + kty: "OKP" + }, + }, + ], + "X448": [ + { + format: "spki", + data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]), + }, + { + format: "raw", + data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]), + }, + { + format: "jwk", + data: { + crv: "X448", + d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "X448", + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", + kty: "OKP" + }, + }, + ], +}; + +// Removed just the last byte. +var badKeyLengthData = { + "Ed25519": [ + { + format: "spki", + data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) + }, + { + format: "pkcs8", + data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168]) + }, + { + format: "raw", + data: new Uint8Array([216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61]) + }, + { + format: "jwk", + data: { + crv: "Ed25519", + d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB", + x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw", + kty: "OKP" + } + }, + { + format: "jwk", + data: { + crv: "Ed25519", + x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPc", + kty: "OKP" + } + } + ], + "Ed448": [ + { + format: "spki", + data: new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29]), + }, + { + format: "raw", + data: new Uint8Array([171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90]), + }, + { + format: "jwk", + data: { + crv: "Ed448", + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "Ed448", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalq", + kty: "OKP" + }, + }, + ], + "X25519": [ + { + format: "spki", + data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255]), + }, + { + format: "raw", + data: new Uint8Array([28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151]), + }, + { + format: "jwk", + data: { + crv: "X25519", + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lw", + kty: "OKP" + } + }, + { + format: "jwk", + data: { + crv: "X25519", + d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2", + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", + kty: "OKP" + }, + }, + ], + "X448": [ + { + format: "spki", + data: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), + }, + { + format: "pkcs8", + data: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146]), + }, + { + format: "raw", + data: new Uint8Array([182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206]), + }, + { + format: "jwk", + data: { + crv: "X448", + d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp", + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", + kty: "OKP" + }, + }, + { + format: "jwk", + data: { + crv: "X448", + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm", + kty: "OKP" + }, + }, + ], +}; + +var missingJWKFieldKeyData = { + "Ed25519": [ + { + param: "x", + data: { + crv: "Ed25519", + d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", + kty: "OKP" + }, + }, + { + param: "kty", + data: { + crv: "Ed25519", + x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", + }, + }, + { + param: "crv", + data: { + x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + kty: "OKP" + }, + } + ], + "Ed448": [ + { + param: "x", + data: { + crv: "Ed448", + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", + kty: "OKP" + } + }, + { + param: "kty", + data: { + crv: "Ed448", + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", + } + }, + { + param: "crv", + data: { + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", + x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA", + kty: "OKP" + } + } + ], + "X25519": [ + { + param: "x", + data: { + crv: "X25519", + d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", + kty: "OKP" + }, + }, + { + param: "kty", + data: { + crv: "X25519", + d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", + }, + }, + { + param: "crv", + data: { + x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY", + kty: "OKP" + }, + } + ], + "X448": [ + { + param: "x", + data: { + crv: "X448", + d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", + kty: "OKP" + } + }, + { + param: "kty", + data: { + crv: "X448", + d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", + } + }, + { + param: "crv", + data: { + x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8", + kty: "OKP" + } + } + ], +}; + +// The public key doesn't match the private key. +var mismatchedJWKKeyData = { + "Ed25519": [ + { + crv: "Ed25519", + d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8", + x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + kty: "OKP" + }, + ], + "Ed448": [ + { + crv: "Ed448", + d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u", + x: "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA", + kty: "OKP" + }, + ], + "X25519": [ + { + crv: "X25519", + d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E", + x: "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo", + kty: "OKP" + }, + ], + "X448": [ + { + + crv: "X448", + kty: "OKP", + d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4", + x: "mwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3+A5TLEH6A", + }, + ], +} diff --git a/test/fixtures/wpt/common/META.yml b/test/fixtures/wpt/common/META.yml index ca4d2e523c0866..963dff9d1f1ecf 100644 --- a/test/fixtures/wpt/common/META.yml +++ b/test/fixtures/wpt/common/META.yml @@ -1,3 +1,2 @@ suggested_reviewers: - - zqzhang - deniak diff --git a/test/fixtures/wpt/common/dispatcher/dispatcher.js b/test/fixtures/wpt/common/dispatcher/dispatcher.js index a0f9f43e622483..dab0100020b829 100644 --- a/test/fixtures/wpt/common/dispatcher/dispatcher.js +++ b/test/fixtures/wpt/common/dispatcher/dispatcher.js @@ -1,7 +1,32 @@ // Define a universal message passing API. It works cross-origin and across // browsing context groups. const dispatcher_path = "/common/dispatcher/dispatcher.py"; -const dispatcher_url = new URL(dispatcher_path, location.href).href; + +// Finds the nearest ancestor window that has a non srcdoc location. This should +// give us a usable location for constructing further URLs. +function findLocationFromAncestors(w) { + if (w.location.href == 'about:srcdoc') { + return findLocationFromAncestors(w.parent); + } + return w.location; +} + +// Handles differences between workers vs frames (src vs srcdoc). +function findLocation() { + if (location.href == 'about:srcdoc') { + return findLocationFromAncestors(window.parent); + } + if (location.protocol == 'blob:' || location.protocol == 'data:') { + // Allows working around blob and data URLs. + if (self.document && self.document.baseURI) { + return self.document.baseURI; + } + } + return location; +} + +const dispatcherLocation = findLocation(); +const dispatcher_url = new URL(dispatcher_path, dispatcherLocation).href; // Return a promise, limiting the number of concurrent accesses to a shared // resources to |max_concurrent_access|. @@ -138,7 +163,7 @@ const cacheableShowRequestHeaders = function(origin, uuid) { // protocol: (optional) Sets the returned URL's `protocol` property. // } function remoteExecutorUrl(uuid, options) { - const url = new URL("/common/dispatcher/remote-executor.html", location); + const url = new URL("/common/dispatcher/remote-executor.html", dispatcherLocation); url.searchParams.set("uuid", uuid); if (options?.host) { diff --git a/test/fixtures/wpt/common/dummy.json b/test/fixtures/wpt/common/dummy.json new file mode 100644 index 00000000000000..0967ef424bce67 --- /dev/null +++ b/test/fixtures/wpt/common/dummy.json @@ -0,0 +1 @@ +{} diff --git a/test/fixtures/wpt/common/media.js b/test/fixtures/wpt/common/media.js index f2dc8612660495..a5a8e957e9b5be 100644 --- a/test/fixtures/wpt/common/media.js +++ b/test/fixtures/wpt/common/media.js @@ -9,10 +9,12 @@ function getVideoURI(base) var videotag = document.createElement("video"); - if ( videotag.canPlayType && - videotag.canPlayType('video/ogg; codecs="theora, vorbis"') ) + if ( videotag.canPlayType ) { - extension = '.ogv'; + if (videotag.canPlayType('video/webm; codecs="vp9, opus"') ) + { + extension = '.webm'; + } } return base + extension; @@ -46,10 +48,10 @@ function getAudioURI(base) function getMediaContentType(url) { var extension = new URL(url, location).pathname.split(".").pop(); var map = { - "mp4": "video/mp4", - "ogv": "application/ogg", - "mp3": "audio/mp3", - "oga": "application/ogg", + "mp4" : "video/mp4", + "webm": "video/webm", + "mp3" : "audio/mp3", + "oga" : "application/ogg", }; return map[extension]; } diff --git a/test/fixtures/wpt/common/top-layer.js b/test/fixtures/wpt/common/top-layer.js new file mode 100644 index 00000000000000..2dc8ce3893aa72 --- /dev/null +++ b/test/fixtures/wpt/common/top-layer.js @@ -0,0 +1,29 @@ +// This function is a version of test_driver.bless which works while there are +// elements in the top layer: +// https://github.com/web-platform-tests/wpt/issues/41218. +// Pass it the element at the top of the top layer stack. +window.blessTopLayer = async (topLayerElement) => { + const button = document.createElement('button'); + topLayerElement.append(button); + let wait_click = new Promise(resolve => button.addEventListener("click", resolve, {once: true})); + await test_driver.click(button); + await wait_click; + button.remove(); +}; + +window.isTopLayer = (el) => { + // A bit of a hack. Just test a few properties of the ::backdrop pseudo + // element that change when in the top layer. + const properties = ['right','background']; + const testEl = document.createElement('div'); + document.body.appendChild(testEl); + const computedStyle = getComputedStyle(testEl, '::backdrop'); + const nonTopLayerValues = properties.map(p => computedStyle[p]); + testEl.remove(); + for(let i=0;i new Float16Array(new Uint8Array(compressedBytesWithDeflate).buffer) }, { name: 'Float32Array', @@ -100,7 +100,7 @@ const bufferSourceChunksForGzip = [ }, { name: 'Float16Array', - value: new Float16Array(new Uint8Array(compressedBytesWithGzip).buffer) + value: () => new Float16Array(new Uint8Array(compressedBytesWithGzip).buffer) }, { name: 'Float32Array', @@ -151,7 +151,7 @@ const bufferSourceChunksForDeflateRaw = [ }, { name: 'Float16Array', - value: new Float16Array(new Uint8Array(compressedBytesWithDeflateRaw).buffer) + value: () => new Float16Array(new Uint8Array(compressedBytesWithDeflateRaw).buffer) }, { name: 'Float32Array', @@ -172,7 +172,7 @@ for (const chunk of bufferSourceChunksForDeflate) { const ds = new DecompressionStream('deflate'); const reader = ds.readable.getReader(); const writer = ds.writable.getWriter(); - const writePromise = writer.write(chunk.value); + const writePromise = writer.write(typeof chunk.value === 'function' ? chunk.value() : chunk.value); writer.close(); const { value } = await reader.read(); assert_array_equals(Array.from(value), deflateExpectedChunkValue, 'value should match'); @@ -184,7 +184,7 @@ for (const chunk of bufferSourceChunksForGzip) { const ds = new DecompressionStream('gzip'); const reader = ds.readable.getReader(); const writer = ds.writable.getWriter(); - const writePromise = writer.write(chunk.value); + const writePromise = writer.write(typeof chunk.value === 'function' ? chunk.value() : chunk.value); writer.close(); const { value } = await reader.read(); assert_array_equals(Array.from(value), gzipExpectedChunkValue, 'value should match'); @@ -196,7 +196,7 @@ for (const chunk of bufferSourceChunksForDeflateRaw) { const ds = new DecompressionStream('deflate-raw'); const reader = ds.readable.getReader(); const writer = ds.writable.getWriter(); - const writePromise = writer.write(chunk.value); + const writePromise = writer.write(typeof chunk.value === 'function' ? chunk.value() : chunk.value); writer.close(); const { value } = await reader.read(); assert_array_equals(Array.from(value), deflateRawExpectedChunkValue, 'value should match'); diff --git a/test/fixtures/wpt/console/console-countReset-logging-manual.html b/test/fixtures/wpt/console/console-countReset-logging-manual.html index 7fe01f50edbfa1..f0a9358fba5d74 100644 --- a/test/fixtures/wpt/console/console-countReset-logging-manual.html +++ b/test/fixtures/wpt/console/console-countReset-logging-manual.html @@ -24,21 +24,25 @@ console.count(); console.countReset(); console.count(); +console.countReset(); console.count(undefined); console.countReset(undefined); console.count(undefined); +console.countReset(undefined); console.count("default"); console.countReset("default"); console.count("default"); +console.countReset("default"); console.count({toString() {return "default"}}); console.countReset({toString() {return "default"}}); console.count({toString() {return "default"}}); +console.countReset({toString() {return "default"}}); console.count("a label"); -console.countReset(); +console.countReset("a label"); console.count("a label"); console.countReset("b"); // should produce a warning diff --git a/test/fixtures/wpt/console/console-log-large-array.any.js b/test/fixtures/wpt/console/console-log-large-array.any.js new file mode 100644 index 00000000000000..e5cb92d9d36d4a --- /dev/null +++ b/test/fixtures/wpt/console/console-log-large-array.any.js @@ -0,0 +1,8 @@ +// META: global=window,dedicatedworker,shadowrealm +"use strict"; +// https://console.spec.whatwg.org/ + +test(() => { + console.log(new Array(10000000).fill("x")); + console.log(new Uint8Array(10000000)); +}, "Logging large arrays works"); diff --git a/test/fixtures/wpt/console/console-log-symbol.any.js b/test/fixtures/wpt/console/console-log-symbol.any.js new file mode 100644 index 00000000000000..a2facb6c64e864 --- /dev/null +++ b/test/fixtures/wpt/console/console-log-symbol.any.js @@ -0,0 +1,10 @@ +// META: global=window,dedicatedworker,shadowrealm +"use strict"; +// https://console.spec.whatwg.org/ + +test(() => { + console.log(Symbol()); + console.log(Symbol("abc")); + console.log(Symbol.for("def")); + console.log(Symbol.isConcatSpreadable); +}, "Logging a symbol doesn't throw"); diff --git a/test/fixtures/wpt/dom/events/scrolling/scroll_support.js b/test/fixtures/wpt/dom/events/scrolling/scroll_support.js index a708364df07cad..1cde3a1f6b446f 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scroll_support.js +++ b/test/fixtures/wpt/dom/events/scrolling/scroll_support.js @@ -20,6 +20,41 @@ async function waitForScrollendEventNoTimeout(target) { }); } +// Waits until a rAF callback with no "scroll" event in the last 200ms. +function waitForDelayWithoutScrollEvent(eventTarget) { + const TIMEOUT_IN_MS = 200; + + return new Promise(resolve => { + let lastScrollEventTime = performance.now(); + + const scrollListener = () => { + lastScrollEventTime = performance.now(); + }; + eventTarget.addEventListener('scroll', scrollListener); + + const tick = () => { + if (performance.now() - lastScrollEventTime > TIMEOUT_IN_MS) { + eventTarget.removeEventListener('scroll', scrollListener); + resolve(); + return; + } + requestAnimationFrame(tick); // wait another frame + } + requestAnimationFrame(tick); + }); +} + +// Waits for the end of scrolling. Uses the "scrollend" event if available. +// Otherwise, fall backs to waitForDelayWithoutScrollEvent(). +function waitForScrollEndFallbackToDelayWithoutScrollEvent(eventTarget) { + if (window.onscrollend !== undefined) { + return waitForScrollendEventNoTimeout(eventTarget); + } + return waitForScrollEvent(eventTarget).then(() => { + return waitForDelayWithoutScrollEvent(eventTarget); + }); +} + async function waitForPointercancelEvent(test, target, timeoutMs = 500) { return waitForEvent("pointercancel", test, target, timeoutMs); } diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js index fca68358623bd9..aa226e185be7ca 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js @@ -66,24 +66,24 @@ decode([0xFE, 0x6D], "\u9FB8", "GB18030-2022 15"); decode([0xFE, 0x7E], "\u9FB9", "GB18030-2022 16"); decode([0xFE, 0x90], "\u9FBA", "GB18030-2022 17"); decode([0xFE, 0xA0], "\u9FBB", "GB18030-2022 18"); -decode([0x82, 0x35, 0x90, 0x37], "\uE81E", "GB18030-2022 19"); -decode([0x82, 0x35, 0x90, 0x38], "\uE826", "GB18030-2022 20"); -decode([0x82, 0x35, 0x90, 0x39], "\uE82B", "GB18030-2022 21"); -decode([0x82, 0x35, 0x91, 0x30], "\uE82C", "GB18030-2022 22"); -decode([0x82, 0x35, 0x91, 0x31], "\uE832", "GB18030-2022 23"); -decode([0x82, 0x35, 0x91, 0x32], "\uE843", "GB18030-2022 24"); -decode([0x82, 0x35, 0x91, 0x33], "\uE854", "GB18030-2022 25"); -decode([0x82, 0x35, 0x91, 0x34], "\uE864", "GB18030-2022 26"); -decode([0x84, 0x31, 0x82, 0x36], "\uE78D", "GB18030-2022 27"); -decode([0x84, 0x31, 0x82, 0x37], "\uE78F", "GB18030-2022 28"); -decode([0x84, 0x31, 0x82, 0x38], "\uE78E", "GB18030-2022 29"); -decode([0x84, 0x31, 0x82, 0x39], "\uE790", "GB18030-2022 30"); -decode([0x84, 0x31, 0x83, 0x30], "\uE791", "GB18030-2022 31"); -decode([0x84, 0x31, 0x83, 0x31], "\uE792", "GB18030-2022 32"); -decode([0x84, 0x31, 0x83, 0x32], "\uE793", "GB18030-2022 33"); -decode([0x84, 0x31, 0x83, 0x33], "\uE794", "GB18030-2022 34"); -decode([0x84, 0x31, 0x83, 0x34], "\uE795", "GB18030-2022 35"); -decode([0x84, 0x31, 0x83, 0x35], "\uE796", "GB18030-2022 36"); +decode([0x82, 0x35, 0x90, 0x37], "\u9FB4", "GB18030-2022 19"); +decode([0x82, 0x35, 0x90, 0x38], "\u9FB5", "GB18030-2022 20"); +decode([0x82, 0x35, 0x90, 0x39], "\u9FB6", "GB18030-2022 21"); +decode([0x82, 0x35, 0x91, 0x30], "\u9FB7", "GB18030-2022 22"); +decode([0x82, 0x35, 0x91, 0x31], "\u9FB8", "GB18030-2022 23"); +decode([0x82, 0x35, 0x91, 0x32], "\u9FB9", "GB18030-2022 24"); +decode([0x82, 0x35, 0x91, 0x33], "\u9FBA", "GB18030-2022 25"); +decode([0x82, 0x35, 0x91, 0x34], "\u9FBB", "GB18030-2022 26"); +decode([0x84, 0x31, 0x82, 0x36], "\uFE10", "GB18030-2022 27"); +decode([0x84, 0x31, 0x82, 0x37], "\uFE11", "GB18030-2022 28"); +decode([0x84, 0x31, 0x82, 0x38], "\uFE12", "GB18030-2022 29"); +decode([0x84, 0x31, 0x82, 0x39], "\uFE13", "GB18030-2022 30"); +decode([0x84, 0x31, 0x83, 0x30], "\uFE14", "GB18030-2022 31"); +decode([0x84, 0x31, 0x83, 0x31], "\uFE15", "GB18030-2022 32"); +decode([0x84, 0x31, 0x83, 0x32], "\uFE16", "GB18030-2022 33"); +decode([0x84, 0x31, 0x83, 0x33], "\uFE17", "GB18030-2022 34"); +decode([0x84, 0x31, 0x83, 0x34], "\uFE18", "GB18030-2022 35"); +decode([0x84, 0x31, 0x83, 0x35], "\uFE19", "GB18030-2022 36"); let i = 0; for (const range of ranges) { diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html index 531d26084e27dc..dc0dc43468f248 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html @@ -43,24 +43,24 @@ encode("\u9FB9", "%FE~", "GB18030-2022 16"); encode("\u9FBA", "%FE%90", "GB18030-2022 17"); encode("\u9FBB", "%FE%A0", "GB18030-2022 18"); - encode("\uE78D", "%841%826", "GB18030-2022 19"); - encode("\uE78E", "%841%828", "GB18030-2022 20"); - encode("\uE78F", "%841%827", "GB18030-2022 21"); - encode("\uE790", "%841%829", "GB18030-2022 22"); - encode("\uE791", "%841%830", "GB18030-2022 23"); - encode("\uE792", "%841%831", "GB18030-2022 24"); - encode("\uE793", "%841%832", "GB18030-2022 25"); - encode("\uE794", "%841%833", "GB18030-2022 26"); - encode("\uE795", "%841%834", "GB18030-2022 27"); - encode("\uE796", "%841%835", "GB18030-2022 28"); - encode("\uE81E", "%825%907", "GB18030-2022 29"); - encode("\uE826", "%825%908", "GB18030-2022 30"); - encode("\uE82B", "%825%909", "GB18030-2022 31"); - encode("\uE82C", "%825%910", "GB18030-2022 32"); - encode("\uE832", "%825%911", "GB18030-2022 33"); - encode("\uE843", "%825%912", "GB18030-2022 34"); - encode("\uE854", "%825%913", "GB18030-2022 35"); - encode("\uE864", "%825%914", "GB18030-2022 36"); + encode("\uE78D", "%A6%D9", "GB18030-2022 19"); + encode("\uE78E", "%A6%DA", "GB18030-2022 20"); + encode("\uE78F", "%A6%DB", "GB18030-2022 21"); + encode("\uE790", "%A6%DC", "GB18030-2022 22"); + encode("\uE791", "%A6%DD", "GB18030-2022 23"); + encode("\uE792", "%A6%DE", "GB18030-2022 24"); + encode("\uE793", "%A6%DF", "GB18030-2022 25"); + encode("\uE794", "%A6%EC", "GB18030-2022 26"); + encode("\uE795", "%A6%ED", "GB18030-2022 27"); + encode("\uE796", "%A6%F3", "GB18030-2022 28"); + encode("\uE81E", "%FEY", "GB18030-2022 29"); + encode("\uE826", "%FEa", "GB18030-2022 30"); + encode("\uE82B", "%FEf", "GB18030-2022 31"); + encode("\uE82C", "%FEg", "GB18030-2022 32"); + encode("\uE832", "%FEm", "GB18030-2022 33"); + encode("\uE843", "%FE~", "GB18030-2022 34"); + encode("\uE854", "%FE%90", "GB18030-2022 35"); + encode("\uE864", "%FE%A0", "GB18030-2022 36"); const upperCaseNibble = x => { return Math.floor(x).toString(16).toUpperCase(); diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.any.js b/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.any.js index c0221480da156d..b7f1ca9c51e88f 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.any.js +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.any.js @@ -1,3 +1,5 @@ +// Additional tests can be found in ../gb18030/gb18030-decoder.any.js + const gbkPointers = [ 6432, 7533, 7536, 7672, 7673, 7674, 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 23766, 23770, 23771, 23772, 23773, 23774, 23776, 23777, 23778, 23779, 23780, 23781, 23782, 23784, 23785, 23786, diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-encoder.html b/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-encoder.html index e43cb73fea72e5..11557242e3dc65 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-encoder.html +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-encoder.html @@ -23,4 +23,43 @@ encode("\u00A5", "%26%23165%3B", "legacy WebKit case 1"); encode("\u22EF", "%26%238943%3B", "legacy WebKit case 2"); encode("\u301C", "%26%2312316%3B", "legacy WebKit case 3"); + encode("\u{10FFFF}", "%26%231114111%3B", "U+10FFFF"); + + // GB18030-2022 + encode("\uFE10", "%A6%D9", "GB18030-2022 1"); + encode("\uFE12", "%A6%DA", "GB18030-2022 2"); + encode("\uFE11", "%A6%DB", "GB18030-2022 3"); + encode("\uFE13", "%A6%DC", "GB18030-2022 4"); + encode("\uFE14", "%A6%DD", "GB18030-2022 5"); + encode("\uFE15", "%A6%DE", "GB18030-2022 6"); + encode("\uFE16", "%A6%DF", "GB18030-2022 7"); + encode("\uFE17", "%A6%EC", "GB18030-2022 8"); + encode("\uFE18", "%A6%ED", "GB18030-2022 9"); + encode("\uFE19", "%A6%F3", "GB18030-2022 10"); + encode("\u9FB4", "%FEY", "GB18030-2022 11"); + encode("\u9FB5", "%FEa", "GB18030-2022 12"); + encode("\u9FB6", "%FEf", "GB18030-2022 13"); + encode("\u9FB7", "%FEg", "GB18030-2022 14"); + encode("\u9FB8", "%FEm", "GB18030-2022 15"); + encode("\u9FB9", "%FE~", "GB18030-2022 16"); + encode("\u9FBA", "%FE%90", "GB18030-2022 17"); + encode("\u9FBB", "%FE%A0", "GB18030-2022 18"); + encode("\uE78D", "%A6%D9", "GB18030-2022 19"); + encode("\uE78E", "%A6%DA", "GB18030-2022 20"); + encode("\uE78F", "%A6%DB", "GB18030-2022 21"); + encode("\uE790", "%A6%DC", "GB18030-2022 22"); + encode("\uE791", "%A6%DD", "GB18030-2022 23"); + encode("\uE792", "%A6%DE", "GB18030-2022 24"); + encode("\uE793", "%A6%DF", "GB18030-2022 25"); + encode("\uE794", "%A6%EC", "GB18030-2022 26"); + encode("\uE795", "%A6%ED", "GB18030-2022 27"); + encode("\uE796", "%A6%F3", "GB18030-2022 28"); + encode("\uE81E", "%FEY", "GB18030-2022 29"); + encode("\uE826", "%FEa", "GB18030-2022 30"); + encode("\uE82B", "%FEf", "GB18030-2022 31"); + encode("\uE82C", "%FEg", "GB18030-2022 32"); + encode("\uE832", "%FEm", "GB18030-2022 33"); + encode("\uE843", "%FE~", "GB18030-2022 34"); + encode("\uE854", "%FE%90", "GB18030-2022 35"); + encode("\uE864", "%FE%A0", "GB18030-2022 36"); diff --git a/test/fixtures/wpt/encoding/resources/utf-32-big-endian-nobom.xml b/test/fixtures/wpt/encoding/resources/utf-32-big-endian-nobom.xml index f51213c965ce74..f704501ccae0d6 100644 Binary files a/test/fixtures/wpt/encoding/resources/utf-32-big-endian-nobom.xml and b/test/fixtures/wpt/encoding/resources/utf-32-big-endian-nobom.xml differ diff --git a/test/fixtures/wpt/encoding/resources/utf-32-little-endian-nobom.xml b/test/fixtures/wpt/encoding/resources/utf-32-little-endian-nobom.xml index 64e6051a2c6b07..465f44df5f782a 100644 Binary files a/test/fixtures/wpt/encoding/resources/utf-32-little-endian-nobom.xml and b/test/fixtures/wpt/encoding/resources/utf-32-little-endian-nobom.xml differ diff --git a/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html new file mode 100644 index 00000000000000..182c707dc3b783 --- /dev/null +++ b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers new file mode 100644 index 00000000000000..5f8621ef83660c --- /dev/null +++ b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers @@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin diff --git a/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000000..fa153f8f965d2b --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html @@ -0,0 +1,28 @@ + + +queueMicrotask() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/WEB_FEATURES.yml b/test/fixtures/wpt/html/webappapis/structured-clone/WEB_FEATURES.yml new file mode 100644 index 00000000000000..423a469bf17283 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/structured-clone/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: structured-clone + files: "**" diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js index 660477dca4c621..00a86fa74b9a96 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js @@ -9,6 +9,7 @@ * - `postTest()`: An optional, async function run after a test is done * - `structuredClone(obj, transferList)`: Required function that somehow * structurally clones an object. + * Must return a promise. * - `hasDocument`: When true, disables tests that require a document. True by default. */ @@ -30,11 +31,11 @@ function runStructuredCloneBatteryOfTests(runner) { } return new Promise(resolve => { - promise_test(async _ => { + promise_test(async t => { test = await test; await setupPromise; await runner.preTest(test); - await test.f(runner) + await test.f(runner, t) await runner.postTest(test); resolve(); }, test.description); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js index 744f1168196001..23cf4f651ac70a 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js @@ -20,3 +20,150 @@ structuredCloneBatteryOfTests.push({ }); // TODO: ImageBitmap + +structuredCloneBatteryOfTests.push({ + description: 'A detached ArrayBuffer cannot be transferred', + async f(runner, t) { + const buffer = new ArrayBuffer(); + await runner.structuredClone(buffer, [buffer]); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(buffer, [buffer]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'A detached platform object cannot be transferred', + async f(runner, t) { + const {port1} = new MessageChannel(); + await runner.structuredClone(port1, [port1]); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(port1, [port1]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring a non-transferable platform object fails', + async f(runner, t) { + const blob = new Blob(); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(blob, [blob]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'An object whose interface is deleted from the global object must still be received', + async f(runner) { + const {port1} = new MessageChannel(); + const messagePortInterface = globalThis.MessagePort; + delete globalThis.MessagePort; + try { + const transfer = await runner.structuredClone(port1, [port1]); + assert_true(transfer instanceof messagePortInterface); + } finally { + globalThis.MessagePort = messagePortInterface; + } + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'A subclass instance will be received as its closest transferable superclass', + async f(runner) { + // MessagePort doesn't have a constructor, so we must use something else. + + // Make sure that ReadableStream is transferable before we test its subclasses. + try { + const stream = new ReadableStream(); + await runner.structuredClone(stream, [stream]); + } catch(err) { + if (err instanceof DOMException && err.code === DOMException.DATA_CLONE_ERR) { + throw new OptionalFeatureUnsupportedError("ReadableStream isn't transferable"); + } else { + throw err; + } + } + + class ReadableStreamSubclass extends ReadableStream {} + const original = new ReadableStreamSubclass(); + const transfer = await runner.structuredClone(original, [original]); + assert_equals(Object.getPrototypeOf(transfer), ReadableStream.prototype); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Resizable ArrayBuffer is transferable', + async f(runner) { + const buffer = new ArrayBuffer(16, { maxByteLength: 1024 }); + const copy = await runner.structuredClone(buffer, [buffer]); + assert_equals(buffer.byteLength, 0); + assert_equals(copy.byteLength, 16); + assert_equals(copy.maxByteLength, 1024); + assert_true(copy.resizable); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Length-tracking TypedArray is transferable', + async f(runner) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab); + const copy = await runner.structuredClone(ta, [ab]); + assert_equals(ab.byteLength, 0); + assert_equals(copy.buffer.byteLength, 16); + assert_equals(copy.buffer.maxByteLength, 1024); + assert_true(copy.buffer.resizable); + copy.buffer.resize(32); + assert_equals(copy.byteLength, 32); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Length-tracking DataView is transferable', + async f(runner) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab); + const copy = await runner.structuredClone(dv, [ab]); + assert_equals(ab.byteLength, 0); + assert_equals(copy.buffer.byteLength, 16); + assert_equals(copy.buffer.maxByteLength, 1024); + assert_true(copy.buffer.resizable); + copy.buffer.resize(32); + assert_equals(copy.byteLength, 32); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring OOB TypedArray throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(ta, [ab]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring OOB DataView throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(dv, [ab]) + ); + } +}); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js index 0c96ded2088357..923ac9dc164918 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js @@ -3,11 +3,6 @@ structuredCloneBatteryOfTests = []; function check(description, input, callback, requiresDocument = false) { - testObjMock = { - done() {}, - step_func(f) {return _ => f()}, - }; - structuredCloneBatteryOfTests.push({ description, async f(runner) { @@ -16,47 +11,41 @@ function check(description, input, callback, requiresDocument = false) { newInput = input(); } const copy = await runner.structuredClone(newInput); - await callback(copy, newInput, testObjMock); + await callback(copy, newInput); }, requiresDocument }); } -function compare_primitive(actual, input, test_obj) { +function compare_primitive(actual, input) { assert_equals(actual, input); - if (test_obj) - test_obj.done(); } -function compare_Array(callback, callback_is_async) { - return function(actual, input, test_obj) { +function compare_Array(callback) { + return async function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Array, 'instanceof Array'); assert_not_equals(actual, input); assert_equals(actual.length, input.length, 'length'); - callback(actual, input); - if (test_obj && !callback_is_async) - test_obj.done(); + await callback(actual, input); } } -function compare_Object(callback, callback_is_async) { - return function(actual, input, test_obj) { +function compare_Object(callback) { + return async function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Object, 'instanceof Object'); assert_false(actual instanceof Array, 'instanceof Array'); assert_not_equals(actual, input); - callback(actual, input); - if (test_obj && !callback_is_async) - test_obj.done(); + await callback(actual, input); } } -function enumerate_props(compare_func, test_obj) { - return function(actual, input) { +function enumerate_props(compare_func) { + return async function(actual, input) { for (const x in input) { - compare_func(actual[x], input[x], test_obj); + await compare_func(actual[x], input[x]); } }; } @@ -127,14 +116,12 @@ check('Object primitives', {'undefined':undefined, '9007199254740994':9007199254740994, '-9007199254740994':-9007199254740994}, compare_Object(enumerate_props(compare_primitive))); -function compare_Boolean(actual, input, test_obj) { +function compare_Boolean(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Boolean, 'instanceof Boolean'); assert_equals(String(actual), String(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } check('Boolean true', new Boolean(true), compare_Boolean); check('Boolean false', new Boolean(false), compare_Boolean); @@ -143,14 +130,12 @@ check('Object Boolean objects', {'true':new Boolean(true), 'false':new Boolean(f function compare_obj(what) { const Type = self[what]; - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Type, 'instanceof '+what); assert_equals(Type(actual), Type(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); }; } check('String empty string', new String(''), compare_obj('String')); @@ -203,14 +188,12 @@ check('Object Number objects', {'0.2':new Number(0.2), '9007199254740994':new Number(9007199254740994), '-9007199254740994':new Number(-9007199254740994)}, compare_Object(enumerate_props(compare_obj('Number')))); -function compare_Date(actual, input, test_obj) { +function compare_Date(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Date, 'instanceof Date'); assert_equals(Number(actual), Number(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } check('Date 0', new Date(0), compare_Date); check('Date -0', new Date(-0), compare_Date); @@ -227,7 +210,7 @@ check('Object Date objects', {'0':new Date(0), function compare_RegExp(expected_source) { // XXX ES6 spec doesn't define exact serialization for `source` (it allows several ways to escape) - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof RegExp, 'instanceof RegExp'); @@ -239,8 +222,6 @@ function compare_RegExp(expected_source) { assert_equals(actual.unicode, input.unicode, 'unicode'); assert_equals(actual.lastIndex, 0, 'lastIndex'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } } function func_RegExp_flags_lastIndex() { @@ -273,7 +254,28 @@ check('Object RegExp object, RegExp empty', {'x':new RegExp('')}, compare_Object check('Object RegExp object, RegExp slash', {'x':new RegExp('/')}, compare_Object(enumerate_props(compare_RegExp('\\/')))); check('Object RegExp object, RegExp new line', {'x':new RegExp('\n')}, compare_Object(enumerate_props(compare_RegExp('\\n')))); -async function compare_Blob(actual, input, test_obj, expect_File) { +function compare_Error(actual, input) { + assert_true(actual instanceof Error, "Checking instanceof"); + assert_equals(actual.constructor, input.constructor, "Checking constructor"); + assert_equals(actual.name, input.name, "Checking name"); + assert_equals(actual.hasOwnProperty("message"), input.hasOwnProperty("message"), "Checking message existence"); + assert_equals(actual.message, input.message, "Checking message"); + assert_equals(actual.foo, undefined, "Checking for absence of custom property"); +} + +check('Empty Error object', new Error, compare_Error); + +const errorConstructors = [Error, EvalError, RangeError, ReferenceError, + SyntaxError, TypeError, URIError]; +for (const constructor of errorConstructors) { + check(`${constructor.name} object`, () => { + let error = new constructor("Error message here"); + error.foo = "testing"; + return error; + }, compare_Error); +} + +async function compare_Blob(actual, input, expect_File) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Blob, 'instanceof Blob'); @@ -333,33 +335,33 @@ function func_Blob_NUL() { } check('Blob NUL', func_Blob_NUL, compare_Blob); -check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true)); - -check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])() }, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob), true)); - -function compare_File(actual, input, test_obj) { +check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob))); + +check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])() }, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob))); + +async function compare_File(actual, input) { assert_true(actual instanceof File, 'instanceof File'); assert_equals(actual.name, input.name, 'name'); assert_equals(actual.lastModified, input.lastModified, 'lastModified'); - compare_Blob(actual, input, test_obj, true); + await compare_Blob(actual, input, true); } function func_File_basic() { return new File(['foo'], 'bar', {type:'text/x-bar', lastModified:42}); } check('File basic', func_File_basic, compare_File); -function compare_FileList(actual, input, test_obj) { +function compare_FileList(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof FileList, 'instanceof FileList'); @@ -367,8 +369,6 @@ function compare_FileList(actual, input, test_obj) { assert_not_equals(actual, input); // XXX when there's a way to populate or construct a FileList, // check the items in the FileList - if (test_obj) - test_obj.done(); } function func_FileList_empty() { const input = document.createElement('input'); @@ -379,30 +379,36 @@ check('FileList empty', func_FileList_empty, compare_FileList, true); check('Array FileList object, FileList empty', () => ([func_FileList_empty()]), compare_Array(enumerate_props(compare_FileList)), true); check('Object FileList object, FileList empty', () => ({'x':func_FileList_empty()}), compare_Object(enumerate_props(compare_FileList)), true); +function compare_ArrayBuffer(actual, input) { + assert_true(actual instanceof ArrayBuffer, 'instanceof ArrayBuffer'); + assert_equals(actual.byteLength, input.byteLength, 'byteLength'); + assert_equals(actual.maxByteLength, input.maxByteLength, 'maxByteLength'); + assert_equals(actual.resizable, input.resizable, 'resizable'); + assert_equals(actual.growable, input.growable, 'growable'); +} + function compare_ArrayBufferView(view) { const Type = self[view]; - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Type, 'instanceof '+view); assert_equals(actual.length, input.length, 'length'); + assert_equals(actual.byteLength, input.byteLength, 'byteLength'); + assert_equals(actual.byteOffset, input.byteOffset, 'byteOffset'); assert_not_equals(actual.buffer, input.buffer, 'buffer'); for (let i = 0; i < actual.length; ++i) { assert_equals(actual[i], input[i], 'actual['+i+']'); } - if (test_obj) - test_obj.done(); }; } -function compare_ImageData(actual, input, test_obj) { +function compare_ImageData(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_equals(actual.width, input.width, 'width'); assert_equals(actual.height, input.height, 'height'); assert_not_equals(actual.data, input.data, 'data'); compare_ArrayBufferView('Uint8ClampedArray')(actual.data, input.data, null); - if (test_obj) - test_obj.done(); } function func_ImageData_1x1_transparent_black() { const canvas = document.createElement('canvas'); @@ -506,6 +512,23 @@ check('Object with non-configurable property', function() { return rv; }, compare_Object(check_configurable_property('foo'))); +structuredCloneBatteryOfTests.push({ + description: 'Object with a getter that throws', + async f(runner, t) { + const exception = new Error(); + const testObject = { + get testProperty() { + throw exception; + } + }; + await promise_rejects_exactly( + t, + exception, + runner.structuredClone(testObject) + ); + } +}); + /* The tests below are inspired by @zcorpan’s work but got some more substantial changed due to their previous async setup */ @@ -616,3 +639,115 @@ check('ObjectPrototype must lose its exotic-ness when cloned', assert_equals(Object.getPrototypeOf(copy), newProto); } ); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing a non-serializable platform object fails', + async f(runner, t) { + const request = new Response(); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(request) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'An object whose interface is deleted from the global must still deserialize', + async f(runner) { + const blob = new Blob(); + const blobInterface = globalThis.Blob; + delete globalThis.Blob; + try { + const copy = await runner.structuredClone(blob); + assert_true(copy instanceof blobInterface); + } finally { + globalThis.Blob = blobInterface; + } + } +}); + +check( + 'A subclass instance will deserialize as its closest serializable superclass', + () => { + class FileSubclass extends File {} + return new FileSubclass([], ""); + }, + (copy) => { + assert_equals(Object.getPrototypeOf(copy), File.prototype); + } +); + +check( + 'Resizable ArrayBuffer', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return ab; + }, + compare_ArrayBuffer); + +structuredCloneBatteryOfTests.push({ + description: 'Growable SharedArrayBuffer', + async f(runner) { + const sab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 }); + assert_true(sab.growable); + try { + const copy = await runner.structuredClone(sab); + compare_ArrayBuffer(sab, copy); + } catch (e) { + // If we're cross-origin isolated, cloning SABs should not fail. + if (e instanceof DOMException && e.code === DOMException.DATA_CLONE_ERR) { + assert_false(self.crossOriginIsolated); + } else { + throw e; + } + } + } +}); + +check( + 'Length-tracking TypedArray', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return new Uint8Array(ab); + }, + compare_ArrayBufferView('Uint8Array')); + +check( + 'Length-tracking DataView', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return new DataView(ab); + }, + compare_ArrayBufferView('DataView')); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing OOB TypedArray throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(ta) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing OOB DataView throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(dv) + ); + } +}); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html new file mode 100644 index 00000000000000..d80010e0df78ad --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html @@ -0,0 +1,20 @@ + +self.structuredClone() uses this's relevant Realm for deserialization + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html new file mode 100644 index 00000000000000..75971023d2d79f --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html @@ -0,0 +1,11 @@ + +window.structuredClone() doesn't crash when window is detached + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js index 34f96f33fdf881..1358a71fc03d4e 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js @@ -1,9 +1,14 @@ // META: title=structuredClone() tests +// META: script=/common/sab.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js runStructuredCloneBatteryOfTests({ - structuredClone: (obj, transfer) => self.structuredClone(obj, { transfer }), + structuredClone: (obj, transfer) => { + return new Promise(resolve => { + resolve(self.structuredClone(obj, { transfer })); + }); + }, hasDocument: typeof document !== "undefined", }); diff --git a/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js b/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js new file mode 100644 index 00000000000000..bf4eb7cf5ac897 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js @@ -0,0 +1,19 @@ +async_test((t) => { + let wasPreviouslyCalled = false; + + const handle = setInterval( + t.step_func(() => { + if (!wasPreviouslyCalled) { + wasPreviouslyCalled = true; + + clearInterval(handle); + + // Make the test succeed after the callback would've run next. + setInterval(t.step_func_done(), 750); + } else { + assert_unreached(); + } + }), + 500 + ); +}, "Clearing an interval from the callback should still clear it."); diff --git a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js new file mode 100644 index 00000000000000..17215e218a9e26 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js @@ -0,0 +1,12 @@ +var t = async_test("Interaction of setTimeout and WebIDL") +function finishTest() { + assert_equals(log, "ONE TWO ") + t.done() +} +var log = ''; +function logger(s) { log += s + ' '; } + +setTimeout({ toString: function () { + setTimeout("logger('ONE')", 100); + return "logger('TWO'); t.step(finishTest)"; +} }, 100); diff --git a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html deleted file mode 100644 index 77a8746908d742..00000000000000 --- a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html +++ /dev/null @@ -1,23 +0,0 @@ - -Interaction of setTimeout and WebIDL - - - - - - -
- diff --git a/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000000..b06b9a56be3706 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html @@ -0,0 +1,31 @@ + + +window.setInterval() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000000..7dad4dc9ca1da8 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html @@ -0,0 +1,27 @@ + + +window.setTimeout() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/interfaces/dom.idl b/test/fixtures/wpt/interfaces/dom.idl index 72d61f5cfd80ad..99192924f4f46f 100644 --- a/test/fixtures/wpt/interfaces/dom.idl +++ b/test/fixtures/wpt/interfaces/dom.idl @@ -120,9 +120,9 @@ interface mixin ParentNode { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; - [CEReactions, Unscopable] undefined prepend((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined append((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceChildren((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined append((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceChildren((Node or DOMString)... nodes); Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); @@ -139,9 +139,9 @@ Element includes NonDocumentTypeChildNode; CharacterData includes NonDocumentTypeChildNode; interface mixin ChildNode { - [CEReactions, Unscopable] undefined before((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined after((Node or TrustedScript or DOMString)... nodes); - [CEReactions, Unscopable] undefined replaceWith((Node or TrustedScript or DOMString)... nodes); + [CEReactions, Unscopable] undefined before((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined after((Node or DOMString)... nodes); + [CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes); [CEReactions, Unscopable] undefined remove(); }; DocumentType includes ChildNode; diff --git a/test/fixtures/wpt/interfaces/html.idl b/test/fixtures/wpt/interfaces/html.idl index 4d6c0229bc1392..25e1f8a4ca058e 100644 --- a/test/fixtures/wpt/interfaces/html.idl +++ b/test/fixtures/wpt/interfaces/html.idl @@ -125,6 +125,7 @@ interface HTMLElement : Element { [CEReactions] attribute boolean spellcheck; [CEReactions] attribute DOMString writingSuggestions; [CEReactions] attribute DOMString autocapitalize; + [CEReactions] attribute boolean autocorrect; [CEReactions] attribute [LegacyNullToEmptyString] DOMString innerText; [CEReactions] attribute [LegacyNullToEmptyString] DOMString outerText; @@ -1411,8 +1412,6 @@ interface mixin CanvasDrawPath { interface mixin CanvasUserInterface { undefined drawFocusIfNeeded(Element element); undefined drawFocusIfNeeded(Path2D path, Element element); - undefined scrollPathIntoView(); - undefined scrollPathIntoView(Path2D path); }; interface mixin CanvasText { diff --git a/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html b/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html new file mode 100644 index 00000000000000..c673e09cb461e0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js b/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js new file mode 100644 index 00000000000000..4de816bdc42bd8 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js @@ -0,0 +1,81 @@ +promise_test(t => { + // This setup is required for later tests as well. + // Await for a dropped entry. + return new Promise(res => { + // Set a buffer size of 0 so that new resource entries count as dropped. + performance.setResourceTimingBufferSize(0); + // Use an observer to make sure the promise is resolved only when the + // new entry has been created. + new PerformanceObserver(res).observe({type: 'resource'}); + fetch('resources/square.png?id=1'); + }).then(() => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 0); + resolve(); + })).observe({type: 'mark'}); + performance.mark('test'); + })}); +}, 'Dropped entries count is 0 when there are no dropped entries of relevant type.'); + +promise_test(async t => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 1); + resolve(); + })).observe({entryTypes: ['mark', 'resource']}); + performance.mark('meow'); + }); +}, 'Dropped entries correctly counted with multiple types.'); + +promise_test(t => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 1, + 'There should have been some dropped resource timing entries at this point'); + resolve(); + })).observe({type: 'resource', buffered: true}); + }); +}, 'Dropped entries counted even if observer was not registered at the time.'); + +promise_test(t => { + return new Promise(resolve => { + let callback_ran = false; + new PerformanceObserver(t.step_func((entries, obs, options) => { + if (!callback_ran) { + assert_equals(options['droppedEntriesCount'], 2, + 'There should be two dropped entries right now.'); + fetch('resources/square.png?id=3'); + callback_ran = true; + } else { + assert_equals(options['droppedEntriesCount'], undefined, + 'droppedEntriesCount should be unset after the first callback!'); + resolve(); + } + })).observe({type: 'resource'}); + fetch('resources/square.png?id=2'); + }); +}, 'Dropped entries only surfaced on the first callback.'); + + +promise_test(t => { + return new Promise(resolve => { + let callback_ran = false; + let droppedEntriesCount = -1; + new PerformanceObserver(t.step_func((entries, obs, options) => { + if (!callback_ran) { + assert_greater_than(options['droppedEntriesCount'], 0, + 'There should be several dropped entries right now.'); + droppedEntriesCount = options['droppedEntriesCount']; + callback_ran = true; + obs.observe({type: 'mark'}); + performance.mark('woof'); + } else { + assert_equals(options['droppedEntriesCount'], droppedEntriesCount, + 'There should be droppedEntriesCount due to the new observe().'); + resolve(); + } + })).observe({type: 'resource'}); + fetch('resources/square.png?id=4'); + }); +}, 'Dropped entries surfaced after an observe() call!'); diff --git a/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js b/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js new file mode 100644 index 00000000000000..6caaa3306132bd --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js @@ -0,0 +1,2 @@ +// META: script=/resources/idlharness-shadowrealm.js +idl_test_shadowrealm(["performance-timeline"], ["hr-time", "dom"]); diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html new file mode 100644 index 00000000000000..add11255af45c0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html @@ -0,0 +1,30 @@ + + + + + + The navigation_id Detached iframe Parent Page. + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html new file mode 100644 index 00000000000000..7ff415530bc69d --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html new file mode 100644 index 00000000000000..b996f0f117922d --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html @@ -0,0 +1,49 @@ + + + + + + + +

This text is to trigger a LCP entry emission.

+ + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html new file mode 100644 index 00000000000000..e1da9100aeee55 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html new file mode 100644 index 00000000000000..30613ebb980eb0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html new file mode 100644 index 00000000000000..f5a2428e5f568a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html @@ -0,0 +1,53 @@ + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html new file mode 100644 index 00000000000000..6d0614a6e23940 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html b/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html new file mode 100644 index 00000000000000..96fc57be1d426c --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id.helper.js b/test/fixtures/wpt/performance-timeline/navigation-id.helper.js new file mode 100644 index 00000000000000..1b72fe9908d573 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id.helper.js @@ -0,0 +1,144 @@ +// The test functions called in the navigation-counter test. They rely on +// artifacts defined in +// '/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js' +// which should be included before this file to use these functions. + +// This function is to obtain navigation ids of all performance entries to +// verify. +let testInitial = () => { + return window.performance.getEntries().map(e => e.navigationId); +} + +let testMarkMeasure = (markId, markName, MeasureName) => { + const markName1 = 'test-mark'; + const markName2 = 'test-mark' + markId; + const measureName = 'test-measure' + markId; + + window.performance.mark(markName1); + window.performance.mark(markName2); + window.performance.measure(measureName, markName1, markName2); + return window.performance.getEntriesByName(markName2).concat( + window.performance.getEntriesByName(measureName)).map(e => e.navigationId); +} + +let testResourceTiming = async (resourceTimingEntryId) => { + let navigationId; + + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find( + e => e.name.includes('json_resource' + resourceTimingEntryId)); + if (entry) { + navigationId = entry.navigationId; + resolve(); + } + }).observe({ type: 'resource' }); + }); + + const resp = await fetch( + '/performance-timeline/resources/json_resource' + resourceTimingEntryId + '.json'); + await p; + return [navigationId]; +} + +let testElementTiming = async (elementTimingEntryId) => { + let navigationId; + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find( + e => e.entryType === 'element' && e.identifier === 'test-element-timing' + elementTimingEntryId); + if (entry) { + navigationId = entry.navigationId; + resolve(); + } + }).observe({ type: 'element' }); + }); + + let el = document.createElement('p'); + el.setAttribute('elementtiming', 'test-element-timing' + elementTimingEntryId); + el.textContent = 'test element timing text'; + document.body.appendChild(el); + await p; + return [navigationId]; +} + +let testLongTask = async () => { + let navigationIds = []; + + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find(e => e.entryType === 'longtask') + if (entry) { + navigationIds.push(entry.navigationId); + navigationIds = navigationIds.concat( + entry.attribution.map(a => a.navigationId)); + resolve(); + } + }).observe({ type: 'longtask' }); + }); + + const script = document.createElement('script'); + script.src = '/performance-timeline/resources/make_long_task.js'; + document.body.appendChild(script); + await p; + document.body.removeChild(script); + return navigationIds; +} + +const testFunctionMap = { + 'mark_measure': testMarkMeasure, + 'resource_timing': testResourceTiming, + 'element_timing': testElementTiming, + 'long_task_task_attribution': testLongTask, +}; + +function runNavigationIdTest(params, description) { + const defaultParams = { + openFunc: url => window.open(url, '_blank', 'noopener'), + scripts: [], + funcBeforeNavigation: () => { }, + targetOrigin: originCrossSite, + navigationTimes: 4, + funcAfterAssertion: () => { }, + } // Apply defaults. + params = { ...defaultParams, ...params }; + + promise_test(async t => { + const pageA = new RemoteContext(token()); + const pageB = new RemoteContext(token()); + + const urlA = executorPath + pageA.context_id; + const urlB = params.targetOrigin + executorPath + pageB.context_id; + // Open url A. + params.openFunc(urlA); + await pageA.execute_script(waitForPageShow); + + // Assert navigation ids of all performance entries are the same. + let navigationIds = await pageA.execute_script(testInitial); + assert_true( + navigationIds.every(t => t === navigationIds[0]), + 'Navigation Ids should be the same as the initial load.'); + + for (i = 1; i <= params.navigationTimes; i++) { + // Navigate away to url B and back. + await navigateAndThenBack(pageA, pageB, urlB); + + // Assert new navigation ids are generated when the document is load from bfcache. + let nextNavigationIds = await pageA.execute_script( + testFunctionMap[params.testName], [i + 1]); + + // Assert navigation ids of all performance entries are the same. + assert_true( + nextNavigationIds.every(t => t === nextNavigationIds[0]), + 'All Navigation Ids should be same after bfcache navigation.'); + + // Assert navigation ids after bfcache navigation are different from those before. + assert_true( + navigationIds[0] !== nextNavigationIds[0], + params.testName + + ' Navigation Ids should be re-generated and different from the previous ones.'); + + navigationIds = nextNavigationIds; + } + }, description); +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/abort-block-bfcache.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/abort-block-bfcache.window.js new file mode 100644 index 00000000000000..e5dbb0f43c8dd3 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/abort-block-bfcache.window.js @@ -0,0 +1,21 @@ +// META: title=Aborting a parser should block bfcache +// META: script=./test-helper.js +// META: timeout=long + + +async_test(t => { + if (!sessionStorage.getItem("pageVisited")) { + // This is the first time loading the page. + sessionStorage.setItem("pageVisited", 1); + t.step_timeout(() => { + // Go to another page and instantly come back to this page. + location.href = new URL("../resources/going-back.html", window.location); + }, 0); + // Abort parsing in the middle of loading the page. + window.stop(); + } else { + const nrr = performance.getEntriesByType('navigation')[0].notRestoredReasons; + assert_true(ReasonsInclude(nrr.reasons, "parser-aborted")); + t.done(); + } +}, "aborting a parser should block bfcache."); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js new file mode 100644 index 00000000000000..44495fa981b752 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js @@ -0,0 +1,55 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that empty attributes are reported as empty strings and missing +// attributes are reported as null. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a cross-origin iframe. + const rc1_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {id: '', name: ''}, + ); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/[{ + 'url': null, + 'src': rc1_child_url, + // Id and name should be empty. + 'id': '', + 'name': '', + 'reasons': null, + 'children': null + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js new file mode 100644 index 00000000000000..28dbc38575a3b2 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js @@ -0,0 +1,47 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons are only updated after non BFCache navigation. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/ []); + + // This time no blocking feature is used, so the page is restored + // from BFCache. Ensure that the previous reasons stay there. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/ []); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js new file mode 100644 index 00000000000000..bfb685451c36d6 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js @@ -0,0 +1,28 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons is empty for successful BFCache restore. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + + // Check the BFCache result and verify that no reasons are recorded + // for successful restore. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + assert_true(await rc1.executeScript(() => { + let reasons = + performance.getEntriesByType('navigation')[0].notRestoredReasons; + return reasons === null; + })); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js new file mode 100644 index 00000000000000..2a313fe7b14334 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js @@ -0,0 +1,60 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that cross-origin subtree's reasons are not exposed to +// notRestoredReasons. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a cross-origin iframe. + const rc1_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {id: 'test-id'}, + ); + // Use WebSocket to block BFCache. + await useWebSocket(rc1_child); + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Add a child to the iframe. + const rc1_grand_child = await rc1_child.addIframe(); + const rc1_grand_child_url = await rc1_grand_child.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': "masked"}], + /*children=*/[{ + 'url': null, + 'src': rc1_child_url, + 'id': 'test-id', + 'name': null, + 'reasons': null, + 'children': null + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js new file mode 100644 index 00000000000000..c8f53a660fa9a1 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js @@ -0,0 +1,40 @@ +// META: title=Ensure that ongoing fetch upon entering bfcache blocks bfcache and recorded. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + const wavURL = new URL(get_host_info().HTTP_REMOTE_ORIGIN + '/fetch/range/resources/long-wav.py'); + await rc1.executeScript((wavURL) => { + // Register pagehide handler to create a fetch request. + addEventListener('pagehide', (wavURL) => { + fetch(wavURL, { + keepalive: true + }); + }) + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'fetch'}], + /*children=*/[]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-iframes-without-attributes.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-iframes-without-attributes.tentative.window.js new file mode 100644 index 00000000000000..cda0ac43944742 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-iframes-without-attributes.tentative.window.js @@ -0,0 +1,103 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that empty attributes are reported as empty strings and missing +// attributes are reported as null. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a cross-origin iframe. + const rc1_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {id: '', name: ''}, + ); + const rc2_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {}, + ); + const rc3_child = await rc1.addIframe( + /*extraConfig=*/ {}, + /*attributes=*/ {}, + ); + const rc4_child = await rc1.addIframe( + /*extraConfig=*/ {}, + /*attributes=*/ {id: '', name: ''}, + ); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + const rc2_child_url = await rc2_child.executeScript(() => { + return location.href; + }); + const rc3_child_url = await rc3_child.executeScript(() => { + return location.href; + }); + const rc4_child_url = await rc4_child.executeScript(() => { + return location.href; + }); + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/[{ + 'url': null, + 'src': rc1_child_url, + // Id and name should be empty. + 'id': '', + 'name': '', + 'reasons': null, + 'children': null + }, { + 'url': null, + 'src': rc2_child_url, + // Id and name should be null. + 'id': null, + 'name': null, + 'reasons': null, + 'children': null + },{ + 'url': rc3_child_url, + 'src': rc3_child_url, + // Id and name should be null. + 'id': null, + 'name': null, + 'reasons': [], + 'children': [] + }, { + 'url': rc4_child_url, + 'src': rc4_child_url, + 'id': '', + 'name': '', + 'reasons': [], + 'children': [] + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js new file mode 100644 index 00000000000000..46d8752f20d967 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js @@ -0,0 +1,32 @@ +// META: title=Ensure that if WebLock is held upon entering bfcache, it cannot enter bfcache and gets reported. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Request a WebLock. + let return_value = await rc1.executeScript(() => { + return new Promise((resolve) => { + navigator.locks.request('resource', () => { + resolve(42); + }); + }) + }); + assert_equals(return_value, 42); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, ['lock']); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js new file mode 100644 index 00000000000000..faa7649bc33c3f --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js @@ -0,0 +1,26 @@ +// META: title=Ensure that navigation failure blocks bfcache and gets recorded. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/404.py +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; +const {ORIGIN} = get_host_info(); + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ {status: 404}, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, ['response-status-not-ok']); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js new file mode 100644 index 00000000000000..1cf1d55d90f78a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js @@ -0,0 +1,36 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons is populated when not restored. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/ []); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js new file mode 100644 index 00000000000000..7191456cc845bd --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js @@ -0,0 +1,53 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; +const {ORIGIN, REMOTE_ORIGIN} = get_host_info(); + +// Ensure that notRestoredReasons reset after the server redirect. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + // Create a remote context with the redirected URL. + let rc1_redirected = + await rcHelper.createContext(/*extraConfig=*/ { + origin: 'HTTP_ORIGIN', + scripts: [], + headers: [], + }); + + const redirectUrl = + `${ORIGIN}/common/redirect.py?location=${encodeURIComponent(rc1_redirected.url)}`; + // Replace the history state. + await rc1.executeScript((url) => { + window.history.replaceState(null, '', url); + }, [redirectUrl]); + + // Navigate away. + const newRemoteContextHelper = await rc1.navigateToNew(); + + // Go back. + await newRemoteContextHelper.historyBack(); + + const navigation_entry = await rc1_redirected.executeScript(() => { + return performance.getEntriesByType('navigation')[0]; + }); + assert_equals( + navigation_entry.redirectCount, 1, 'Expected redirectCount is 1.'); + // Becauase of the redirect, notRestoredReasons is reset. + assert_equals( + navigation_entry.notRestoredReasons, null, + 'Expected notRestoredReasons is null.'); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js new file mode 100644 index 00000000000000..1a8972778d287c --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js @@ -0,0 +1,50 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; +const {ORIGIN, REMOTE_ORIGIN} = get_host_info(); + +// Ensure that notRestoredReasons reset after the server redirect. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/ []); + + // Reload. + await rc1.navigate(() => { + location.reload(); + }, []); + + // Becauase of the reload, notRestoredReasons is reset. + const navigation_entry = await rc1.executeScript(() => { + return performance.getEntriesByType('navigation')[0]; + }); + + assert_equals( + navigation_entry.notRestoredReasons, null, + 'Expected notRestoredReasons is null.'); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js new file mode 100644 index 00000000000000..89d66b070ed8c4 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js @@ -0,0 +1,61 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + + +'use strict'; + +// Ensure that same-origin subtree's reasons are exposed to notRestoredReasons. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a same-origin iframe and use WebSocket. + const rc1_child = await rc1.addIframe( + /*extra_config=*/ {}, /*attributes=*/ {id: 'test-id'}); + await useWebSocket(rc1_child); + + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Add a child to the iframe. + const rc1_grand_child = await rc1_child.addIframe(); + const rc1_grand_child_url = await rc1_grand_child.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[], + /*children=*/[{ + 'url': rc1_child_url, + 'src': rc1_child_url, + 'id': 'test-id', + 'name': '', + 'reasons': [{'reason': 'websocket'}], + 'children': [{ + 'url': rc1_grand_child_url, + 'src': rc1_grand_child_url, + 'id': '', + 'name': '', + 'reasons': [], + 'children': [] + }] + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js new file mode 100644 index 00000000000000..1162bfaf7600fd --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js @@ -0,0 +1,43 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons are accessible after history replace. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + // Navigate away. + const newRemoteContextHelper = await rc1.navigateToNew(); + // Replace the history state to a same-origin site. + await newRemoteContextHelper.executeScript((destUrl) => { + window.history.replaceState(null, '', '#'); + }); + // Go back. + await newRemoteContextHelper.historyBack(); + + // Reasons are not reset for same-origin replace. + await assertNotRestoredReasonsEquals( + rc1, + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[{'reason': 'websocket'}], + /*children=*/ []); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js new file mode 100644 index 00000000000000..ba9a4c0342fcb5 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js @@ -0,0 +1,57 @@ +// META: script=../../html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js + +async function assertNotRestoredReasonsEquals( + remoteContextHelper, url, src, id, name, reasons, children) { + let result = await remoteContextHelper.executeScript(() => { + return performance.getEntriesByType('navigation')[0].notRestoredReasons; + }); + assertReasonsStructEquals( + result, url, src, id, name, reasons, children); +} + +function assertReasonsStructEquals( + result, url, src, id, name, reasons, children) { + assert_equals(result.url, url); + assert_equals(result.src, src); + assert_equals(result.id, id); + assert_equals(result.name, name); + + // Reasons should match. + let expected = new Set(reasons); + let actual = new Set(result.reasons); + matchReasons(extractReason(expected), extractReason(actual)); + + // Children should match. + if (children == null) { + assert_equals(result.children, children); + } else { + for (let j = 0; j < children.length; j++) { + assertReasonsStructEquals( + result.children[j], children[j].url, + children[j].src, children[j].id, children[j].name, children[j].reasons, + children[j].children); + } + } +} + +function ReasonsInclude(reasons, targetReason) { + for (const reason of reasons) { + if (reason.reason == targetReason) { + return true; + } + } + return false; +} + +// Requires: +// - /websockets/constants.sub.js in the test file and pass the domainPort +// constant here. +async function useWebSocket(remoteContextHelper) { + let return_value = await remoteContextHelper.executeScript((domain) => { + return new Promise((resolve) => { + var webSocketInNotRestoredReasonsTests = new WebSocket(domain + '/echo'); + webSocketInNotRestoredReasonsTests.onopen = () => { resolve(42); }; + }); + }, [SCHEME_DOMAIN_PORT]); + assert_equals(return_value, 42); +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/child-frame.html b/test/fixtures/wpt/performance-timeline/resources/child-frame.html new file mode 100644 index 00000000000000..40c8f7268857d0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/child-frame.html @@ -0,0 +1,7 @@ + + + + + diff --git a/test/fixtures/wpt/performance-timeline/resources/empty.html b/test/fixtures/wpt/performance-timeline/resources/empty.html new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/test/fixtures/wpt/performance-timeline/resources/going-back.html b/test/fixtures/wpt/performance-timeline/resources/going-back.html new file mode 100644 index 00000000000000..f4a26669baa163 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/going-back.html @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js b/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js new file mode 100644 index 00000000000000..a56489baaf4d06 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js @@ -0,0 +1,60 @@ +const verifyEntries = (entries, filterOptions) => { + for (const filterOption of filterOptions) { + let countBeforeFiltering = entries.length; + + // Using negate of the condition so that the next filtering is applied on less entries. + entries = entries.filter( + e => !(e.entryType == filterOption['entryType'] && e.name.includes(filterOption['name']))); + + assert_equals( + countBeforeFiltering - entries.length, filterOption['expectedCount'], filterOption['failureMsg']); + } +} + +const createFilterOption = (name, entryType, expectedCount, msgPrefix, description = '') => { + if (description) { + description = ' ' + description; + } + + let failureMsg = + `${msgPrefix} should have ${expectedCount} ${entryType} entries for name ${name}` + description; + + return { + name: name, + entryType: entryType, + expectedCount: expectedCount, + failureMsg: failureMsg + }; +} + +const loadChildFrame = (src) => { + return new Promise(resolve => { + + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", resolve); + + childFrame.src = src; + + document.body.appendChild(childFrame); + }); +} + +const loadChildFrameAndGrandchildFrame = (src) => { + return new Promise(resolve => { + + const crossOriginChildFrame = document.createElement('iframe'); + + // Wait for the child frame to send a message. The child frame would send a message + // when it loads its child frame. + window.addEventListener('message', e => { + if (e.data == 'Load completed') { + resolve(); + } + }); + + crossOriginChildFrame.src = src; + + document.body.appendChild(crossOriginChildFrame) + }); +} diff --git a/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html b/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html new file mode 100644 index 00000000000000..0d43f418a096a0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html @@ -0,0 +1,43 @@ + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/resources/json_resource.json b/test/fixtures/wpt/performance-timeline/resources/json_resource.json new file mode 100644 index 00000000000000..68b6ac1d56f7c2 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/json_resource.json @@ -0,0 +1,4 @@ +{ + "name": "nav_id_test", + "target": "resource_timing" +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/make_long_task.js b/test/fixtures/wpt/performance-timeline/resources/make_long_task.js new file mode 100644 index 00000000000000..a52d6d839298cc --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/make_long_task.js @@ -0,0 +1,4 @@ +(function () { + let now = window.performance.now(); + while (window.performance.now() < now + 60); +}()); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html b/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html new file mode 100644 index 00000000000000..02aafbb5c78368 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html @@ -0,0 +1,21 @@ + + + + + + The navigation_id Detached iframe Page. + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js b/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js new file mode 100644 index 00000000000000..3a2740d0675c84 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js @@ -0,0 +1,6 @@ +self.onmessage = () => { + const mark_name = 'user_timig_mark'; + performance.mark(mark_name); + postMessage(performance.getEntriesByName(mark_name)[0].navigationId); + self.close(); +} diff --git a/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html b/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html new file mode 100644 index 00000000000000..8b86a6398bfd49 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html @@ -0,0 +1,18 @@ + + +Cross-realm access of supportedEntryTypes returns Array of another realm + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html b/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html new file mode 100644 index 00000000000000..70019223a648d9 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html new file mode 100644 index 00000000000000..57623e5b33bfb0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html new file mode 100644 index 00000000000000..bcb9a81657f227 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html @@ -0,0 +1,76 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html new file mode 100644 index 00000000000000..cccbf4100dd2ae --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html new file mode 100644 index 00000000000000..d630665b652cb1 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html new file mode 100644 index 00000000000000..58cad40faba658 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html new file mode 100644 index 00000000000000..2368a8e881aa3a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html new file mode 100644 index 00000000000000..b823d6edaa3262 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html new file mode 100644 index 00000000000000..d10d3c5ed512b7 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html b/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html new file mode 100644 index 00000000000000..6c6643df75cf09 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html b/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html new file mode 100644 index 00000000000000..43988b21fbbe02 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html @@ -0,0 +1,16 @@ + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/META.yml b/test/fixtures/wpt/resource-timing/META.yml index 662c42cb664219..153654eae8b1a1 100644 --- a/test/fixtures/wpt/resource-timing/META.yml +++ b/test/fixtures/wpt/resource-timing/META.yml @@ -1,6 +1,5 @@ spec: https://w3c.github.io/resource-timing/ suggested_reviewers: - plehegar - - zqzhang - igrigorik - yoavweiss diff --git a/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html b/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html new file mode 100644 index 00000000000000..b0340139bf7f40 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html @@ -0,0 +1,63 @@ + + + + +Verify that encodedBodySize/decodedBodySize are CORS-protected rather than TAO-protected + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/content-type-minimization.html b/test/fixtures/wpt/resource-timing/content-type-minimization.html new file mode 100644 index 00000000000000..d7dbc2cc9f3b6a --- /dev/null +++ b/test/fixtures/wpt/resource-timing/content-type-minimization.html @@ -0,0 +1,79 @@ + + + + +This test validates the parsing of content-type of resources. + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/content-type.html b/test/fixtures/wpt/resource-timing/content-type.html new file mode 100644 index 00000000000000..654e083e14aa1f --- /dev/null +++ b/test/fixtures/wpt/resource-timing/content-type.html @@ -0,0 +1,126 @@ + + + +This test validates the content-type of resources. + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html b/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html index 1b107d3aef7764..8e368d13807745 100644 --- a/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html +++ b/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html @@ -19,13 +19,19 @@ const blank_page = `/resource-timing/resources/blank_page_green.htm`; const destUrl = `/common/slow-redirect.py?delay=${delay}&location=${REMOTE_ORIGIN}/${blank_page}`; -const timeBefore = performance.now() -attribute_test(load.iframe, destUrl, entry => { - assert_equals(entry.startTime, entry.fetchStart, 'startTime and fetchStart should be equal'); - assert_greater_than(entry.startTime, timeBefore, 'startTime and fetchStart should be greater than the time before fetching'); - // See https://github.com/w3c/resource-timing/issues/264 - assert_less_than(Math.round(entry.startTime - timeBefore), delay * 1000, 'startTime should not expose redirect delays'); -}, "Verify that cross-origin resources don't implicitly expose their redirect timings") +const timeBefore = performance.now(); +(async () => { + // Wait 10 ms, to ensure the difference between startTime and timeBefore is + // larger than 1 ms, to avoid flakiness in browsers that clamp timestamps to + // 1 ms. + await new Promise(r => step_timeout(r, 10)); + attribute_test(load.iframe, destUrl, entry => { + assert_equals(entry.startTime, entry.fetchStart, 'startTime and fetchStart should be equal'); + assert_greater_than(entry.startTime, timeBefore, 'startTime and fetchStart should be greater than the time before fetching'); + // See https://github.com/w3c/resource-timing/issues/264 + assert_less_than(Math.round(entry.startTime - timeBefore), delay * 1000, 'startTime should not expose redirect delays'); + }, "Verify that cross-origin resources don't implicitly expose their redirect timings") +})(); diff --git a/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js b/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js new file mode 100644 index 00000000000000..e2b408fdd74f29 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js @@ -0,0 +1,90 @@ +// META: global=window,worker +// META: script=/common/get-host-info.sub.js +// META: script=/resource-timing/resources/resource-loaders.js + +// TODO(crbug/1358591): Rename this file from "tentative" once +// `w3c/resource-timing#343` is merged. + +const {REMOTE_ORIGIN, ORIGIN} = get_host_info(); + +const redirectBase = new URL( + '/resource-timing/resources/redirect-cors.py', REMOTE_ORIGIN).href; +const cacheAndValidatedBase = new URL( + '/resource-timing/resources/cacheable-and-validated.py?content=content', + ORIGIN).href; + +const mustRevalidate = {headers: {'Cache-Control': 'max-age=0'}}; + +const fetchAndEatBody = (url, fetchOption) => { + return fetch(url, fetchOption).then(response => response.arrayBuffer()); +}; + +const accumulateEntries = () => { + return new Promise(resolve => { + const po = new PerformanceObserver(list => { + resolve(list); + }); + po.observe({type: "resource", buffered: true}); + }); +}; + +const checkDeliveryTypeBase = + (list, lookupURL, deliveryTypeForCachedResources) => { + const entries = list.getEntriesByName(lookupURL); + assert_equals(entries.length, 3, 'Wrong number of entries'); + + // 200 response (`cacheMode` is an empty string) + assert_equals(entries[0].deliveryType, "", + "Expect empty deliveryType for 200 response."); + // Cached response (`cacheMode` is "local") or 304 response (`cacheMode` is + // "validated"). + assert_equals(entries[1].deliveryType, deliveryTypeForCachedResources, + `Expect "${deliveryTypeForCachedResources}" deliveryType for a + cached response.`); + assert_equals(entries[2].deliveryType, deliveryTypeForCachedResources, + `Expect "${deliveryTypeForCachedResources}" deliveryType for a + revalidated response.`); +}; + +promise_test(() => { + // Use a different URL every time so that the cache behaviour does not depend + // on execution order. + const initialURL = load.cache_bust(cacheAndValidatedBase); + const checkDeliveryType = + list => checkDeliveryTypeBase(list, initialURL, "cache"); + return fetchAndEatBody(initialURL, {}) // 200. + .then(() => fetchAndEatBody(initialURL, {})) // Cached. + .then(() => fetchAndEatBody(initialURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, same origin.'); + +promise_test(() => { + const cacheAndValidatedURL = load.cache_bust( + cacheAndValidatedBase + '&timing_allow_origin=*'); + const redirectURL = redirectBase + + "?timing_allow_origin=*" + + `&allow_origin=${encodeURIComponent(ORIGIN)}` + + `&location=${encodeURIComponent(cacheAndValidatedURL)}`; + const checkDeliveryType = + list => checkDeliveryTypeBase(list, redirectURL, "cache"); + return fetchAndEatBody(redirectURL, {}) // 200. + .then(() => fetchAndEatBody(redirectURL, {})) // Cached. + .then(() => fetchAndEatBody(redirectURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, cross origin, TAO passes.'); + +promise_test(() => { + const cacheAndValidatedURL = load.cache_bust(cacheAndValidatedBase); + const redirectURL = redirectBase + + `?allow_origin=${encodeURIComponent(ORIGIN)}` + + `&location=${encodeURIComponent(cacheAndValidatedURL)}`; + const checkDeliveryType = + list => checkDeliveryTypeBase(list, redirectURL, ""); + return fetchAndEatBody(redirectURL, {}) // 200. + .then(() => fetchAndEatBody(redirectURL, {})) // Cached. + .then(() => fetchAndEatBody(redirectURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, cross origin, TAO fails.'); diff --git a/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html b/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html index 95849d282621ff..ebc2247babcd4a 100644 --- a/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html +++ b/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html @@ -30,6 +30,22 @@ network_error_entry_test( `/element-timing/resources/multiple-redirects.py?redirect_count=22&final_resource=${validXmlUrl}`, null, "too many redirects"); + +// ORB (https://github.com/whatwg/fetch/pull/1442) will return network errors +// for certain cross-origin fetches. This tests that the same rules apply to +// these fetches. Since ORB (at least as presently implemented) doesn't return +// network errors for fetches, we have to load this case using an element. +// +// This emulates a case previously tested in service-workers/service-worker/resource-timing.sub.https.html +const orb_loader = (url, _) => new Promise(resolve => { + const img = document.createElement("img"); + img.src = url; + img.onerror = resolve; + document.body.appendChild(img); +} ); +network_error_entry_test( + '//{{hosts[alt][]}}:{{ports[https][0]}}/service-workers/service-worker/resources/missing.jpg', + null, "network error for ORB-blocked response", orb_loader); diff --git a/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html b/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html index 4193422653a595..1605e224ab43b2 100644 --- a/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html +++ b/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html @@ -12,7 +12,7 @@ const {REMOTE_ORIGIN, ORIGIN} = get_host_info(); const redirect = "/common/redirect.py?" + - "location=/resource-timing/resources/green.html"; + "location=/resource-timing/resources/empty_script.js"; const cross_origin_redirect = REMOTE_ORIGIN + redirect; const same_origin_redirect = ORIGIN + redirect; diff --git a/test/fixtures/wpt/resource-timing/iframe-failed-commit.html b/test/fixtures/wpt/resource-timing/iframe-failed-commit.html index 1da207d2fbe05e..d3b5cce59ec21e 100644 --- a/test/fixtures/wpt/resource-timing/iframe-failed-commit.html +++ b/test/fixtures/wpt/resource-timing/iframe-failed-commit.html @@ -3,6 +3,7 @@ Resource Timing - test that unsuccessful iframes create entries + @@ -20,6 +21,10 @@ return load.iframe_with_attrs(path, {"csp": "default-src 'none'"}); }; +const load_iframe_with_csp_no_navigation = async path => { + return load.iframe_with_attrs(path, {"csp": "default-src 'none'"}, () => {}, true); +} + // Runs a test (labeled by the given label) to verify that loading an iframe // with the given URL generates a PerformanceResourceTiming entry and that the // entry does not expose sensitive timing attributes. @@ -46,12 +51,12 @@ }; // Runs a test (labeled by the given label) to verify that loading an iframe -// with the given URL, an empty response body and under a "default-src 'none' -// Content-Security-Policy generates a PerformanceResourceTiming entry and that -// the entry does expose sensitive timing attributes. -const empty_unmasked_entry_with_csp_test = (url, label) => { - return attribute_test(load_iframe_with_csp, url, - invariants.assert_tao_pass_no_redirect_http_empty, label); +// with the given URL under a "default-src 'none' Content-Security-Policy +// generates a PerformanceResourceTiming entry and that the entry does not +// expose sensitive timing attributes. +const non_navigating_masked_entry_with_csp_test = (url, label) => { + return attribute_test(load_iframe_with_csp_no_navigation, url, + invariants.assert_tao_failure_resource, label); }; const {REMOTE_ORIGIN, ORIGINAL_HOST, HTTPS_PORT} = get_host_info(); @@ -68,7 +73,8 @@ unmasked_entry_with_csp_test("/resource-timing/resources/csp-default-none.html", "Same-origin iframe that complies with CSP attribute gets reported"); -unmasked_entry_with_csp_test("/resource-timing/resources/green-frame.html", +// masked because this will load an error page which is cross-origin. +masked_entry_with_csp_test("/resource-timing/resources/green-frame.html", "Same-origin iframe that doesn't comply with CSP attribute gets reported"); masked_entry_with_csp_test( @@ -79,7 +85,7 @@ new URL("/resource-timing/resources/green-frame.html", REMOTE_ORIGIN), "Cross-origin iframe that doesn't comply with CSP attribute gets reported"); -empty_unmasked_entry_with_csp_test( +masked_entry_with_csp_test( "/resource-timing/resources/200_empty.asis", "Same-origin empty iframe with a 200 status gets reported"); @@ -87,19 +93,19 @@ new URL("/resource-timing/resources/200_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 200 status gets reported"); -unmasked_entry_with_csp_test( - new URL("/resource-timing/resources/204_empty.asis"), +non_navigating_masked_entry_with_csp_test( + new URL("/resource-timing/resources/204_empty.asis", location.origin), "Same-origin empty iframe with a 204 status gets reported"); -unmasked_entry_with_csp_test( - new URL("/resource-timing/resources/205_empty.asis"), +non_navigating_masked_entry_with_csp_test( + new URL("/resource-timing/resources/205_empty.asis", location.origin), "Same-origin empty iframe with a 205 status gets reported"); -masked_entry_with_csp_test( +non_navigating_masked_entry_with_csp_test( new URL("/resource-timing/resources/204_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 204 status gets reported"); -masked_entry_with_csp_test( +non_navigating_masked_entry_with_csp_test( new URL("/resource-timing/resources/205_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 205 status gets reported"); diff --git a/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html b/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html index 5f99a5cab2de6b..02d1c362c9df49 100644 --- a/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html +++ b/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html @@ -4,9 +4,21 @@ + + - \ No newline at end of file + diff --git a/test/fixtures/wpt/resource-timing/initiator-type/link.html b/test/fixtures/wpt/resource-timing/initiator-type/link.html index c49576a8e650bc..43367ac3d501e2 100644 --- a/test/fixtures/wpt/resource-timing/initiator-type/link.html +++ b/test/fixtures/wpt/resource-timing/initiator-type/link.html @@ -1,38 +1,35 @@ + - -Resource Timing initiator type: link - - - - - - + + Resource Timing initiator type: link + + + + + + + + + + + + - - - - - - - -
    This content forces a font to get fetched
+ // Verify there are enries for each of nested.css' nested resources. + initiator_type_test("resource_timing_test0.css?id=n1", "css", "css resources embedded in css"); + initiator_type_test("fonts/Ahem.ttf?id=n1", "css", "font resources embedded in css"); + initiator_type_test("blue.png?id=n1", "css", "image resources embedded in css"); + initiator_type_test("resource_timing_test0.css?id=prefetch", "link", ""); + initiator_type_test("resource_timing_test0.css?id=preload", "link", ""); + initiator_type_test("manifest.json", "link", ""); + initiator_type_test("resources/empty.js?id=modulePreload", "other", "module preload"); + +
    This content forces a font to get fetched
diff --git a/test/fixtures/wpt/resource-timing/initiator-type/script.html b/test/fixtures/wpt/resource-timing/initiator-type/script.html index dbd6a131decae1..6e9e3ae7eef361 100644 --- a/test/fixtures/wpt/resource-timing/initiator-type/script.html +++ b/test/fixtures/wpt/resource-timing/initiator-type/script.html @@ -12,6 +12,7 @@ + diff --git a/test/fixtures/wpt/resource-timing/initiator-type/video.html b/test/fixtures/wpt/resource-timing/initiator-type/video.html index 16f3b3dea5f1e8..2d8c9dcc474c2c 100644 --- a/test/fixtures/wpt/resource-timing/initiator-type/video.html +++ b/test/fixtures/wpt/resource-timing/initiator-type/video.html @@ -19,14 +19,14 @@ src="/resource-timing/resources/empty.py?id=track"> diff --git a/test/fixtures/wpt/resource-timing/initiator-type/workers.html b/test/fixtures/wpt/resource-timing/initiator-type/workers.html index 3a23ad71a31555..a3da99356db5e2 100644 --- a/test/fixtures/wpt/resource-timing/initiator-type/workers.html +++ b/test/fixtures/wpt/resource-timing/initiator-type/workers.html @@ -17,7 +17,7 @@ new Worker(moduleWorkerURL, {type: "module"}); new Worker(workerURL, {type: "classic"}); initiator_type_test(workerURL, "other", "classic worker"); - initiator_type_test(moduleWorkerURL, "other", "module worker"); + initiator_type_test(moduleWorkerURL, "script", "module worker"); diff --git a/test/fixtures/wpt/resource-timing/interim-response-times.h2.html b/test/fixtures/wpt/resource-timing/interim-response-times.h2.html new file mode 100644 index 00000000000000..4b1ca93ff7bd62 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/interim-response-times.h2.html @@ -0,0 +1,74 @@ + + + + + +Resource Timing: PerformanceResourceTiming interim resource times + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/interim-response-times.html b/test/fixtures/wpt/resource-timing/interim-response-times.html new file mode 100644 index 00000000000000..a4d03f599ee5a7 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/interim-response-times.html @@ -0,0 +1,72 @@ + + + + + +Resource Timing: PerformanceResourceTiming interim resource times + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/internal-resources-not-counted.html b/test/fixtures/wpt/resource-timing/internal-resources-not-counted.html new file mode 100644 index 00000000000000..a746e2adfa32be --- /dev/null +++ b/test/fixtures/wpt/resource-timing/internal-resources-not-counted.html @@ -0,0 +1,39 @@ + + +Resource Timing should not include internal resources + + + + + +

This test validates that image resources which are part of an element's +UA-defined interface are not exposed to the performance timeline. This uses an +<audio> element as an example of an element with internal resources used +for the playback controls, and verifies that resource timing entries are not +created. +

+ + + + + diff --git a/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html b/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html new file mode 100644 index 00000000000000..b8bba5614d0d12 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html @@ -0,0 +1,33 @@ + + +Test ResourceTiming reporting for cross-origin iframe. + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html b/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html new file mode 100644 index 00000000000000..6b60305ded2e99 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html @@ -0,0 +1,53 @@ + + +Make sure that resources fetched by cross origin CSS are not in the timeline. + + + + + + + +
    Some content
+ diff --git a/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html b/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html index 278c78e320e98c..6990c6c06082e5 100644 --- a/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html +++ b/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html @@ -4,6 +4,7 @@ This test validates the values in resource timing for cross-origin redirects. + @@ -15,20 +16,26 @@ diff --git a/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html b/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html new file mode 100644 index 00000000000000..ea47ae3a7950a2 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html @@ -0,0 +1,38 @@ + + + + + +This test validates that resource timing entires should always be queued regardless the size of the buffer. + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html new file mode 100644 index 00000000000000..b99183a49cd84c --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html @@ -0,0 +1,53 @@ + + + + Resource timing attributes are consistent for the same-origin subresources. + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html new file mode 100644 index 00000000000000..5bab39e2760728 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html @@ -0,0 +1,34 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/resource-timing-level1.js b/test/fixtures/wpt/resource-timing/resource-timing-level1.js index 95b5cdfb1ed0ca..6167777fe68fa3 100644 --- a/test/fixtures/wpt/resource-timing/resource-timing-level1.js +++ b/test/fixtures/wpt/resource-timing/resource-timing-level1.js @@ -235,47 +235,6 @@ window.onload = }); }); - // Test that responseStart uses the timing of 1XX responses by - // synthesizing a delay between a 100 and 200 status, and verifying that - // this delay is included before responseEnd. If the delay is not - // included, this implies that the 200 status line was (incorrectly) used - // for responseStart timing, despite the 100 response arriving earlier. - // - // Source: "In the case where more than one response is available for a - // request, due to an Informational 1xx response, the reported - // responseStart value is that of the first response to the last - // request." - [ - { initiator: "iframe", response: "(done)", mime: mimeHtml }, - { initiator: "xmlhttprequest", response: "(done)", mime: mimeText }, - { initiator: "script", response: '"";', mime: mimeScript }, - { initiator: "link", response: ".unused{}", mime: mimeCss }, - ] - .forEach(function (template) { - testCases.push({ - description: "'" + template.initiator + " responseStart uses 1XX (first) response timings'", - test: function (test) { - initiateFetch( - test, - template.initiator, - getSyntheticUrl("status:100" - + "&flush" - + "&" + serverStepDelay + "ms" - + "&status:200" - + "&mime:" + template.mime - + "&send:" + encodeURIComponent(template.response)), - function (initiator, entry) { - assert_greater_than_equal( - entry.responseEnd, - entry.responseStart + serverStepDelay, - "HTTP/1.1 1XX (first) response should determine 'responseStart' timing."); - - test.done(); - }); - } - }); - }); - // Function to run the next case in the queue. var currentTestIndex = -1; function runNextCase() { diff --git a/test/fixtures/wpt/resource-timing/resources/child_script.js b/test/fixtures/wpt/resource-timing/resources/child_script.js new file mode 100644 index 00000000000000..8b137891791fe9 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/child_script.js @@ -0,0 +1 @@ + diff --git a/test/fixtures/wpt/resource-timing/resources/delay-load.html b/test/fixtures/wpt/resource-timing/resources/delay-load.html new file mode 100644 index 00000000000000..4898c1be8ebfff --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/delay-load.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/fixtures/wpt/resource-timing/resources/entry-invariants.js b/test/fixtures/wpt/resource-timing/resources/entry-invariants.js index 4bef9496103ca6..78d43d1b01e451 100644 --- a/test/fixtures/wpt/resource-timing/resources/entry-invariants.js +++ b/test/fixtures/wpt/resource-timing/resources/entry-invariants.js @@ -1,3 +1,19 @@ +const await_with_timeout = async (delay, message, promise, cleanup = ()=>{}) => { + let timeout_id; + const timeout = new Promise((_, reject) => { + timeout_id = step_timeout(() => + reject(new DOMException(message, "TimeoutError")), delay) + }); + let result = null; + try { + result = await Promise.race([promise, timeout]); + clearTimeout(timeout_id); + } finally { + cleanup(); + } + return result; +}; + // Asserts that the given attributes are present in 'entry' and hold equal // values. const assert_all_equal_ = (entry, attributes) => { @@ -75,8 +91,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -98,8 +112,6 @@ const invariants = { "secureConnectionStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -139,8 +151,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -172,8 +182,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -196,8 +204,6 @@ const invariants = { "secureConnectionStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -229,8 +235,6 @@ const invariants = { "workerStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -405,8 +409,6 @@ const invariants = { "requestStart", "responseStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); assert_ordered_(entry, [ @@ -440,8 +442,6 @@ const invariants = { "requestStart", "responseStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); } @@ -467,7 +467,10 @@ const attribute_test_internal = (loader, path, validator, run_test, test_label) }); await loader(path, validator); - const entry = await(loaded_entry); + const entry = await await_with_timeout(2000, + "Timeout was reached before entry fired", + loaded_entry); + assert_not_equals(entry, null, 'No entry was received'); run_test(entry); }, test_label); }; @@ -485,11 +488,13 @@ const attribute_test_with_validator = (loader, path, validator, run_test, test_l attribute_test_internal(loader, path, validator, run_test, test_label); }; -const network_error_entry_test = (originalURL, args, label) => { +const network_error_entry_test = (originalURL, args, label, loader) => { const url = new URL(originalURL, location.href); const search = new URLSearchParams(url.search.substr(1)); const timeBefore = performance.now(); - loader = () => new Promise(resolve => fetch(url, args).catch(resolve)); + + // Load using `fetch()`, unless we're given a specific loader for this test. + loader ??= () => new Promise(resolve => fetch(url, args).catch(resolve)); attribute_test( loader, url, diff --git a/test/fixtures/wpt/resource-timing/resources/frame-timing.js b/test/fixtures/wpt/resource-timing/resources/frame-timing.js index e0c364e9b2c3e2..019bd424b55065 100644 --- a/test/fixtures/wpt/resource-timing/resources/frame-timing.js +++ b/test/fixtures/wpt/resource-timing/resources/frame-timing.js @@ -1,48 +1,63 @@ function test_frame_timing_before_load_event(type) { - promise_test(async t => { - const {document, performance} = type === 'frame' ? window.parent : window; - const delay = 500; - const frame = document.createElement(type); - t.add_cleanup(() => frame.remove()); - await new Promise(resolve => { - frame.addEventListener('load', resolve); - frame.src = `resources/iframe-with-delay.sub.html?delay=${delay}`; - (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); - }); + promise_test(async t => { + const {document, performance} = type === 'frame' ? window.parent : window; + const delay = 500; + const frame = document.createElement(type); + t.add_cleanup(() => frame.remove()); + await new Promise(resolve => { + frame.addEventListener('load', resolve); + frame.src = `/resource-timing/resources/iframe-with-delay.sub.html?delay=${delay}`; + (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); + }); - const entries = performance.getEntriesByName(frame.src); - const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; - assert_equals(entries.length, 1); - assert_equals(entries[0].initiatorType, type); - assert_greater_than(performance.now(), entries[0].responseEnd + delay); - const domContentLoadedEventAbsoluteTime = navigationEntry.domContentLoadedEventStart + frame.contentWindow.performance.timeOrigin; - const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; - assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); - }, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); + const entries = performance.getEntriesByName(frame.src); + const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; + assert_equals(entries.length, 1); + assert_equals(entries[0].initiatorType, type); + assert_greater_than(performance.now(), entries[0].responseEnd + delay); + const domContentLoadedEventAbsoluteTime = + navigationEntry.domContentLoadedEventStart + + frame.contentWindow.performance.timeOrigin; + const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; + assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); + }, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); } -function test_frame_timing_change_src(type) { - promise_test(async t => { - const {document, performance} = type === 'frame' ? window.parent : window; - const frame = document.createElement(type); - t.add_cleanup(() => frame.remove()); - await new Promise(resolve => { - const done = () => { - resolve(); - frame.removeEventListener('load', done); - } - frame.addEventListener('load', done); - frame.src = 'resources/green.html?1'; - (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); - }); +function test_frame_timing_change_src(type, + origin1 = document.origin, + origin2 = document.origin, + tao = false, label = '') { + const uid = token(); + promise_test(async t => { + const {document, performance} = type === 'frame' ? window.parent : window; + const frame = document.createElement(type); + t.add_cleanup(() => frame.remove()); + function createURL(origin) { + const url = new URL(`${origin}/resource-timing/resources/green.html`, location.href); + url.searchParams.set("uid", uid); + if (tao) + url.searchParams.set("pipe", "header(Timing-Allow-Origin, *)"); + return url.toString(); + } - await new Promise(resolve => { - frame.addEventListener('load', resolve); - frame.src = 'resources/green.html?2'; - }); + await new Promise(resolve => { + const done = () => { + resolve(); + frame.removeEventListener('load', done); + } + frame.addEventListener('load', done); + frame.src = createURL(origin1); + const root = type === 'frame' ? document.querySelector('frameset') : document.body; + root.appendChild(frame); + }); - const entries = performance.getEntries().filter(e => e.name.includes('green.html')); - assert_equals(entries.length, 2); - }, `A ${type} should report separate RT entries if its src changed from the outside`); -} \ No newline at end of file + await new Promise(resolve => { + frame.addEventListener('load', resolve); + frame.src = createURL(origin2); + }); + + const entries = performance.getEntries().filter(e => e.name.includes(uid)); + assert_equals(entries.length, 2); + }, label || `A ${type} should report separate RT entries if its src changed from the outside`); +} diff --git a/test/fixtures/wpt/resource-timing/resources/get-resourceID.js b/test/fixtures/wpt/resource-timing/resources/get-resourceID.js new file mode 100644 index 00000000000000..3fe499226a405d --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/get-resourceID.js @@ -0,0 +1,30 @@ +function getResourceID(resourceName) { + return new Promise((resolve) => { + const observer = new PerformanceObserver((list) => { + const entries = list.getEntriesByType("resource"); + for (const entry of entries) { + if (entry.name.endsWith(resourceName)) { + observer.disconnect(); + resolve(`${entry.name}/${entry.startTime}`); + return; + } + } + }); + observer.observe({ entryTypes: ["resource"] }); + }); +} + +function getDocumentResourceID() { + return new Promise((resolve) => { + const observer = new PerformanceObserver((list) => { + const entries = list.getEntriesByType("navigation"); + if (entries.length > 0) { + observer.disconnect(); + const [entry] = entries; + const { name, startTime } = entry; + resolve(`${name}/${startTime}`); + } + }); + observer.observe({ entryTypes: ["navigation"] }); + }); +} diff --git a/test/fixtures/wpt/resource-timing/resources/loadingResources.js b/test/fixtures/wpt/resource-timing/resources/loadingResources.js new file mode 100644 index 00000000000000..e5d5d71982af05 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/loadingResources.js @@ -0,0 +1,21 @@ +//Fetching the Stylesheet +var link = document.createElement("link"); +link.rel = "stylesheet"; +link.href = "../resources/empty_style.css"; +document.head.appendChild(link); + +// Fetching an image +var img = document.createElement("img"); +img.src = "/images/blue.png"; +img.alt = "Sample Image for testing initiator Attribute"; +document.body.appendChild(img); + +//Inserting a html document in an iframe +var iframe = document.createElement("iframe"); +iframe.src = "../resources/green.html"; +document.body.appendChild(iframe); + +// Inserting a script element +var script = document.createElement("script"); +script.src = "../resources/empty.js"; +document.body.appendChild(script); diff --git a/test/fixtures/wpt/resource-timing/resources/nested-contexts.js b/test/fixtures/wpt/resource-timing/resources/nested-contexts.js index c0822943e86a68..31337ae5da2e18 100644 --- a/test/fixtures/wpt/resource-timing/resources/nested-contexts.js +++ b/test/fixtures/wpt/resource-timing/resources/nested-contexts.js @@ -22,22 +22,12 @@ const post_refresh_url = const setup_navigate_or_refresh = (type, pre, post) => { const verify_document_navigate_not_observable = () => { - const entries = performance.getEntriesByType("resource"); - let found_first_document = false; - for (entry of entries) { - if (entry.name == pre) { - found_first_document = true; - } - if (entry.name == post) { - opener.postMessage(`FAIL - ${type} document should not be observable`, - `*`); - return; - } - } - if (!found_first_document) { - opener.postMessage("FAIL - initial document should be observable", "*"); - return; + if (performance.getEntriesByName(post).length) { + opener.postMessage(`FAIL - ${type} document should not be observable`, + `*`); + } + opener.postMessage("PASS", "*"); } window.addEventListener("message", e => { @@ -57,21 +47,8 @@ const setup_refresh_test = () => { const setup_back_navigation = pushed_url => { const verify_document_navigate_not_observable = navigated_back => { - const entries = performance.getEntriesByType("resource"); - let found_first_document = false; - for (entry of entries) { - if (entry.name == pre_navigate_url) { - found_first_document = true; - } - if (entry.name == post_navigate_url) { - opener.postMessage("FAIL - navigated document exposed", "*"); - return; - } - } - if (!found_first_document) { - opener.postMessage(`FAIL - first document not exposed. navigated_back ` + - `is ${navigated_back}`, "*"); - return; + if (performance.getEntriesByName(post_navigate_url).length) { + opener.postMessage("FAIL - navigated document exposed", "*"); } if (navigated_back) { opener.postMessage("PASS", "*"); diff --git a/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html b/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html new file mode 100644 index 00000000000000..f47913468b68eb --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html @@ -0,0 +1,8 @@ + + + + + + +
    Some content
+ diff --git a/test/fixtures/wpt/resource-timing/resources/parent_script.js b/test/fixtures/wpt/resource-timing/resources/parent_script.js new file mode 100644 index 00000000000000..01ec0c5823de97 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/parent_script.js @@ -0,0 +1 @@ +import './child.js'; diff --git a/test/fixtures/wpt/resource-timing/resources/resource-loaders.js b/test/fixtures/wpt/resource-timing/resources/resource-loaders.js index 99a2c28d2b3b27..37fea16b1750fa 100644 --- a/test/fixtures/wpt/resource-timing/resources/resource-loaders.js +++ b/test/fixtures/wpt/resource-timing/resources/resource-loaders.js @@ -1,23 +1,38 @@ const load = { - _cache_bust_value: Math.random().toString().substr(2), cache_bust: path => { let url = new URL(path, location.origin); url.href += (url.href.includes("?")) ? '&' : '?'; - url.href += "unique=" + load._cache_bust_value++ + // The `Number` type in Javascript, when interpreted as an integer, can only + // safely represent [-2^53 + 1, 2^53 - 1] without the loss of precision [1]. + // We do not generate a global value and increment from it, as the increment + // might not have enough precision to be reflected. + // + // [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number + url.href += "unique=" + Math.random().toString().substring(2); return url.href; }, - // Returns a promise that settles once the given path has been fetched as an - // image resource. - image: path => { + image_with_attrs: async (path, attribute_map) => { return new Promise(resolve => { const img = new Image(); + for (const key in attribute_map) + img[key] = attribute_map[key]; img.onload = img.onerror = resolve; img.src = load.cache_bust(path); }); }, + // Returns a promise that settles once the given path has been fetched as an + // image resource. + image: path => { + return load.image_with_attrs(path, undefined); + }, + + // Returns a promise that settles once the given path has been fetched as an + // image resource. + image_cors: path => load.image_with_attrs(path, {crossOrigin: "anonymous"}), + // Returns a promise that settles once the given path has been fetched as a // font resource. font: path => { @@ -37,10 +52,13 @@ const load = { }); }, - // Returns a promise that settles once the given path has been fetched as a - // stylesheet resource. - stylesheet: async path => { + stylesheet_with_attrs: async (path, attribute_map) => { const link = document.createElement("link"); + if (attribute_map instanceof Object) { + for (const [key, value] of Object.entries(attribute_map)) { + link[key] = value; + } + } link.rel = "stylesheet"; link.type = "text/css"; link.href = load.cache_bust(path); @@ -54,7 +72,13 @@ const load = { document.head.removeChild(link); }, - iframe_with_attrs: async (path, attribute_map, validator) => { + // Returns a promise that settles once the given path has been fetched as a + // stylesheet resource. + stylesheet: async path => { + return load.stylesheet_with_attrs(path, undefined); + }, + + iframe_with_attrs: async (path, attribute_map, validator, skip_wait_for_navigation) => { const frame = document.createElement("iframe"); if (attribute_map instanceof Object) { for (const [key, value] of Object.entries(attribute_map)) { @@ -66,11 +90,17 @@ const load = { }); frame.src = load.cache_bust(path); document.body.appendChild(frame); - await loaded; + if ( !skip_wait_for_navigation ) { + await loaded; + } if (validator instanceof Function) { validator(frame); } - document.body.removeChild(frame); + // since we skipped the wait for load animation, we cannot + // remove the iframe here since the request could get cancelled + if ( !skip_wait_for_navigation ) { + document.body.removeChild(frame); + } }, // Returns a promise that settles once the given path has been fetched as an @@ -79,10 +109,13 @@ const load = { return load.iframe_with_attrs(path, undefined, validator); }, - // Returns a promise that settles once the given path has been fetched as a - // script. - script: async path => { + script_with_attrs: async (path, attribute_map) => { const script = document.createElement("script"); + if (attribute_map instanceof Object) { + for (const [key, value] of Object.entries(attribute_map)) { + script[key] = value; + } + } const loaded = new Promise(resolve => { script.onload = script.onerror = resolve; }); @@ -92,21 +125,29 @@ const load = { document.body.removeChild(script); }, + // Returns a promise that settles once the given path has been fetched as a + // script. + script: async path => { + return load.script_with_attrs(path, undefined); + }, + // Returns a promise that settles once the given path has been fetched as an // object. object: async (path, type) => { const object = document.createElement("object"); - const loaded = new Promise(resolve => { + const object_load_settled = new Promise(resolve => { object.onload = object.onerror = resolve; }); object.data = load.cache_bust(path); if (type) { object.type = type; } - object.style = "width: 0px; height: 0px"; document.body.appendChild(object); - await loaded; - document.body.removeChild(object); + await await_with_timeout(2000, + "Timeout was reached before load or error events fired", + object_load_settled, + () => { document.body.removeChild(object) } + ); }, // Returns a promise that settles once the given path has been fetched diff --git a/test/fixtures/wpt/resource-timing/resources/test-initiator.js b/test/fixtures/wpt/resource-timing/resources/test-initiator.js new file mode 100644 index 00000000000000..f839b463c56d8f --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/test-initiator.js @@ -0,0 +1,16 @@ +function testResourceInitiator(resourceName, expectedInitiator) { + return new Promise(resolve => { + const observer = new PerformanceObserver(list => { + const entries = list.getEntriesByType('resource'); + for (const entry of entries) { + if (entry.name.endsWith(resourceName)) { + observer.disconnect(); + assert_equals(entry.initiator, expectedInitiator, `Test ${resourceName} initiator`); + resolve(); + return; + } + } + }); + observer.observe({entryTypes: ['resource']}); + }); +} \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/response-status-code.html b/test/fixtures/wpt/resource-timing/response-status-code.html new file mode 100644 index 00000000000000..3a184c6f016b28 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/response-status-code.html @@ -0,0 +1,165 @@ + + + + +This test validates the response status of resources. + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/sizes-redirect-img.html b/test/fixtures/wpt/resource-timing/sizes-redirect-img.html index 786018d0c4634c..e440029782b5d5 100644 --- a/test/fixtures/wpt/resource-timing/sizes-redirect-img.html +++ b/test/fixtures/wpt/resource-timing/sizes-redirect-img.html @@ -18,7 +18,7 @@ const redirectUrl = (redirectSourceOrigin, targetUrl) => { return redirectSourceOrigin + - '/resource-timing/resources/redirect-cors.py?timing_allow_origin=*' + + '/resource-timing/resources/redirect-cors.py?allow_origin=*&timing_allow_origin=*' + '&location=' + encodeURIComponent(targetUrl); }; @@ -35,18 +35,18 @@ verify_entry, "PerformanceResourceTiming sizes redirect image - same origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, baseUrl), verify_entry, "PerformanceResourceTiming sizes redirect image - cross origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, redirectUrl(hostInfo.HTTP_ORIGIN, baseUrl)), verify_entry, "PerformanceResourceTiming sizes redirect image - cross origin to same origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_ORIGIN, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, redirectUrl(hostInfo.HTTP_ORIGIN, diff --git a/test/fixtures/wpt/resource-timing/tentative/document-initiated.html b/test/fixtures/wpt/resource-timing/tentative/document-initiated.html new file mode 100644 index 00000000000000..eea2bb2761d79c --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/document-initiated.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample Image for testing initiator Attribute + + + + + diff --git a/test/fixtures/wpt/resource-timing/tentative/script-initiated.html b/test/fixtures/wpt/resource-timing/tentative/script-initiated.html new file mode 100644 index 00000000000000..d6f3d1a32034a7 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/script-initiated.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html b/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html new file mode 100644 index 00000000000000..d12e3d193d0837 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/tojson.html b/test/fixtures/wpt/resource-timing/tojson.html index 7a6187d3d55bcd..2564b855dffb8e 100644 --- a/test/fixtures/wpt/resource-timing/tojson.html +++ b/test/fixtures/wpt/resource-timing/tojson.html @@ -47,7 +47,9 @@ 'transferSize', 'encodedBodySize', 'decodedBodySize', - 'renderBlockingStatus' + 'renderBlockingStatus', + 'responseStatus', + 'contentType', ]; for (const key of performanceResourceTimingKeys) { try { diff --git a/test/fixtures/wpt/resources/check-layout-th.js b/test/fixtures/wpt/resources/check-layout-th.js index f14ca3246b8ea2..54ddb35f311200 100644 --- a/test/fixtures/wpt/resources/check-layout-th.js +++ b/test/fixtures/wpt/resources/check-layout-th.js @@ -218,6 +218,7 @@ window.checkLayout = function(selectorList, callDone = true) nodes = Array.prototype.slice.call(nodes); var checkedLayout = false; Array.prototype.forEach.call(nodes, function(node) { + const title = node.title == '' ? '' : `: ${node.title}`; test(function(t) { var container = node.parentNode.className == 'container' ? node.parentNode : node; var prefix = @@ -240,7 +241,7 @@ window.checkLayout = function(selectorList, callDone = true) } checkedLayout |= !passed; } - }, selectorList + ' ' + String(++testNumber)); + }, `${selectorList} ${++testNumber}${title}`); }); if (!checkedLayout) { console.error("No valid data-* attributes found in selector list : " + selectorList); diff --git a/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js b/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js deleted file mode 100644 index 99a3e911eb6336..00000000000000 --- a/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Polyfill for attaching shadow trees for declarative Shadow DOM for - * implementations that do not support declarative Shadow DOM. - * - * Note: this polyfill will feature-detect the native feature, and do nothing - * if supported. - * - * See: https://github.com/whatwg/html/pull/5465 - * - * root: The root of the subtree in which to upgrade shadow roots - * - */ - -function polyfill_declarative_shadow_dom(root) { - if (HTMLTemplateElement.prototype.hasOwnProperty('shadowRootMode')) - return; - root.querySelectorAll("template[shadowrootmode]").forEach(template => { - const mode = template.getAttribute("shadowrootmode"); - const delegatesFocus = template.hasAttribute("shadowrootdelegatesfocus"); - const shadowRoot = template.parentNode.attachShadow({ mode, delegatesFocus }); - shadowRoot.appendChild(template.content); - template.remove(); - polyfill_declarative_shadow_dom(shadowRoot); - }); -} diff --git a/test/fixtures/wpt/resources/idlharness.js b/test/fixtures/wpt/resources/idlharness.js index 8f741b09b26bcb..4cf19234af20eb 100644 --- a/test/fixtures/wpt/resources/idlharness.js +++ b/test/fixtures/wpt/resources/idlharness.js @@ -566,6 +566,7 @@ IdlArray.prototype.is_json_type = function(type) case "Uint8ClampedArray": case "BigInt64Array": case "BigUint64Array": + case "Float16Array": case "Float32Array": case "Float64Array": case "ArrayBuffer": diff --git a/test/fixtures/wpt/resources/testdriver-actions.js b/test/fixtures/wpt/resources/testdriver-actions.js index 3e5ba74b4cab35..edb4759954d4c3 100644 --- a/test/fixtures/wpt/resources/testdriver-actions.js +++ b/test/fixtures/wpt/resources/testdriver-actions.js @@ -290,7 +290,7 @@ }, /** - * Create a keyDown event for the current default key source + * Create a keyUp event for the current default key source * * @param {String} key - Key to release * @param {String?} sourceName - Named key source to use or null for the default key source diff --git a/test/fixtures/wpt/resources/testdriver.js b/test/fixtures/wpt/resources/testdriver.js index ddf723cb3ee8a5..d05be1d7df9a6a 100644 --- a/test/fixtures/wpt/resources/testdriver.js +++ b/test/fixtures/wpt/resources/testdriver.js @@ -49,6 +49,58 @@ * @namespace {test_driver} */ window.test_driver = { + /** + Represents `WebDriver BiDi `_ protocol. + */ + bidi: { + /** + * `log `_ module. + */ + log: { + /** + * `log.entryAdded `_ event. + */ + entry_added: { + /** + * Subscribe to the `log.entryAdded` event. This does not + * add actual listeners. To listen to the event, use the + * `on` or `once` methods. + * @param {{contexts?: null | (string | Window)[]}} params - Parameters for the subscription. + * * `contexts`: an array of window proxies or browsing + * context ids to listen to the event. If not provided, the + * event subscription is done for the current window's + * browsing context. `null` for the global subscription. + * @return {Promise} + */ + subscribe: async function (params = {}) { + return window.test_driver_internal.bidi.log.entry_added.subscribe(params); + }, + /** + * Add an event listener for the `log.entryAdded + * `_ event. Make sure `subscribe` is + * called before using this method. + * + * @param callback {function(event): void} - The callback + * to be called when the event is fired. + * @returns {function(): void} - A function to call to + * remove the event listener. + */ + on: function (callback) { + return window.test_driver_internal.bidi.log.entry_added.on(callback); + }, + once: function () { + return new Promise(resolve => { + const remove_handler = window.test_driver_internal.bidi.log.entry_added.on( + data => { + resolve(data); + remove_handler(); + }); + }); + }, + } + } + }, + /** * Set the context in which testharness.js is loaded * @@ -124,11 +176,10 @@ }, /** - * Triggers a user-initiated click + * Triggers a user-initiated mouse click. * - * If ``element`` isn't inside the - * viewport, it will be scrolled into view before the click - * occurs. + * If ``element`` isn't inside the viewport, it will be + * scrolled into view before the click occurs. * * If ``element`` is from a different browsing context, the * command will be run in that context. @@ -357,6 +408,25 @@ return window.test_driver_internal.set_window_rect(rect, context); }, + /** + * Gets a rect with the size and position on the screen from the current window state. + * + * Matches the behaviour of the `Get Window Rect + * `_ + * WebDriver command + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} fulfilled after the window rect is returned, or rejected + * in cases the WebDriver command returns errors. Returns a + * `WindowRect `_ + */ + get_window_rect: function(context=null) { + return window.test_driver_internal.get_window_rect(context); + }, + /** * Send a sequence of actions * @@ -647,7 +717,7 @@ * * This function places `Secure Payment * Confirmation `_ into - * an automated 'autoaccept' or 'autoreject' mode, to allow testing + * an automated 'autoAccept' or 'autoReject' mode, to allow testing * without user interaction with the transaction UX prompt. * * Matches the `Set SPC Transaction Mode @@ -667,8 +737,8 @@ * @param {String} mode - The `transaction mode * `_ * to set. Must be one of "``none``", - * "``autoaccept``", or - * "``autoreject``". + * "``autoAccept``", or + * "``autoReject``". * @param {WindowProxy} context - Browsing context in which * to run the call, or null for the current * browsing context. @@ -680,6 +750,42 @@ return window.test_driver_internal.set_spc_transaction_mode(mode, context); }, + /** + * Sets the current registration automation mode for Register Protocol Handlers. + * + * This function places `Register Protocol Handlers + * `_ into + * an automated 'autoAccept' or 'autoReject' mode, to allow testing + * without user interaction with the transaction UX prompt. + * + * Matches the `Set Register Protocol Handler Mode + * `_ + * WebDriver command. + * + * @example + * await test_driver.set_rph_registration_mode("autoAccept"); + * test.add_cleanup(() => { + * return test_driver.set_rph_registration_mode("none"); + * }); + * + * navigator.registerProtocolHandler('web+soup', 'soup?url=%s'); + * + * @param {String} mode - The `registration mode + * `_ + * to set. Must be one of "``none``", + * "``autoAccept``", or + * "``autoReject``". + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the transaction mode has been set, + * or rejected if setting the mode fails. + */ + set_rph_registration_mode: function(mode, context=null) { + return window.test_driver_internal.set_rph_registration_mode(mode, context); + }, + /** * Cancels the Federated Credential Management dialog * @@ -968,6 +1074,148 @@ */ get_virtual_sensor_information: function(sensor_type, context=null) { return window.test_driver_internal.get_virtual_sensor_information(sensor_type, context); + }, + + /** + * Overrides device posture set by hardware. + * + * Matches the `Set device posture + * `_ + * WebDriver command. + * + * @param {String} posture - A `DevicePostureType + * `_ + * either "continuous" or "folded". + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled when device posture is set. + * Rejected in case the WebDriver command errors out + * (including if a device posture of the given type + * does not exist). + */ + set_device_posture: function(posture, context=null) { + return window.test_driver_internal.set_device_posture(posture, context); + }, + + /** + * Removes device posture override and returns device posture control + * back to hardware. + * + * Matches the `Clear device posture + * `_ + * WebDriver command. + * + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled after the device posture override has + * been removed. Rejected in case the WebDriver + * command errors out. + */ + clear_device_posture: function(context=null) { + return window.test_driver_internal.clear_device_posture(context); + }, + + /** + * Runs the `bounce tracking timer algorithm + * `_, + * which removes all hosts from the stateful bounce tracking map, without + * regard for the bounce tracking grace period and returns a list of the + * deleted hosts. + * + * Matches the `Run Bounce Tracking Mitigations + * `_ + * WebDriver command. + * + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * @returns {Promise} Fulfilled after the bounce tracking timer + * algorithm has finished running. Returns an array + * of all hosts that were in the stateful bounce + * tracking map before deletion occurred. + */ + run_bounce_tracking_mitigations: function (context = null) { + return window.test_driver_internal.run_bounce_tracking_mitigations(context); + }, + + /** + * Creates a virtual pressure source. + * + * Matches the `Create virtual pressure source + * `_ + * WebDriver command. + * + * @param {String} source_type - A `virtual pressure source type + * `_ + * such as "cpu". + * @param {Object} [metadata={}] - Optional parameters described + * in `Create virtual pressure source + * `_. + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled when virtual pressure source is created. + * Rejected in case the WebDriver command errors out + * (including if a virtual pressure source of the + * same type already exists). + */ + create_virtual_pressure_source: function(source_type, metadata={}, context=null) { + return window.test_driver_internal.create_virtual_pressure_source(source_type, metadata, context); + }, + + /** + * Causes a virtual pressure source to report a new reading. + * + * Matches the `Update virtual pressure source + * `_ + * WebDriver command. + * + * @param {String} source_type - A `virtual pressure source type + * `_ + * such as "cpu". + * @param {String} sample - A `virtual pressure state + * `_ + * such as "critical". + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled after the reading update reaches the + * virtual pressure source. Rejected in case the + * WebDriver command errors out (including if a + * virtual pressure source of the given type does not + * exist). + */ + update_virtual_pressure_source: function(source_type, sample, context=null) { + return window.test_driver_internal.update_virtual_pressure_source(source_type, sample, context); + }, + + /** + * Removes created virtual pressure source. + * + * Matches the `Delete virtual pressure source + * `_ + * WebDriver command. + * + * @param {String} source_type - A `virtual pressure source type + * `_ + * such as "cpu". + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled after the virtual pressure source has + * been removed or if a pressure source of the given + * type does not exist. Rejected in case the + * WebDriver command errors out. + */ + remove_virtual_pressure_source: function(source_type, context=null) { + return window.test_driver_internal.remove_virtual_pressure_source(source_type, context); } }; @@ -980,6 +1228,21 @@ */ in_automation: false, + bidi: { + log: { + entry_added: { + async subscribe() { + throw new Error( + "bidi.log.entry_added.subscribe is not implemented by testdriver-vendor.js"); + }, + on() { + throw new Error( + "bidi.log.entry_added.on is not implemented by testdriver-vendor.js"); + } + } + } + }, + async click(element, coords) { if (this.in_automation) { throw new Error("click() is not implemented by testdriver-vendor.js"); @@ -1002,6 +1265,14 @@ throw new Error("get_named_cookie() is not implemented by testdriver-vendor.js"); }, + async get_computed_role(element) { + throw new Error("get_computed_role is a testdriver.js function which cannot be run in this context."); + }, + + async get_computed_name(element) { + throw new Error("get_computed_name is a testdriver.js function which cannot be run in this context."); + }, + async send_keys(element, keys) { if (this.in_automation) { throw new Error("send_keys() is not implemented by testdriver-vendor.js"); @@ -1046,6 +1317,10 @@ throw new Error("set_window_rect() is not implemented by testdriver-vendor.js"); }, + async get_window_rect(context=null) { + throw new Error("get_window_rect() is not implemented by testdriver-vendor.js"); + }, + async action_sequence(actions, context=null) { throw new Error("action_sequence() is not implemented by testdriver-vendor.js"); }, @@ -1094,6 +1369,10 @@ throw new Error("set_spc_transaction_mode() is not implemented by testdriver-vendor.js"); }, + set_rph_registration_mode: function(mode, context=null) { + return Promise.reject(new Error("unimplemented")); + }, + async cancel_fedcm_dialog(context=null) { throw new Error("cancel_fedcm_dialog() is not implemented by testdriver-vendor.js"); }, @@ -1140,6 +1419,30 @@ async get_virtual_sensor_information(sensor_type, context=null) { throw new Error("get_virtual_sensor_information() is not implemented by testdriver-vendor.js"); + }, + + async set_device_posture(posture, context=null) { + throw new Error("set_device_posture() is not implemented by testdriver-vendor.js"); + }, + + async clear_device_posture(context=null) { + throw new Error("clear_device_posture() is not implemented by testdriver-vendor.js"); + }, + + async run_bounce_tracking_mitigations(context=null) { + throw new Error("run_bounce_tracking_mitigations() is not implemented by testdriver-vendor.js"); + }, + + async create_virtual_pressure_source(source_type, metadata={}, context=null) { + throw new Error("create_virtual_pressure_source() is not implemented by testdriver-vendor.js"); + }, + + async update_virtual_pressure_source(source_type, sample, context=null) { + throw new Error("update_virtual_pressure_source() is not implemented by testdriver-vendor.js"); + }, + + async remove_virtual_pressure_source(source_type, context=null) { + throw new Error("remove_virtual_pressure_source() is not implemented by testdriver-vendor.js"); } }; })(); diff --git a/test/fixtures/wpt/resources/testharness.js b/test/fixtures/wpt/resources/testharness.js index 497ae23f0e83ee..7fd5336bf34ae9 100644 --- a/test/fixtures/wpt/resources/testharness.js +++ b/test/fixtures/wpt/resources/testharness.js @@ -91,7 +91,12 @@ } on_event(window, 'load', function() { + setTimeout(() => { this_obj.all_loaded = true; + if (tests.all_done()) { + tests.complete(); + } + },0); }); on_event(window, 'message', function(event) { @@ -852,7 +857,7 @@ promise = promiseOrConstructor; description = descriptionOrPromise; assert(maybeDescription === undefined, - "Too many args pased to no-constructor version of promise_rejects_dom"); + "Too many args passed to no-constructor version of promise_rejects_dom, or accidentally explicitly passed undefined"); } return bring_promise_to_current_realm(promise) .then(test.unreached_func("Should have rejected: " + description)) @@ -1196,6 +1201,23 @@ object.addEventListener(event, callback, false); } + // Internal helper function to provide timeout-like functionality in + // environments where there is no setTimeout(). (No timeout ID or + // clearTimeout().) + function fake_set_timeout(callback, delay) { + var p = Promise.resolve(); + var start = Date.now(); + var end = start + delay; + function check() { + if ((end - Date.now()) > 0) { + p.then(check); + } else { + callback(); + } + } + p.then(check); + } + /** * Global version of :js:func:`Test.step_timeout` for use in single page tests. * @@ -1207,7 +1229,8 @@ function step_timeout(func, timeout) { var outer_this = this; var args = Array.prototype.slice.call(arguments, 2); - return setTimeout(function() { + var local_set_timeout = typeof global_scope.setTimeout === "undefined" ? fake_set_timeout : setTimeout; + return local_set_timeout(function() { func.apply(outer_this, args); }, timeout * tests.timeout_multiplier); } @@ -2151,7 +2174,7 @@ func = funcOrConstructor; description = descriptionOrFunc; assert(maybeDescription === undefined, - "Too many args pased to no-constructor version of assert_throws_dom"); + "Too many args passed to no-constructor version of assert_throws_dom, or accidentally explicitly passed undefined"); } assert_throws_dom_impl(type, func, description, "assert_throws_dom", constructor) } @@ -2715,7 +2738,8 @@ Test.prototype.step_timeout = function(func, timeout) { var test_this = this; var args = Array.prototype.slice.call(arguments, 2); - return setTimeout(this.step_func(function() { + var local_set_timeout = typeof global_scope.setTimeout === "undefined" ? fake_set_timeout : setTimeout; + return local_set_timeout(this.step_func(function() { return func.apply(test_this, args); }), timeout * tests.timeout_multiplier); }; @@ -2746,6 +2770,7 @@ var timeout_full = timeout * tests.timeout_multiplier; var remaining = Math.ceil(timeout_full / interval); var test_this = this; + var local_set_timeout = typeof global_scope.setTimeout === 'undefined' ? fake_set_timeout : setTimeout; const step = test_this.step_func((result) => { if (result) { @@ -2756,7 +2781,7 @@ "Timed out waiting on condition"); } remaining--; - setTimeout(wait_for_inner, interval); + local_set_timeout(wait_for_inner, interval); } }); @@ -4169,11 +4194,7 @@ status ], ], - ["button", - {"onclick": "let evt = new Event('__test_restart'); " + - "let canceled = !window.dispatchEvent(evt);" + - "if (!canceled) { location.reload() }"}, - "Rerun"] + ["button", {"id":"rerun"}, "Rerun"] ]]; if (harness_status.status === harness_status.ERROR) { @@ -4205,6 +4226,13 @@ log.appendChild(render(summary_template, {num_tests:tests.length}, output_document)); + output_document.getElementById("rerun").addEventListener("click", + function() { + let evt = new Event('__test_restart'); + let canceled = !window.dispatchEvent(evt); + if (!canceled) { location.reload(); } + }); + forEach(output_document.querySelectorAll("section#summary label"), function(element) { @@ -4229,18 +4257,6 @@ }); }); - // This use of innerHTML plus manual escaping is not recommended in - // general, but is necessary here for performance. Using textContent - // on each individual adds tens of seconds of execution time for - // large test suites (tens of thousands of tests). - function escape_html(s) - { - return s.replace(/\&/g, "&") - .replace(/ { - var output_fn = "" + escape_html(assert.assert_name) + "("; - var prefix_len = output_fn.length; - var output_args = assert.args; - var output_len = output_args.reduce((prev, current) => prev+current, prefix_len); - if (output_len[output_len.length - 1] > 50) { - output_args = output_args.map((x, i) => - (i > 0 ? " ".repeat(prefix_len) : "" )+ x + (i < output_args.length - 1 ? ",\n" : "")); - } else { - output_args = output_args.map((x, i) => x + (i < output_args.length - 1 ? ", " : "")); - } - output_fn += escape_html(output_args.join("")); - output_fn += ')'; - var output_location; + + const table = asserts_output.querySelector("table"); + for (const assert of asserts) { + const status_class_name = status_class(Test.prototype.status_formats[assert.status]); + var output_fn = "(" + assert.args.join(", ") + ")"; if (assert.stack) { - output_location = assert.stack.split("\n", 1)[0].replace(/@?\w+:\/\/[^ "\/]+(?::\d+)?/g, " "); + output_fn += "\n"; + output_fn += assert.stack.split("\n", 1)[0].replace(/@?\w+:\/\/[^ "\/]+(?::\d+)?/g, " "); } - return "" + - "" + - Test.prototype.status_formats[assert.status] + "" + - "
" +
-                    output_fn +
-                    (output_location ? "\n" + escape_html(output_location) : "") +
-                    "
"; + table.appendChild(render( + ["tr", {"class":"overall-" + status_class_name}, + ["td", {"class":status_class_name}, Test.prototype.status_formats[assert.status]], + ["td", {}, ["pre", {}, ["strong", {}, assert.assert_name], output_fn]] ])); } - ).join("\n"); - rv += ""; - return rv; + return asserts_output; } - log.appendChild(document.createElementNS(xhtml_ns, "section")); var assertions = has_assertions(); - var html = "

Details

" + - "" + - (assertions ? "" : "") + - "" + - ""; - for (var i = 0; i < tests.length; i++) { - var test = tests[i]; - html += '' + - '"; - } - html += "
ResultTest NameAssertionMessage
' + - test.format_status() + - "" + - escape_html(test.name) + - "" + - (assertions ? escape_html(get_assertion(test)) + "" : "") + - escape_html(test.message ? tests[i].message : " ") + - (tests[i].stack ? "
" +
-                 escape_html(tests[i].stack) +
-                 "
": ""); + const section = render( + ["section", {}, + ["h2", {}, "Details"], + ["table", {"id":"results", "class":(assertions ? "assertions" : "")}, + ["thead", {}, + ["tr", {}, + ["th", {}, "Result"], + ["th", {}, "Test Name"], + (assertions ? ["th", {}, "Assertion"] : ""), + ["th", {}, "Message" ]]], + ["tbody", {}]]]); + + const tbody = section.querySelector("tbody"); + for (const test of tests) { + const status = test.format_status(); + const status_class_name = status_class(status); + tbody.appendChild(render( + ["tr", {"class":"overall-" + status_class_name}, + ["td", {"class":status_class_name}, status], + ["td", {}, test.name], + (assertions ? ["td", {}, get_assertion(test)] : ""), + ["td", {}, + test.message ?? "", + ["pre", {}, test.stack ?? ""]]])); if (!(test instanceof RemoteTest)) { - html += "
Asserts run" + get_asserts_output(test) + "
" + tbody.lastChild.lastChild.appendChild(get_asserts_output(test)); } - html += "
"; - try { - log.lastChild.innerHTML = html; - } catch (e) { - log.appendChild(document.createElementNS(xhtml_ns, "p")) - .textContent = "Setting innerHTML for the log threw an exception."; - log.appendChild(document.createElementNS(xhtml_ns, "pre")) - .textContent = html; } + log.appendChild(section); }; /* @@ -4410,13 +4408,20 @@ { var substitution_re = /\$\{([^ }]*)\}/g; - function do_substitution(input) { + function do_substitution(input) + { var components = input.split(substitution_re); var rv = []; - for (var i = 0; i < components.length; i += 2) { - rv.push(components[i]); - if (components[i + 1]) { - rv.push(String(substitutions[components[i + 1]])); + if (components.length === 1) { + rv = components; + } else if (substitutions) { + for (var i = 0; i < components.length; i += 2) { + if (components[i]) { + rv.push(components[i]); + } + if (substitutions[components[i + 1]]) { + rv.push(String(substitutions[components[i + 1]])); + } } } return rv; @@ -4772,6 +4777,15 @@ return "Untitled"; } + /** Fetches a JSON resource and parses it */ + async function fetch_json(resource) { + const response = await fetch(resource); + return await response.json(); + } + if (!global_scope.GLOBAL || !global_scope.GLOBAL.isShadowRealm()) { + expose(fetch_json, 'fetch_json'); + } + /** * Setup globals */ diff --git a/test/fixtures/wpt/resources/testharnessreport.js b/test/fixtures/wpt/resources/testharnessreport.js index e5cb40fe0ef652..405a2d8b06f00f 100644 --- a/test/fixtures/wpt/resources/testharnessreport.js +++ b/test/fixtures/wpt/resources/testharnessreport.js @@ -14,31 +14,6 @@ * parameters they are called with see testharness.js */ -function dump_test_results(tests, status) { - var results_element = document.createElement("script"); - results_element.type = "text/json"; - results_element.id = "__testharness__results__"; - var test_results = tests.map(function(x) { - return {name:x.name, status:x.status, message:x.message, stack:x.stack} - }); - var data = {test:window.location.href, - tests:test_results, - status: status.status, - message: status.message, - stack: status.stack}; - results_element.textContent = JSON.stringify(data); - - // To avoid a HierarchyRequestError with XML documents, ensure that 'results_element' - // is inserted at a location that results in a valid document. - var parent = document.body - ? document.body // is required in XHTML documents - : document.documentElement; // fallback for optional in HTML5, SVG, etc. - - parent.appendChild(results_element); -} - -add_completion_callback(dump_test_results); - /* If the parent window has a testharness_properties object, * we use this to provide the test settings. This is used by the * default in-browser runner to configure the timeout and the diff --git a/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js index 7dd5ba3f3fb013..60d82b9cf6a1fd 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js @@ -934,3 +934,36 @@ promise_test(async () => { assert_typed_array_equals(result4.value, new Uint8Array([0]).subarray(0, 0), 'second chunk from branch2 should be correct'); }, 'ReadableStream teeing with byte source: respond() and close() while both branches are pulling'); + +promise_test(async t => { + let pullCount = 0; + const arrayBuffer = new Uint8Array([0x01, 0x02, 0x03]).buffer; + const enqueuedChunk = new Uint8Array(arrayBuffer, 2); + assert_equals(enqueuedChunk.length, 1); + assert_equals(enqueuedChunk.byteOffset, 2); + const rs = new ReadableStream({ + type: 'bytes', + pull(c) { + ++pullCount; + if (pullCount === 1) { + c.enqueue(enqueuedChunk); + } + } + }); + + const [branch1, branch2] = rs.tee(); + const reader1 = branch1.getReader(); + const reader2 = branch2.getReader(); + + const [result1, result2] = await Promise.all([reader1.read(), reader2.read()]); + assert_equals(result1.done, false, 'reader1 done'); + assert_equals(result2.done, false, 'reader2 done'); + + const view1 = result1.value; + const view2 = result2.value; + // The first stream has the transferred buffer, but the second stream has the + // cloned buffer. + const underlying = new Uint8Array([0x01, 0x02, 0x03]).buffer; + assert_typed_array_equals(view1, new Uint8Array(underlying, 2), 'reader1 value'); + assert_typed_array_equals(view2, new Uint8Array([0x03]), 'reader2 value'); +}, 'ReadableStream teeing with byte source: reading an array with a byte offset should clone correctly'); diff --git a/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html b/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html new file mode 100644 index 00000000000000..58a4371186ece7 --- /dev/null +++ b/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html @@ -0,0 +1,18 @@ + + + diff --git a/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js b/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js index 37f8c9df169607..3bfe634a6e153d 100644 --- a/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js +++ b/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js @@ -105,7 +105,7 @@ async function transferMessagePortWith(constructor) { await transferMessagePortWithOrder3(new constructor()); } -async function advancedTransferMesagePortWith(constructor) { +async function advancedTransferMessagePortWith(constructor) { await transferMessagePortWithOrder4(new constructor()); await transferMessagePortWithOrder5(new constructor()); await transferMessagePortWithOrder6(new constructor()); @@ -166,7 +166,7 @@ async function mixedTransferMessagePortWithOrder3() { ); } -async function mixedTransferMesagePortWith() { +async function mixedTransferMessagePortWith() { await mixedTransferMessagePortWithOrder1(); await mixedTransferMessagePortWithOrder2(); await mixedTransferMessagePortWithOrder3(); @@ -185,19 +185,19 @@ promise_test(async t => { }, "Transferring a MessagePort with a TransformStream should set `.ports`"); promise_test(async t => { - await transferMessagePortWith(ReadableStream); + await advancedTransferMessagePortWith(ReadableStream); }, "Transferring a MessagePort with a ReadableStream should set `.ports`, advanced"); promise_test(async t => { - await transferMessagePortWith(WritableStream); + await advancedTransferMessagePortWith(WritableStream); }, "Transferring a MessagePort with a WritableStream should set `.ports`, advanced"); promise_test(async t => { - await transferMessagePortWith(TransformStream); + await advancedTransferMessagePortWith(TransformStream); }, "Transferring a MessagePort with a TransformStream should set `.ports`, advanced"); promise_test(async t => { - await mixedTransferMesagePortWith(); + await mixedTransferMessagePortWith(); }, "Transferring a MessagePort with multiple streams should set `.ports`"); test(() => { diff --git a/test/fixtures/wpt/url/META.yml b/test/fixtures/wpt/url/META.yml index 094b266b64b61b..415bd0f094c6b9 100644 --- a/test/fixtures/wpt/url/META.yml +++ b/test/fixtures/wpt/url/META.yml @@ -3,5 +3,4 @@ suggested_reviewers: - mikewest - domenic - annevk - - GPHemsley - TimothyGu diff --git a/test/fixtures/wpt/url/README.md b/test/fixtures/wpt/url/README.md index fa5e3b0dc72385..50227bc4b330ef 100644 --- a/test/fixtures/wpt/url/README.md +++ b/test/fixtures/wpt/url/README.md @@ -1,11 +1,13 @@ -## urltestdata.json +## urltestdata.json / urltestdata-javascript-only.json -`resources/urltestdata.json` contains URL parsing tests suitable for any URL parser implementation. +[`resources/urltestdata.json`](resources/urltestdata.json) contains URL parsing tests suitable for any URL parser implementation. +[`resources/urltestdata-javascript-only.json`](resources/urltestdata-javascript-only.json) contains URL parsing tests specifically meant +for JavaScript's `URL()` class as well as other languages accepting non-scalar-value strings. -It's used as a source of tests by `a-element.html`, `failure.html`, `url-constructor.any.js`, and -other test files in this directory. +These files are used as a source of tests by `a-element.html`, `failure.html`, `url-constructor.any.js`, +and other test files in this directory. -The format of `resources/urltestdata.json` is a JSON array of comments as strings and test cases as +Both files share the same format. They consist of a JSON array of comments as strings and test cases as objects. The keys for each test case are: * `input`: a string to be parsed as URL. diff --git a/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml index effcf04bee3fb0..e68e68dda2ad6c 100644 --- a/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml +++ b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml @@ -12,4 +12,8 @@ - + diff --git a/test/fixtures/wpt/url/a-element-origin.html b/test/fixtures/wpt/url/a-element-origin.html index 9cc8e94cbed060..7015f853f01a1d 100644 --- a/test/fixtures/wpt/url/a-element-origin.html +++ b/test/fixtures/wpt/url/a-element-origin.html @@ -5,4 +5,8 @@
- + diff --git a/test/fixtures/wpt/url/a-element-xhtml.xhtml b/test/fixtures/wpt/url/a-element-xhtml.xhtml index 05bec4ce4b2f1e..610481a7819d62 100644 --- a/test/fixtures/wpt/url/a-element-xhtml.xhtml +++ b/test/fixtures/wpt/url/a-element-xhtml.xhtml @@ -17,4 +17,8 @@ - + diff --git a/test/fixtures/wpt/url/a-element.html b/test/fixtures/wpt/url/a-element.html index 3428fa00574c4d..a7621d2ded76c4 100644 --- a/test/fixtures/wpt/url/a-element.html +++ b/test/fixtures/wpt/url/a-element.html @@ -10,7 +10,11 @@
- + Link with embedded \n is parsed correctly diff --git a/test/fixtures/wpt/url/failure.html b/test/fixtures/wpt/url/failure.html index e61f462f97456f..d95b1d52d67237 100644 --- a/test/fixtures/wpt/url/failure.html +++ b/test/fixtures/wpt/url/failure.html @@ -6,7 +6,10 @@
+ + + diff --git a/test/fixtures/wpt/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html b/test/fixtures/wpt/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html new file mode 100644 index 00000000000000..0d5c7ca6ed57fd --- /dev/null +++ b/test/fixtures/wpt/wasm/webapi/esm-integration/script-src-blocks-wasm.tentative.sub.html @@ -0,0 +1,21 @@ + +script-src blocks Wasm execution + + + + + diff --git a/test/fixtures/wpt/wasm/webapi/esm-integration/source-phase.tentative.html b/test/fixtures/wpt/wasm/webapi/esm-integration/source-phase.tentative.html new file mode 100644 index 00000000000000..870b16bd0a0ce8 --- /dev/null +++ b/test/fixtures/wpt/wasm/webapi/esm-integration/source-phase.tentative.html @@ -0,0 +1,35 @@ + +Source phase imports + + + + diff --git a/test/fixtures/wpt/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html b/test/fixtures/wpt/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html new file mode 100644 index 00000000000000..e193f3efc69330 --- /dev/null +++ b/test/fixtures/wpt/wasm/webapi/esm-integration/worker-import-source-phase.tentative.html @@ -0,0 +1,13 @@ + +Testing import of WebAssembly source phase from JavaScript worker + + + + diff --git a/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html b/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html index 8002e07ce7f1cf..6145dd04ff8c8d 100644 --- a/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html +++ b/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html @@ -10,4 +10,7 @@ assert_equals(msg, 42); done(); } +worker.onerror = () => { + assert_unreached("worker got an error"); +} diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml b/test/fixtures/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml new file mode 100644 index 00000000000000..378ed57dc52d07 --- /dev/null +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: broadcast-channel + files: "**" diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js b/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js index 68b4706028f5aa..eec09d65a3aba2 100644 --- a/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js @@ -1,3 +1,11 @@ +test(function() { + assert_throws_js( + TypeError, + () => BroadcastChannel(""), + "Calling BroadcastChannel constructor without 'new' must throw" + ); +}, "BroadcastChannel constructor called as normal function"); + async_test(t => { let c1 = new BroadcastChannel('eventType'); let c2 = new BroadcastChannel('eventType'); diff --git a/test/fixtures/wpt/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html b/test/fixtures/wpt/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html similarity index 100% rename from test/fixtures/wpt/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html rename to test/fixtures/wpt/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html diff --git a/test/fixtures/wpt/webstorage/localstorage-basic-partitioned.tentative.sub.html b/test/fixtures/wpt/webstorage/localstorage-basic-partitioned.sub.html similarity index 97% rename from test/fixtures/wpt/webstorage/localstorage-basic-partitioned.tentative.sub.html rename to test/fixtures/wpt/webstorage/localstorage-basic-partitioned.sub.html index 7ed49b1e9a0eb5..3d5b1e93ce5ef6 100644 --- a/test/fixtures/wpt/webstorage/localstorage-basic-partitioned.tentative.sub.html +++ b/test/fixtures/wpt/webstorage/localstorage-basic-partitioned.sub.html @@ -38,7 +38,7 @@ assert_true(typeof sameSiteID === "string"); if (location.origin !== altOrigin) { - crossSiteWindow = window.open(`${altOrigin}/webstorage/localstorage-basic-partitioned.tentative.sub.html`, "", "noopener=false"); + crossSiteWindow = window.open(`${altOrigin}/webstorage/localstorage-basic-partitioned.sub.html`, "", "noopener=false"); t.add_cleanup(() => crossSiteWindow.close()); } } diff --git a/test/fixtures/wpt/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js b/test/fixtures/wpt/webstorage/localstorage-cross-origin-iframe.https.window.js similarity index 100% rename from test/fixtures/wpt/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js rename to test/fixtures/wpt/webstorage/localstorage-cross-origin-iframe.https.window.js diff --git a/test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.tentative.sub.html b/test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.sub.html similarity index 97% rename from test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.tentative.sub.html rename to test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.sub.html index 30575bfaf1a579..38525b99a23497 100644 --- a/test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.tentative.sub.html +++ b/test/fixtures/wpt/webstorage/sessionStorage-basic-partitioned.sub.html @@ -47,7 +47,7 @@ // new cross-site window that contains our shared-iframe to repeat // the process in a cross-site environment. if (location.origin !== altOrigin) { - crossSiteWindow = window.open(`${altOrigin}/webstorage/sessionStorage-basic-partitioned.tentative.sub.html`, "", "noopener=false"); + crossSiteWindow = window.open(`${altOrigin}/webstorage/sessionStorage-basic-partitioned.sub.html`, "", "noopener=false"); t.add_cleanup(() => crossSiteWindow.close()); } }