From 68e83901f354b41f3dfb22df41324db95759ae85 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Thu, 2 Mar 2023 18:04:40 +0100 Subject: [PATCH] test: update WPT resources, common, streams, FileAPI, broadcastchannel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/46912 Reviewed-By: Yagiz Nizipli Reviewed-By: Tobias NieรŸen --- test/common/wpt.js | 26 +- test/common/wpt/worker.js | 17 +- .../Blob-methods-from-detached-frame.html | 59 ++ .../cross-partition.tentative.https.html | 276 +++++++ .../wpt/FileAPI/blob/Blob-constructor.any.js | 11 +- .../wpt/FileAPI/blob/Blob-constructor.html | 501 ------------- .../wpt/FileAPI/blob/Blob-in-worker.worker.js | 15 +- .../wpt/FileAPI/blob/Blob-slice-overflow.html | 42 -- .../fixtures/wpt/FileAPI/blob/Blob-slice.html | 238 ------ .../FileAPI/blob/Blob-stream-byob-crash.html | 11 + .../blob/Blob-stream-sync-xhr-crash.html | 13 + .../wpt/FileAPI/blob/Blob-stream.any.js | 27 +- .../wpt/FileAPI/file/File-constructor.html | 159 ---- .../send-file-form-controls.tentative.html | 117 --- .../send-file-form-iso-2022-jp.tentative.html | 72 -- .../send-file-form-punctuation.tentative.html | 230 ------ ...send-file-form-windows-1252.tentative.html | 69 -- ...nd-file-form-x-user-defined.tentative.html | 70 -- ...send-file-formdata-controls.tentative.html | 93 --- ...d-file-formdata-punctuation.tentative.html | 168 ----- .../file/send-file-formdata-utf-8.html | 53 -- .../wpt/FileAPI/file/send-file-formdata.html | 28 - test/fixtures/wpt/FileAPI/fileReader.any.js | 59 ++ test/fixtures/wpt/FileAPI/fileReader.html | 67 -- test/fixtures/wpt/FileAPI/idlharness.any.js | 19 + test/fixtures/wpt/FileAPI/idlharness.html | 7 +- .../fixtures/wpt/FileAPI/idlharness.worker.js | 3 - ...oding.html => Determining-Encoding.any.js} | 14 +- ...ileReader-event-handler-attributes.any.js} | 10 +- ....html => FileReader-multiple-reads.any.js} | 12 +- ...der_abort.html => filereader_abort.any.js} | 17 +- ...der_error.html => filereader_error.any.js} | 18 +- ...ml => filereader_readAsArrayBuffer.any.js} | 17 +- ...l => filereader_readAsBinaryString.any.js} | 11 +- ...L.html => filereader_readAsDataURL.any.js} | 13 +- ...Text.html => filereader_readAsText.any.js} | 17 +- ...tate.html => filereader_readystate.any.js} | 17 +- ...r_result.html => filereader_result.any.js} | 19 +- test/fixtures/wpt/FileAPI/support/Blob.js | 4 +- .../wpt/FileAPI/support/empty-document.html | 3 + .../support/send-file-formdata-helper.js | 8 +- .../FileAPI/url/cross-global-revoke.sub.html | 5 +- .../wpt/FileAPI/url/url-format.any.js | 8 +- .../wpt/FileAPI/url/url-with-fetch.any.js | 19 + test/fixtures/wpt/README.md | 10 +- .../wpt/common/custom-cors-response.js | 32 + test/fixtures/wpt/common/dispatcher/README.md | 228 ++++++ .../wpt/common/dispatcher/dispatcher.js | 256 +++++++ .../dispatcher/executor-service-worker.js | 24 + .../wpt/common/dispatcher/executor-worker.js | 12 + .../wpt/common/dispatcher/executor.html | 15 + .../common/dispatcher/remote-executor.html | 12 + test/fixtures/wpt/common/gc.js | 52 ++ test/fixtures/wpt/common/media.js | 4 +- .../fixtures/wpt/common/object-association.js | 68 +- test/fixtures/wpt/common/proxy-all.sub.pac | 3 + test/fixtures/wpt/common/reftest-wait.js | 19 + test/fixtures/wpt/common/sab.js | 6 +- .../security-features/resources/common.sub.js | 42 +- .../security-features/tools/spec.src.json | 45 +- test/fixtures/wpt/common/stringifiers.js | 2 +- ...listener-passive-by-default.tentative.html | 73 -- ...listener-passive-by-default.tentative.html | 51 -- .../wpt/encoding/gb18030-encoder.html | 21 - test/fixtures/wpt/encoding/gbk-encoder.html | 21 - .../gb18030/gb18030-decoder.html | 55 -- .../legacy-mb-schinese/gbk/gbk-decoder.html | 33 - .../wpt/encoding/single-byte-decoder.html | 113 --- .../timers/negative-setinterval.html | 18 - .../timers/negative-settimeout.html | 9 - .../timers/type-long-setinterval.html | 14 - .../timers/type-long-settimeout.html | 9 - test/fixtures/wpt/resources/.gitignore | 3 - test/fixtures/wpt/resources/LICENSE | 30 - .../fixtures/wpt/resources/check-layout-th.js | 4 + .../declarative-shadow-dom-polyfill.js | 24 + .../wpt/resources/idlharness-shadowrealm.js | 60 +- test/fixtures/wpt/resources/idlharness.js | 223 +++--- test/fixtures/wpt/resources/testdriver.js | 60 +- .../wpt/resources/testharness.css.headers | 2 - test/fixtures/wpt/resources/testharness.js | 33 +- .../fixtures/wpt/resources/webidl2/.gitignore | 4 - .../wpt/resources/webidl2/.travis.yml | 5 - .../wpt/resources/webidl2/CHANGELOG.md | 292 -------- test/fixtures/wpt/resources/webidl2/LICENSE | 21 - test/fixtures/wpt/resources/webidl2/README.md | 629 ---------------- .../wpt/resources/webidl2/checker/index.html | 55 -- .../wpt/resources/webidl2/coverage.html | 341 --------- test/fixtures/wpt/resources/webidl2/index.js | 1 - .../wpt/resources/webidl2/lib/writer.js | 221 ------ .../wpt/resources/webidl2/package-lock.json | 700 ------------------ .../wpt/resources/webidl2/package.json | 27 - ...js => enqueue-with-detached-buffer.any.js} | 4 +- .../garbage-collection.any.js | 1 + .../wpt/streams/resources/test-utils.js | 20 - .../wpt/streams/transferable/gc-crash.html | 17 + test/fixtures/wpt/url/url-constructor.html | 44 -- test/fixtures/wpt/url/url-origin.html | 24 - test/fixtures/wpt/versions.json | 16 +- .../webmessaging/broadcastchannel/blobs.html | 5 +- .../cross-partition.https.tentative.html | 366 ++++++++- .../broadcastchannel/opaque-origin.html | 158 ++++ .../broadcastchannel/resources/worker.js | 8 +- test/wpt/status/FileAPI/blob.json | 8 + test/wpt/status/streams.json | 7 + test/wpt/status/url.json | 2 + test/wpt/test-streams.js | 25 - test/wpt/test-url.js | 3 - 108 files changed, 2076 insertions(+), 5276 deletions(-) create mode 100644 test/fixtures/wpt/FileAPI/Blob-methods-from-detached-frame.html create mode 100644 test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html delete mode 100644 test/fixtures/wpt/FileAPI/blob/Blob-constructor.html delete mode 100644 test/fixtures/wpt/FileAPI/blob/Blob-slice-overflow.html delete mode 100644 test/fixtures/wpt/FileAPI/blob/Blob-slice.html create mode 100644 test/fixtures/wpt/FileAPI/blob/Blob-stream-byob-crash.html create mode 100644 test/fixtures/wpt/FileAPI/blob/Blob-stream-sync-xhr-crash.html delete mode 100644 test/fixtures/wpt/FileAPI/file/File-constructor.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-form-controls.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-form-punctuation.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-formdata-controls.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-formdata-punctuation.tentative.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-formdata-utf-8.html delete mode 100644 test/fixtures/wpt/FileAPI/file/send-file-formdata.html create mode 100644 test/fixtures/wpt/FileAPI/fileReader.any.js delete mode 100644 test/fixtures/wpt/FileAPI/fileReader.html create mode 100644 test/fixtures/wpt/FileAPI/idlharness.any.js rename test/fixtures/wpt/FileAPI/reading-data-section/{Determining-Encoding.html => Determining-Encoding.any.js} (86%) rename test/fixtures/wpt/FileAPI/reading-data-section/{FileReader-event-handler-attributes.html => FileReader-event-handler-attributes.any.js} (60%) rename test/fixtures/wpt/FileAPI/reading-data-section/{FileReader-multiple-reads.html => FileReader-multiple-reads.any.js} (89%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_abort.html => filereader_abort.any.js} (77%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_error.html => filereader_error.any.js} (51%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_readAsArrayBuffer.html => filereader_readAsArrayBuffer.any.js} (60%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_readAsBinaryString.html => filereader_readAsBinaryString.any.js} (64%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_readAsDataURL.html => filereader_readAsDataURL.any.js} (74%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_readAsText.html => filereader_readAsText.any.js} (73%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_readystate.html => filereader_readystate.any.js} (51%) rename test/fixtures/wpt/FileAPI/reading-data-section/{filereader_result.html => filereader_result.any.js} (87%) create mode 100644 test/fixtures/wpt/FileAPI/support/empty-document.html create mode 100644 test/fixtures/wpt/common/custom-cors-response.js create mode 100644 test/fixtures/wpt/common/dispatcher/README.md create mode 100644 test/fixtures/wpt/common/dispatcher/dispatcher.js create mode 100644 test/fixtures/wpt/common/dispatcher/executor-service-worker.js create mode 100644 test/fixtures/wpt/common/dispatcher/executor-worker.js create mode 100644 test/fixtures/wpt/common/dispatcher/executor.html create mode 100644 test/fixtures/wpt/common/dispatcher/remote-executor.html create mode 100644 test/fixtures/wpt/common/gc.js create mode 100644 test/fixtures/wpt/common/proxy-all.sub.pac delete mode 100644 test/fixtures/wpt/dom/events/document-level-touchmove-event-listener-passive-by-default.tentative.html delete mode 100644 test/fixtures/wpt/dom/events/document-level-wheel-event-listener-passive-by-default.tentative.html delete mode 100644 test/fixtures/wpt/encoding/gb18030-encoder.html delete mode 100644 test/fixtures/wpt/encoding/gbk-encoder.html delete mode 100644 test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.html delete mode 100644 test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.html delete mode 100644 test/fixtures/wpt/encoding/single-byte-decoder.html delete mode 100644 test/fixtures/wpt/html/webappapis/timers/negative-setinterval.html delete mode 100644 test/fixtures/wpt/html/webappapis/timers/negative-settimeout.html delete mode 100644 test/fixtures/wpt/html/webappapis/timers/type-long-setinterval.html delete mode 100644 test/fixtures/wpt/html/webappapis/timers/type-long-settimeout.html delete mode 100644 test/fixtures/wpt/resources/.gitignore delete mode 100644 test/fixtures/wpt/resources/LICENSE create mode 100644 test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js delete mode 100644 test/fixtures/wpt/resources/testharness.css.headers delete mode 100644 test/fixtures/wpt/resources/webidl2/.gitignore delete mode 100644 test/fixtures/wpt/resources/webidl2/.travis.yml delete mode 100644 test/fixtures/wpt/resources/webidl2/CHANGELOG.md delete mode 100644 test/fixtures/wpt/resources/webidl2/LICENSE delete mode 100644 test/fixtures/wpt/resources/webidl2/README.md delete mode 100644 test/fixtures/wpt/resources/webidl2/checker/index.html delete mode 100644 test/fixtures/wpt/resources/webidl2/coverage.html delete mode 100644 test/fixtures/wpt/resources/webidl2/index.js delete mode 100644 test/fixtures/wpt/resources/webidl2/lib/writer.js delete mode 100644 test/fixtures/wpt/resources/webidl2/package-lock.json delete mode 100644 test/fixtures/wpt/resources/webidl2/package.json rename test/fixtures/wpt/streams/readable-byte-streams/{enqueue-with-detached-buffer.window.js => enqueue-with-detached-buffer.any.js} (88%) create mode 100644 test/fixtures/wpt/streams/transferable/gc-crash.html delete mode 100644 test/fixtures/wpt/url/url-constructor.html delete mode 100644 test/fixtures/wpt/url/url-origin.html diff --git a/test/common/wpt.js b/test/common/wpt.js index 9558b9a4e8d917..57c409f5cc8a0f 100644 --- a/test/common/wpt.js +++ b/test/common/wpt.js @@ -453,14 +453,13 @@ class WPTRunner { this.scriptsModifier = modifier; } - fullInitScript(hasSubsetScript, locationSearchString) { + fullInitScript(url, metaTitle) { let { initScript } = this; - if (hasSubsetScript || locationSearchString) { - initScript = `${initScript}\n\n//===\nglobalThis.location ||= {};`; - } - if (locationSearchString) { - initScript = `${initScript}\n\n//===\nglobalThis.location.search = "${locationSearchString}";`; + initScript = `${initScript}\n\n//===\nglobalThis.location = new URL("${url.href}");`; + + if (metaTitle) { + initScript = `${initScript}\n\n//===\nglobalThis.META_TITLE = "${metaTitle}";`; } if (this.globalThisInitScripts.length === null) { @@ -553,13 +552,13 @@ class WPTRunner { const relativePath = spec.getRelativePath(); const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js'); const scriptsToRun = []; - let hasSubsetScript = false; + let needsGc = false; // Scripts specified with the `// META: script=` header if (meta.script) { for (const script of meta.script) { - if (script === '/common/subset-tests.js' || script === '/common/subset-tests-by-key.js') { - hasSubsetScript = true; + if (script === '/common/gc.js') { + needsGc = true; } const obj = { filename: this.resource.toRealFilePath(relativePath, script), @@ -592,12 +591,13 @@ class WPTRunner { testRelativePath: relativePath, wptRunner: __filename, wptPath: this.path, - initScript: this.fullInitScript(hasSubsetScript, variant), + initScript: this.fullInitScript(new URL(`/${relativePath.replace(/\.js$/, '.html')}${variant}`, 'http://wpt'), meta.title), harness: { code: fs.readFileSync(harnessPath, 'utf8'), filename: harnessPath, }, scriptsToRun, + needsGc, }, }); this.workers.set(testFileName, worker); @@ -749,11 +749,7 @@ class WPTRunner { */ resultCallback(filename, test, reportResult) { const status = this.getTestStatus(test.status); - const title = this.getTestTitle(filename); - if (/^Untitled( \d+)?$/.test(test.name)) { - test.name = `${title}${test.name.slice(8)}`; - } - console.log(`---- ${title} ----`); + console.log(`---- ${test.name} ----`); if (status !== kPass) { this.fail(filename, test, status, reportResult); } else { diff --git a/test/common/wpt/worker.js b/test/common/wpt/worker.js index 34368ab5c5beff..14d3d887aad5eb 100644 --- a/test/common/wpt/worker.js +++ b/test/common/wpt/worker.js @@ -1,22 +1,29 @@ 'use strict'; -const { runInThisContext } = require('vm'); +const { runInNewContext, runInThisContext } = require('vm'); +const { setFlagsFromString } = require('v8'); const { parentPort, workerData } = require('worker_threads'); const { ResourceLoader } = require(workerData.wptRunner); const resource = new ResourceLoader(workerData.wptPath); -global.self = global; -global.GLOBAL = { +if (workerData.needsGc) { + // See https://github.com/nodejs/node/issues/16595#issuecomment-340288680 + setFlagsFromString('--expose-gc'); + globalThis.gc = runInNewContext('gc'); +} + +globalThis.self = global; +globalThis.GLOBAL = { isWindow() { return false; }, isShadowRealm() { return false; }, }; -global.require = require; +globalThis.require = require; // This is a mock, because at the moment fetch is not implemented // in Node.js, but some tests and harness depend on this to pull // resources. -global.fetch = function fetch(file) { +globalThis.fetch = function fetch(file) { return resource.read(workerData.testRelativePath, file, true); }; diff --git a/test/fixtures/wpt/FileAPI/Blob-methods-from-detached-frame.html b/test/fixtures/wpt/FileAPI/Blob-methods-from-detached-frame.html new file mode 100644 index 00000000000000..37efd5ed2016b7 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/Blob-methods-from-detached-frame.html @@ -0,0 +1,59 @@ + + +Blob methods from detached frame work as expected + + + + + + diff --git a/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html new file mode 100644 index 00000000000000..c75ce07d054eb7 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js b/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js index 6c34d7e34b93f9..d16f760caeeb2d 100644 --- a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js +++ b/test/fixtures/wpt/FileAPI/blob/Blob-constructor.any.js @@ -311,7 +311,16 @@ test_blob(function() { desc: "Passing a Float64Array as element of the blobParts array should work." }); - +test_blob(function() { + return new Blob([ + new BigInt64Array([BigInt("0x5353415053534150")]), + new BigUint64Array([BigInt("0x5353415053534150")]) + ]); +}, { + expected: "PASSPASSPASSPASS", + type: "", + desc: "Passing BigInt typed arrays as elements of the blobParts array should work." +}); var t_ports = async_test("Passing a FrozenArray as the blobParts array should work (FrozenArray)."); t_ports.step(function() { diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.html b/test/fixtures/wpt/FileAPI/blob/Blob-constructor.html deleted file mode 100644 index 62a649aed66418..00000000000000 --- a/test/fixtures/wpt/FileAPI/blob/Blob-constructor.html +++ /dev/null @@ -1,501 +0,0 @@ - - -Blob constructor - - - - - - - -
- diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-in-worker.worker.js b/test/fixtures/wpt/FileAPI/blob/Blob-in-worker.worker.js index a67060e7b85eff..a0ca84551dd7cc 100644 --- a/test/fixtures/wpt/FileAPI/blob/Blob-in-worker.worker.js +++ b/test/fixtures/wpt/FileAPI/blob/Blob-in-worker.worker.js @@ -1,14 +1,9 @@ importScripts("/resources/testharness.js"); -async_test(function() { - var data = "TEST"; - var blob = new Blob([data], {type: "text/plain"}); - var reader = new FileReader(); - reader.onload = this.step_func_done(function() { - assert_equals(reader.result, data); - }); - reader.onerror = this.unreached_func("Unexpected error event"); - reader.readAsText(blob); -}, "Create Blob in Worker"); +promise_test(async () => { + const data = "TEST"; + const blob = new Blob([data], {type: "text/plain"}); + assert_equals(await blob.text(), data); +}, 'Create Blob in Worker'); done(); diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-slice-overflow.html b/test/fixtures/wpt/FileAPI/blob/Blob-slice-overflow.html deleted file mode 100644 index 74cd83a34f7116..00000000000000 --- a/test/fixtures/wpt/FileAPI/blob/Blob-slice-overflow.html +++ /dev/null @@ -1,42 +0,0 @@ - - -Blob slice overflow - - - - -
- - diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-slice.html b/test/fixtures/wpt/FileAPI/blob/Blob-slice.html deleted file mode 100644 index 03fe6ca5343bd1..00000000000000 --- a/test/fixtures/wpt/FileAPI/blob/Blob-slice.html +++ /dev/null @@ -1,238 +0,0 @@ - - -Blob slice - - - - - -
- diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-stream-byob-crash.html b/test/fixtures/wpt/FileAPI/blob/Blob-stream-byob-crash.html new file mode 100644 index 00000000000000..5992ed1396ca90 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/blob/Blob-stream-byob-crash.html @@ -0,0 +1,11 @@ + + diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-stream-sync-xhr-crash.html b/test/fixtures/wpt/FileAPI/blob/Blob-stream-sync-xhr-crash.html new file mode 100644 index 00000000000000..fe54fb615b1579 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/blob/Blob-stream-sync-xhr-crash.html @@ -0,0 +1,13 @@ + + diff --git a/test/fixtures/wpt/FileAPI/blob/Blob-stream.any.js b/test/fixtures/wpt/FileAPI/blob/Blob-stream.any.js index 792b6639c35a26..87710a171a9752 100644 --- a/test/fixtures/wpt/FileAPI/blob/Blob-stream.any.js +++ b/test/fixtures/wpt/FileAPI/blob/Blob-stream.any.js @@ -1,24 +1,26 @@ // META: title=Blob Stream // META: script=../support/Blob.js -// META: script=../../streams/resources/test-utils.js +// META: script=/common/gc.js 'use strict'; // Helper function that triggers garbage collection while reading a chunk // if perform_gc is true. async function read_and_gc(reader, perform_gc) { - const read_promise = reader.read(); - if (perform_gc) - garbageCollect(); + // Passing Uint8Array for byte streams; non-byte streams will simply ignore it + const read_promise = reader.read(new Uint8Array(64)); + if (perform_gc) { + await garbageCollect(); + } return read_promise; } // Takes in a ReadableStream and reads from it until it is done, returning // an array that contains the results of each read operation. If perform_gc // is true, garbage collection is triggered while reading every chunk. -async function read_all_chunks(stream, perform_gc = false) { +async function read_all_chunks(stream, { perform_gc = false, mode } = {}) { assert_true(stream instanceof ReadableStream); assert_true('getReader' in stream); - const reader = stream.getReader(); + const reader = stream.getReader({ mode }); assert_true('read' in reader); let read_value = await read_and_gc(reader, perform_gc); @@ -65,8 +67,17 @@ promise_test(async() => { let blob = new Blob([typed_arr]); const stream = blob.stream(); blob = null; - garbageCollect(); - const chunks = await read_all_chunks(stream, /*perform_gc=*/true); + await garbageCollect(); + const chunks = await read_all_chunks(stream, { perform_gc: true }); assert_array_equals(chunks, input_arr); }, "Blob.stream() garbage collection of blob shouldn't break stream" + "consumption") + +promise_test(async () => { + const input_arr = [8, 241, 48, 123, 151]; + const typed_arr = new Uint8Array(input_arr); + let blob = new Blob([typed_arr]); + const stream = blob.stream(); + const chunks = await read_all_chunks(stream, { mode: "byob" }); + assert_array_equals(chunks, input_arr); +}, "Reading Blob.stream() with BYOB reader") diff --git a/test/fixtures/wpt/FileAPI/file/File-constructor.html b/test/fixtures/wpt/FileAPI/file/File-constructor.html deleted file mode 100644 index 3477e4ada16e92..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/File-constructor.html +++ /dev/null @@ -1,159 +0,0 @@ - - -File constructor - - - -
- diff --git a/test/fixtures/wpt/FileAPI/file/send-file-form-controls.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-form-controls.tentative.html deleted file mode 100644 index d11f4a860931b4..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-form-controls.tentative.html +++ /dev/null @@ -1,117 +0,0 @@ - - -Upload files named using controls (tentative) - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html deleted file mode 100644 index 659af3bde85852..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html +++ /dev/null @@ -1,72 +0,0 @@ - - - -Upload files in ISO-2022-JP form (tentative) - - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-form-punctuation.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-form-punctuation.tentative.html deleted file mode 100644 index 5c2d6d0bf1fe01..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-form-punctuation.tentative.html +++ /dev/null @@ -1,230 +0,0 @@ - - -Upload files named using punctuation (tentative) - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html deleted file mode 100644 index a2c37186b3e023..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html +++ /dev/null @@ -1,69 +0,0 @@ - - -Upload files in Windows-1252 form (tentative) - - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html deleted file mode 100644 index 503b08a51706f7..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html +++ /dev/null @@ -1,70 +0,0 @@ - - -Upload files in x-user-defined form (tentative) - - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-formdata-controls.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-formdata-controls.tentative.html deleted file mode 100644 index 4259741b63ef31..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-formdata-controls.tentative.html +++ /dev/null @@ -1,93 +0,0 @@ - - -FormData: Upload files named using controls (tentative) - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-formdata-punctuation.tentative.html b/test/fixtures/wpt/FileAPI/file/send-file-formdata-punctuation.tentative.html deleted file mode 100644 index d8e84e9d978094..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-formdata-punctuation.tentative.html +++ /dev/null @@ -1,168 +0,0 @@ - - -FormData: Upload files named using punctuation (tentative) - - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-formdata-utf-8.html b/test/fixtures/wpt/FileAPI/file/send-file-formdata-utf-8.html deleted file mode 100644 index 7a7f6cefe776b9..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-formdata-utf-8.html +++ /dev/null @@ -1,53 +0,0 @@ - - -FormData: Upload files in UTF-8 fetch() - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/file/send-file-formdata.html b/test/fixtures/wpt/FileAPI/file/send-file-formdata.html deleted file mode 100644 index 77e048e54741c0..00000000000000 --- a/test/fixtures/wpt/FileAPI/file/send-file-formdata.html +++ /dev/null @@ -1,28 +0,0 @@ - - -FormData: Upload ASCII-named file in UTF-8 form - - - - - - - - diff --git a/test/fixtures/wpt/FileAPI/fileReader.any.js b/test/fixtures/wpt/FileAPI/fileReader.any.js new file mode 100644 index 00000000000000..2876dcb4ce314e --- /dev/null +++ b/test/fixtures/wpt/FileAPI/fileReader.any.js @@ -0,0 +1,59 @@ +// META: title=FileReader States + +'use strict'; + +test(function () { + assert_true( + "FileReader" in globalThis, + "globalThis should have a FileReader property.", + ); +}, "FileReader interface object"); + +test(function () { + var fileReader = new FileReader(); + assert_true(fileReader instanceof FileReader); +}, "no-argument FileReader constructor"); + +var t_abort = async_test("FileReader States -- abort"); +t_abort.step(function () { + var fileReader = new FileReader(); + assert_equals(fileReader.readyState, 0); + assert_equals(fileReader.readyState, FileReader.EMPTY); + + var blob = new Blob(); + fileReader.readAsArrayBuffer(blob); + assert_equals(fileReader.readyState, 1); + assert_equals(fileReader.readyState, FileReader.LOADING); + + fileReader.onabort = this.step_func(function (e) { + assert_equals(fileReader.readyState, 2); + assert_equals(fileReader.readyState, FileReader.DONE); + t_abort.done(); + }); + fileReader.abort(); + fileReader.onabort = this.unreached_func("abort event should fire sync"); +}); + +var t_event = async_test("FileReader States -- events"); +t_event.step(function () { + var fileReader = new FileReader(); + + var blob = new Blob(); + fileReader.readAsArrayBuffer(blob); + + fileReader.onloadstart = this.step_func(function (e) { + assert_equals(fileReader.readyState, 1); + assert_equals(fileReader.readyState, FileReader.LOADING); + }); + + fileReader.onprogress = this.step_func(function (e) { + assert_equals(fileReader.readyState, 1); + assert_equals(fileReader.readyState, FileReader.LOADING); + }); + + fileReader.onloadend = this.step_func(function (e) { + assert_equals(fileReader.readyState, 2); + assert_equals(fileReader.readyState, FileReader.DONE); + t_event.done(); + }); +}); diff --git a/test/fixtures/wpt/FileAPI/fileReader.html b/test/fixtures/wpt/FileAPI/fileReader.html deleted file mode 100644 index b767e22d4a66eb..00000000000000 --- a/test/fixtures/wpt/FileAPI/fileReader.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - FileReader States - - - - - - -
- - - diff --git a/test/fixtures/wpt/FileAPI/idlharness.any.js b/test/fixtures/wpt/FileAPI/idlharness.any.js new file mode 100644 index 00000000000000..1744242b9f3ff1 --- /dev/null +++ b/test/fixtures/wpt/FileAPI/idlharness.any.js @@ -0,0 +1,19 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: timeout=long + +'use strict'; + +// https://w3c.github.io/FileAPI/ + +idl_test( + ['FileAPI'], + ['dom', 'html', 'url'], + idl_array => { + idl_array.add_objects({ + Blob: ['new Blob(["TEST"])'], + File: ['new File(["myFileBits"], "myFileName")'], + FileReader: ['new FileReader()'] + }); + } +); diff --git a/test/fixtures/wpt/FileAPI/idlharness.html b/test/fixtures/wpt/FileAPI/idlharness.html index 5e0a43f80df3f8..45e8684f0027b2 100644 --- a/test/fixtures/wpt/FileAPI/idlharness.html +++ b/test/fixtures/wpt/FileAPI/idlharness.html @@ -2,7 +2,7 @@ - File API automated IDL tests + File API automated IDL tests (requiring dom) @@ -27,10 +27,7 @@

File API automated IDL tests

['dom', 'html', 'url'], idl_array => { idl_array.add_objects({ - Blob: ['new Blob(["TEST"])'], - File: ['new File(["myFileBits"], "myFileName")'], - FileList: ['document.querySelector("#fileChooser").files'], - FileReader: ['new FileReader()'] + FileList: ['document.querySelector("#fileChooser").files'] }); } ); diff --git a/test/fixtures/wpt/FileAPI/idlharness.worker.js b/test/fixtures/wpt/FileAPI/idlharness.worker.js index 786b7e4199fb45..002aaed40a562e 100644 --- a/test/fixtures/wpt/FileAPI/idlharness.worker.js +++ b/test/fixtures/wpt/FileAPI/idlharness.worker.js @@ -10,9 +10,6 @@ idl_test( ['dom', 'html', 'url'], idl_array => { idl_array.add_objects({ - Blob: ['new Blob(["TEST"])'], - File: ['new File(["myFileBits"], "myFileName")'], - FileReader: ['new FileReader()'], FileReaderSync: ['new FileReaderSync()'] }); } diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.html b/test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.any.js similarity index 86% rename from test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.html rename to test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.any.js index d65ae9db18a1ff..5b69f7ed9821ac 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/Determining-Encoding.any.js @@ -1,13 +1,5 @@ - - -FileAPI Test: Blob Determining Encoding - - - - - -
- diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.html b/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.any.js similarity index 60% rename from test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.html rename to test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.any.js index 86657b5711aff1..fc71c6434812e2 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-event-handler-attributes.any.js @@ -1,10 +1,5 @@ - - -FileReader event handler attributes - - -
- diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html b/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.any.js similarity index 89% rename from test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html rename to test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.any.js index e7279fe4bd445e..4b19c69b425188 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.any.js @@ -1,11 +1,5 @@ -๏ปฟ -FileReader: starting new reads while one is in progress - - - - -
- diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.any.js similarity index 77% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.any.js index 940a775d35bf42..c778ae55bb573b 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_abort.any.js @@ -1,17 +1,5 @@ - - - - - FileAPI Test: filereader_abort - - - - - - -
+// META: title=FileAPI Test: filereader_abort - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.any.js similarity index 51% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.any.js index cf4524825b80ca..9845962090132e 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_error.any.js @@ -1,18 +1,5 @@ - - - - - FileAPI Test: filereader_error - - - - - - - -
+// META: title=FileAPI Test: filereader_error - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js similarity index 60% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js index 31001a51a0727f..d06e3170782b7c 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsArrayBuffer.any.js @@ -1,17 +1,5 @@ - - - - - FileAPI Test: filereader_readAsArrayBuffer - - - - - - -
+// META: title=FileAPI Test: filereader_readAsArrayBuffer - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.any.js similarity index 64% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.any.js index b550e4d0a96dc7..e69ff15e75b590 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsBinaryString.any.js @@ -1,11 +1,4 @@ - - -FileAPI Test: filereader_readAsBinaryString - - - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.any.js similarity index 74% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.any.js index 5bc39499a229d1..d6812121295bee 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsDataURL.any.js @@ -1,12 +1,5 @@ - - -FileAPI Test: FileReader.readAsDataURL - - - - +// META: title=FileAPI Test: FileReader.readAsDataURL - \ No newline at end of file +}, 'readAsDataURL result for Blob with unspecified MIME type'); \ No newline at end of file diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.any.js similarity index 73% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.any.js index 7d639d0111473b..4d0fa113931d34 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readAsText.any.js @@ -1,17 +1,5 @@ - - - - - FileAPI Test: filereader_readAsText - - - - - - -
+// META: title=FileAPI Test: filereader_readAsText - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.any.js similarity index 51% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.any.js index 1586b8995059f7..3cb36ab999653b 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_readystate.any.js @@ -1,17 +1,5 @@ - - - - - FileAPI Test: filereader_readystate - - - - - - -
+// META: title=FileAPI Test: filereader_readystate - - - diff --git a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.html b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.any.js similarity index 87% rename from test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.html rename to test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.any.js index b80322ed424f83..28c068bb349c3d 100644 --- a/test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.html +++ b/test/fixtures/wpt/FileAPI/reading-data-section/filereader_result.any.js @@ -1,17 +1,5 @@ - - - - - FileAPI Test: filereader_result - - - - - - -
- - - - diff --git a/test/fixtures/wpt/FileAPI/support/Blob.js b/test/fixtures/wpt/FileAPI/support/Blob.js index 04069acd3ccbe7..2c249746858918 100644 --- a/test/fixtures/wpt/FileAPI/support/Blob.js +++ b/test/fixtures/wpt/FileAPI/support/Blob.js @@ -1,6 +1,6 @@ 'use strict' -function test_blob(fn, expectations) { +self.test_blob = (fn, expectations) => { var expected = expectations.expected, type = expectations.type, desc = expectations.desc; @@ -24,7 +24,7 @@ function test_blob(fn, expectations) { }); } -function test_blob_binary(fn, expectations) { +self.test_blob_binary = (fn, expectations) => { var expected = expectations.expected, type = expectations.type, desc = expectations.desc; diff --git a/test/fixtures/wpt/FileAPI/support/empty-document.html b/test/fixtures/wpt/FileAPI/support/empty-document.html new file mode 100644 index 00000000000000..b9cd130a07f77e --- /dev/null +++ b/test/fixtures/wpt/FileAPI/support/empty-document.html @@ -0,0 +1,3 @@ + + + diff --git a/test/fixtures/wpt/FileAPI/support/send-file-formdata-helper.js b/test/fixtures/wpt/FileAPI/support/send-file-formdata-helper.js index 53572ef36c8d1b..53c8cca7e09b8e 100644 --- a/test/fixtures/wpt/FileAPI/support/send-file-formdata-helper.js +++ b/test/fixtures/wpt/FileAPI/support/send-file-formdata-helper.js @@ -70,19 +70,21 @@ const formDataPostFileUploadTest = ({ }`, ); - const asName = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent); + const asValue = fileBaseName.replace(/\r\n?|\n/g, "\r\n"); + const asName = asValue.replace(/[\r\n"]/g, encodeURIComponent); + const asFilename = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent); const expectedText = [ boundary, 'Content-Disposition: form-data; name="filename"', "", - fileBaseName, + asValue, boundary, `Content-Disposition: form-data; name="${asName}"`, "", "filename", boundary, `Content-Disposition: form-data; name="file"; ` + - `filename="${asName}"`, + `filename="${asFilename}"`, "Content-Type: text/plain", "", kTestChars, diff --git a/test/fixtures/wpt/FileAPI/url/cross-global-revoke.sub.html b/test/fixtures/wpt/FileAPI/url/cross-global-revoke.sub.html index 21b8c5bb1986d5..ce9d680709e058 100644 --- a/test/fixtures/wpt/FileAPI/url/cross-global-revoke.sub.html +++ b/test/fixtures/wpt/FileAPI/url/cross-global-revoke.sub.html @@ -2,6 +2,7 @@ + \ No newline at end of file + diff --git a/test/fixtures/wpt/FileAPI/url/url-format.any.js b/test/fixtures/wpt/FileAPI/url/url-format.any.js index 33732fa61fc3dd..69c51113e6b99b 100644 --- a/test/fixtures/wpt/FileAPI/url/url-format.any.js +++ b/test/fixtures/wpt/FileAPI/url/url-format.any.js @@ -2,10 +2,16 @@ const blob = new Blob(['test']); const file = new File(['test'], 'name'); -test(() => { +test(t => { const url_count = 5000; let list = []; + t.add_cleanup(() => { + for (let url of list) { + URL.revokeObjectURL(url); + } + }); + for (let i = 0; i < url_count; ++i) list.push(URL.createObjectURL(blob)); diff --git a/test/fixtures/wpt/FileAPI/url/url-with-fetch.any.js b/test/fixtures/wpt/FileAPI/url/url-with-fetch.any.js index 9bd8d383df4e1e..54e6a3da5afe9e 100644 --- a/test/fixtures/wpt/FileAPI/url/url-with-fetch.any.js +++ b/test/fixtures/wpt/FileAPI/url/url-with-fetch.any.js @@ -1,4 +1,5 @@ // META: script=resources/fetch-tests.js +// META: script=/common/gc.js function fetch_should_succeed(test, request) { return fetch(request).then(response => response.text()); @@ -37,6 +38,24 @@ promise_test(t => { }); }, 'Revoke blob URL after creating Request, will fetch'); +promise_test(async t => { + const blob_contents = 'test blob contents'; + const blob = new Blob([blob_contents]); + const url = URL.createObjectURL(blob); + let request = new Request(url); + + // Revoke the object URL. Request should take a reference to the blob as + // soon as it receives it in open(), so the request succeeds even though we + // revoke the URL before calling fetch(). + URL.revokeObjectURL(url); + + request = request.clone(); + await garbageCollect(); + + const text = await fetch_should_succeed(t, request); + assert_equals(text, blob_contents); +}, 'Revoke blob URL after creating Request, then clone Request, will fetch'); + promise_test(function(t) { const blob_contents = 'test blob contents'; const blob = new Blob([blob_contents]); diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index 98b9369b88c322..1c365ca20ff1b8 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -10,14 +10,13 @@ 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/03c5072aff/common +- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common - console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console - dom/abort: https://github.com/web-platform-tests/wpt/tree/8fadb38120/dom/abort - dom/events: https://github.com/web-platform-tests/wpt/tree/ab8999891c/dom/events - encoding: https://github.com/web-platform-tests/wpt/tree/0c1b9d1622/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/3b279420d4/FileAPI -- FileAPI/file: https://github.com/web-platform-tests/wpt/tree/c01f637cca/FileAPI/file +- FileAPI: https://github.com/web-platform-tests/wpt/tree/1e432c4550/FileAPI - hr-time: https://github.com/web-platform-tests/wpt/tree/34cafd797e/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 @@ -26,14 +25,15 @@ Last update: - interfaces: https://github.com/web-platform-tests/wpt/tree/df731dab88/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/fbf1e7d247/resources -- streams: https://github.com/web-platform-tests/wpt/tree/9e5ef42bd3/streams +- resources: https://github.com/web-platform-tests/wpt/tree/919874f84f/resources +- streams: https://github.com/web-platform-tests/wpt/tree/51750bc8d7/streams - url: https://github.com/web-platform-tests/wpt/tree/1eaeb0e178/url - user-timing: https://github.com/web-platform-tests/wpt/tree/df24fb604e/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/d8dbe6990b/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi - WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/238d9d9bac/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 [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/common/custom-cors-response.js b/test/fixtures/wpt/common/custom-cors-response.js new file mode 100644 index 00000000000000..be9c7ce3bdc3c9 --- /dev/null +++ b/test/fixtures/wpt/common/custom-cors-response.js @@ -0,0 +1,32 @@ +const custom_cors_response = (payload, base_url) => { + base_url = base_url || new URL(location.href); + + // Clone the given `payload` so that, as we modify it, we won't be mutating + // the caller's value in unexpected ways. + payload = Object.assign({}, payload); + payload.headers = payload.headers || {}; + // Note that, in order to have out-of-the-box support for tests that don't + // call `setup({'allow_uncaught_exception': true})` we return a no-op JS + // payload. This approach will avoid hitting syntax errors if the resource is + // interpreted as script. Without this workaround, the SyntaxError would be + // caught by the test harness and trigger a test failure. + payload.content = payload.content || '/* custom-cors-response.js content */'; + payload.status_code = payload.status_code || 200; + + // Assume that we'll be doing a CORS-enabled fetch so we'll need to set ACAO. + const acao = "Access-Control-Allow-Origin"; + if (!(acao in payload.headers)) { + payload.headers[acao] = '*'; + } + + if (!("Content-Type" in payload.headers)) { + payload.headers["Content-Type"] = "text/javascript"; + } + + let ret = new URL("/common/CustomCorsResponse.py", base_url); + for (const key in payload) { + ret.searchParams.append(key, JSON.stringify(payload[key])); + } + + return ret; +}; diff --git a/test/fixtures/wpt/common/dispatcher/README.md b/test/fixtures/wpt/common/dispatcher/README.md new file mode 100644 index 00000000000000..cfaafb6e5d6496 --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/README.md @@ -0,0 +1,228 @@ +# `RemoteContext`: API for script execution in another context + +`RemoteContext` in `/common/dispatcher/dispatcher.js` provides an interface to +execute JavaScript in another global object (page or worker, the "executor"), +based on: + +- [WPT RFC 88: context IDs from uuid searchParams in URL](https://github.com/web-platform-tests/rfcs/pull/88), +- [WPT RFC 89: execute_script](https://github.com/web-platform-tests/rfcs/pull/89) and +- [WPT RFC 91: RemoteContext](https://github.com/web-platform-tests/rfcs/pull/91). + +Tests can send arbitrary javascript to executors to evaluate in its global +object, like: + +``` +// injector.html +const argOnLocalContext = ...; + +async function execute() { + window.open('executor.html?uuid=' + uuid); + const ctx = new RemoteContext(uuid); + await ctx.execute_script( + (arg) => functionOnRemoteContext(arg), + [argOnLocalContext]); +}; +``` + +and on executor: + +``` +// executor.html +function functionOnRemoteContext(arg) { ... } + +const uuid = new URLSearchParams(window.location.search).get('uuid'); +const executor = new Executor(uuid); +``` + +For concrete examples, see +[events.html](../../html/browsers/browsing-the-web/back-forward-cache/events.html) +and +[executor.html](../../html/browsers/browsing-the-web/back-forward-cache/resources/executor.html) +in back-forward cache tests. + +Note that `executor*` files under `/common/dispatcher/` are NOT for +`RemoteContext.execute_script()`. Use `remote-executor.html` instead. + +This is universal and avoids introducing many specific `XXX-helper.html` +resources. +Moreover, tests are easier to read, because the whole logic of the test can be +defined in a single file. + +## `new RemoteContext(uuid)` + +- `uuid` is a UUID string that identifies the remote context and should match + with the `uuid` parameter of the URL of the remote context. +- Callers should create the remote context outside this constructor (e.g. + `window.open('executor.html?uuid=' + uuid)`). + +## `RemoteContext.execute_script(fn, args)` + +- `fn` is a JavaScript function to execute on the remote context, which is + converted to a string using `toString()` and sent to the remote context. +- `args` is null or an array of arguments to pass to the function on the + remote context. Arguments are passed as JSON. +- If the return value of `fn` when executed in the remote context is a promise, + the promise returned by `execute_script` resolves to the resolved value of + that promise. Otherwise the `execute_script` promise resolves to the return + value of `fn`. + +Note that `fn` is evaluated on the remote context (`executor.html` in the +example above), while `args` are evaluated on the caller context +(`injector.html`) and then passed to the remote context. + +## Return value of injected functions and `execute_script()` + +If the return value of the injected function when executed in the remote +context is a promise, the promise returned by `execute_script` resolves to the +resolved value of that promise. Otherwise the `execute_script` promise resolves +to the return value of the function. + +When the return value of an injected script is a Promise, it should be resolved +before any navigation starts on the remote context. For example, it shouldn't +be resolved after navigating out and navigating back to the page again. +It's fine to create a Promise to be resolved after navigations, if it's not the +return value of the injected function. + +## Calling timing of `execute_script()` + +When `RemoteContext.execute_script()` is called when the remote context is not +active (for example before it is created, before navigation to the page, or +during the page is in back-forward cache), the injected script is evaluated +after the remote context becomes active. + +Multiple calls to `RemoteContext.execute_script()` will result in multiple scripts +being executed in remote context and ordering will be maintained. + +## Errors from `execute_script()` + +Errors from `execute_script()` will result in promise rejections, so it is +important to await the result. This can be `await ctx.execute_script(...)` for +every call but if there are multiple scripts to executed, it may be preferable +to wait on them in parallel to avoid incurring full round-trip time for each, +e.g. + +```js +await Promise.all( + ctx1.execute_script(...), + ctx1.execute_script(...), + ctx2.execute_script(...), + ctx2.execute_script(...), + ... +) +``` + +## Evaluation timing of injected functions + +The script injected by `RemoteContext.execute_script()` can be evaluated any +time during the remote context is active. +For example, even before DOMContentLoaded events or even during navigation. +It's the responsibility of test-specific code/helpers to ensure evaluation +timing constraints (which can be also test-specific), if any needed. + +### Ensuring evaluation timing around page load + +For example, to ensure that injected functions (`mainFunction` below) are +evaluated after the first `pageshow` event, we can use pure JavaScript code +like below: + +``` +// executor.html +window.pageShowPromise = new Promise(resolve => + window.addEventListener('pageshow', resolve, {once: true})); + + +// injector.html +const waitForPageShow = async () => { + while (!window.pageShowPromise) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + await window.pageShowPromise; +}; + +await ctx.execute(waitForPageShow); +await ctx.execute(mainFunction); +``` + +### Ensuring evaluation timing around navigation out/unloading + +It can be important to ensure there are no injected functions nor code behind +`RemoteContext` (such as Fetch APIs accessing server-side stash) running after +navigation is initiated, for example in the case of back-forward cache testing. + +To ensure this, + +- Do not call the next `RemoteContext.execute()` for the remote context after + triggering the navigation, until we are sure that the remote context is not + active (e.g. after we confirm that the new page is loaded). +- Call `Executor.suspend(callback)` synchronously within the injected script. + This suspends executor-related code, and calls `callback` when it is ready + to start navigation. + +The code on the injector side would be like: + +``` +// injector.html +await ctx.execute_script(() => { + executor.suspend(() => { + location.href = 'new-url.html'; + }); +}); +``` + +## Future Work: Possible integration with `test_driver` + +Currently `RemoteContext` is implemented by JavaScript and WPT-server-side +stash, and not integrated with `test_driver` nor `testharness`. +There is a proposal of `test_driver`-integrated version (see the RFCs listed +above). + +The API semantics and guidelines in this document are designed to be applicable +to both the current stash-based `RemoteContext` and `test_driver`-based +version, and thus the tests using `RemoteContext` will be migrated with minimum +modifications (mostly in `/common/dispatcher/dispatcher.js` and executors), for +example in a +[draft CL](https://chromium-review.googlesource.com/c/chromium/src/+/3082215/). + + +# `send()`/`receive()` Message passing APIs + +`dispatcher.js` (and its server-side backend `dispatcher.py`) provides a +universal queue-based message passing API. +Each queue is identified by a UUID, and accessed via the following APIs: + +- `send(uuid, message)` pushes a string `message` to the queue `uuid`. +- `receive(uuid)` pops the first item from the queue `uuid`. +- `showRequestHeaders(origin, uuid)` and + `cacheableShowRequestHeaders(origin, uuid)` return URLs, that push request + headers to the queue `uuid` upon fetching. + +It works cross-origin, and even access different browser context groups. + +Messages are queued, this means one doesn't need to wait for the receiver to +listen, before sending the first message +(but still need to wait for the resolution of the promise returned by `send()` +to ensure the order between `send()`s). + +## Executors + +Similar to `RemoteContext.execute_script()`, `send()`/`receive()` can be used +for sending arbitrary javascript to be evaluated in another page or worker. + +- `executor.html` (as a Document), +- `executor-worker.js` (as a Web Worker), and +- `executor-service-worker.js` (as a Service Worker) + +are examples of executors. +Note that these executors are NOT compatible with +`RemoteContext.execute_script()`. + +## Future Work + +`send()`, `receive()` and the executors below are kept for COEP/COOP tests. + +For remote script execution, new tests should use +`RemoteContext.execute_script()` instead. + +For message passing, +[WPT RFC 90](https://github.com/web-platform-tests/rfcs/pull/90) is still under +discussion. diff --git a/test/fixtures/wpt/common/dispatcher/dispatcher.js b/test/fixtures/wpt/common/dispatcher/dispatcher.js new file mode 100644 index 00000000000000..a0f9f43e622483 --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/dispatcher.js @@ -0,0 +1,256 @@ +// 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; + +// Return a promise, limiting the number of concurrent accesses to a shared +// resources to |max_concurrent_access|. +const concurrencyLimiter = (max_concurrency) => { + let pending = 0; + let waiting = []; + return async (task) => { + pending++; + if (pending > max_concurrency) + await new Promise(resolve => waiting.push(resolve)); + let result = await task(); + pending--; + waiting.shift()?.(); + return result; + }; +} + +// Wait for a random amount of time in the range [10ms,100ms]. +const randomDelay = () => { + return new Promise(resolve => setTimeout(resolve, 10 + 90*Math.random())); +} + +// Sending too many requests in parallel causes congestion. Limiting it improves +// throughput. +// +// Note: The following table has been determined on the test: +// ../cache-storage.tentative.https.html +// using Chrome with a 64 core CPU / 64GB ram, in release mode: +// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ” +// โ”‚concurrencyโ”‚ 1 โ”‚ 2 โ”‚ 3 โ”‚ 4 โ”‚ 5 โ”‚ 6 โ”‚ 10โ”‚ 15โ”‚ 20โ”‚ 30โ”‚ 50โ”‚ 100โ”‚ +// โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ค +// โ”‚time (s) โ”‚ 54โ”‚ 38โ”‚ 31โ”‚ 29โ”‚ 26โ”‚ 24โ”‚ 22โ”‚ 22โ”‚ 22โ”‚ 22โ”‚ 34โ”‚ 36 โ”‚ +// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”˜ +const limiter = concurrencyLimiter(6); + +// While requests to different remote contexts can go in parallel, we need to +// ensure that requests to each remote context are done in order. This maps a +// uuid to a queue of requests to send. A queue is processed until it is empty +// and then is deleted from the map. +const sendQueues = new Map(); + +// Sends a single item (with rate-limiting) and calls the associated resolver +// when it is successfully sent. +const sendItem = async function (uuid, resolver, message) { + await limiter(async () => { + // Requests might be dropped. Retry until getting a confirmation it has been + // processed. + while(1) { + try { + let response = await fetch(dispatcher_url + `?uuid=${uuid}`, { + method: 'POST', + body: message + }) + if (await response.text() == "done") { + resolver(); + return; + } + } catch (fetch_error) {} + await randomDelay(); + }; + }); +} + +// While the queue is non-empty, send the next item. This is async and new items +// may be added to the queue while others are being sent. +const processQueue = async function (uuid, queue) { + while (queue.length) { + const [resolver, message] = queue.shift(); + await sendItem(uuid, resolver, message); + } + // The queue is empty, delete it. + sendQueues.delete(uuid); +} + +const send = async function (uuid, message) { + const itemSentPromise = new Promise((resolve) => { + const item = [resolve, message]; + if (sendQueues.has(uuid)) { + // There is already a queue for `uuid`, just add to it and it will be processed. + sendQueues.get(uuid).push(item); + } else { + // There is no queue for `uuid`, create it and start processing. + const queue = [item]; + sendQueues.set(uuid, queue); + processQueue(uuid, queue); + } + }); + // Wait until the item has been successfully sent. + await itemSentPromise; +} + +const receive = async function (uuid) { + while(1) { + let data = "not ready"; + try { + data = await limiter(async () => { + let response = await fetch(dispatcher_url + `?uuid=${uuid}`); + return await response.text(); + }); + } catch (fetch_error) {} + + if (data == "not ready") { + await randomDelay(); + continue; + } + + return data; + } +} + +// Returns an URL. When called, the server sends toward the `uuid` queue the +// request headers. Useful for determining if something was requested with +// Cookies. +const showRequestHeaders = function(origin, uuid) { + return origin + dispatcher_path + `?uuid=${uuid}&show-headers`; +} + +// Same as above, except for the response is cacheable. +const cacheableShowRequestHeaders = function(origin, uuid) { + return origin + dispatcher_path + `?uuid=${uuid}&cacheable&show-headers`; +} + +// This script requires +// - `/common/utils.js` for `token()`. + +// Returns the URL of a document that can be used as a `RemoteContext`. +// +// `uuid` should be a UUID uniquely identifying the given remote context. +// `options` has the following shape: +// +// { +// host: (optional) Sets the returned URL's `host` property. Useful for +// cross-origin executors. +// protocol: (optional) Sets the returned URL's `protocol` property. +// } +function remoteExecutorUrl(uuid, options) { + const url = new URL("/common/dispatcher/remote-executor.html", location); + url.searchParams.set("uuid", uuid); + + if (options?.host) { + url.host = options.host; + } + + if (options?.protocol) { + url.protocol = options.protocol; + } + + return url; +} + +// Represents a remote executor. For more detailed explanation see `README.md`. +class RemoteContext { + // `uuid` is a UUID string that identifies the remote context and should + // match with the `uuid` parameter of the URL of the remote context. + constructor(uuid) { + this.context_id = uuid; + } + + // Evaluates the script `expr` on the executor. + // - If `expr` is evaluated to a Promise that is resolved with a value: + // `execute_script()` returns a Promise resolved with the value. + // - If `expr` is evaluated to a non-Promise value: + // `execute_script()` returns a Promise resolved with the value. + // - If `expr` throws an error or is evaluated to a Promise that is rejected: + // `execute_script()` returns a rejected Promise with the error's + // `message`. + // Note that currently the type of error (e.g. DOMException) is not + // preserved, except for `TypeError`. + // The values should be able to be serialized by JSON.stringify(). + async execute_script(fn, args) { + const receiver = token(); + await this.send({receiver: receiver, fn: fn.toString(), args: args}); + const response = JSON.parse(await receive(receiver)); + if (response.status === 'success') { + return response.value; + } + + // exception + if (response.name === 'TypeError') { + throw new TypeError(response.value); + } + throw new Error(response.value); + } + + async send(msg) { + return await send(this.context_id, JSON.stringify(msg)); + } +}; + +class Executor { + constructor(uuid) { + this.uuid = uuid; + + // If `suspend_callback` is not `null`, the executor should be suspended + // when there are no ongoing tasks. + this.suspend_callback = null; + + this.execute(); + } + + // Wait until there are no ongoing tasks nor fetch requests for polling + // tasks, and then suspend the executor and call `callback()`. + // Navigation from the executor page should be triggered inside `callback()`, + // to avoid conflict with in-flight fetch requests. + suspend(callback) { + this.suspend_callback = callback; + } + + resume() { + } + + async execute() { + while(true) { + if (this.suspend_callback !== null) { + this.suspend_callback(); + this.suspend_callback = null; + // Wait for `resume()` to be called. + await new Promise(resolve => this.resume = resolve); + + // Workaround for https://crbug.com/1244230. + // Without this workaround, the executor is resumed and the fetch + // request to poll the next task is initiated synchronously from + // pageshow event after the page restored from BFCache, and the fetch + // request promise is never resolved (and thus the test results in + // timeout) due to https://crbug.com/1244230. The root cause is not yet + // known, but setTimeout() with 0ms causes the resume triggered on + // another task and seems to resolve the issue. + await new Promise(resolve => setTimeout(resolve, 0)); + + continue; + } + + const task = JSON.parse(await receive(this.uuid)); + + let response; + try { + const value = await eval(task.fn).apply(null, task.args); + response = JSON.stringify({ + status: 'success', + value: value + }); + } catch(e) { + response = JSON.stringify({ + status: 'exception', + name: e.name, + value: e.message + }); + } + await send(task.receiver, response); + } + } +} diff --git a/test/fixtures/wpt/common/dispatcher/executor-service-worker.js b/test/fixtures/wpt/common/dispatcher/executor-service-worker.js new file mode 100644 index 00000000000000..0b47d66b65f066 --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/executor-service-worker.js @@ -0,0 +1,24 @@ +importScripts('./dispatcher.js'); + +const params = new URLSearchParams(location.search); +const uuid = params.get('uuid'); + +// The fetch handler must be registered before parsing the main script response. +// So do it here, for future use. +fetchHandler = () => {} +addEventListener('fetch', e => { + fetchHandler(e); +}); + +// Force ServiceWorker to immediately activate itself. +addEventListener('install', event => { + skipWaiting(); +}); + +let executeOrders = async function() { + while(true) { + let task = await receive(uuid); + eval(`(async () => {${task}})()`); + } +}; +executeOrders(); diff --git a/test/fixtures/wpt/common/dispatcher/executor-worker.js b/test/fixtures/wpt/common/dispatcher/executor-worker.js new file mode 100644 index 00000000000000..ea065a6bf11955 --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/executor-worker.js @@ -0,0 +1,12 @@ +importScripts('./dispatcher.js'); + +const params = new URLSearchParams(location.search); +const uuid = params.get('uuid'); + +let executeOrders = async function() { + while(true) { + let task = await receive(uuid); + eval(`(async () => {${task}})()`); + } +}; +executeOrders(); diff --git a/test/fixtures/wpt/common/dispatcher/executor.html b/test/fixtures/wpt/common/dispatcher/executor.html new file mode 100644 index 00000000000000..5fe6a95efaf97d --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/executor.html @@ -0,0 +1,15 @@ + + diff --git a/test/fixtures/wpt/common/dispatcher/remote-executor.html b/test/fixtures/wpt/common/dispatcher/remote-executor.html new file mode 100644 index 00000000000000..8b0030390d0d19 --- /dev/null +++ b/test/fixtures/wpt/common/dispatcher/remote-executor.html @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/test/fixtures/wpt/common/gc.js b/test/fixtures/wpt/common/gc.js new file mode 100644 index 00000000000000..ac43a4cfaf7735 --- /dev/null +++ b/test/fixtures/wpt/common/gc.js @@ -0,0 +1,52 @@ +/** + * Does a best-effort attempt at invoking garbage collection. Attempts to use + * the standardized `TestUtils.gc()` function, but falls back to other + * environment-specific nonstandard functions, with a final result of just + * creating a lot of garbage (in which case you will get a console warning). + * + * This should generally only be used to attempt to trigger bugs and crashes + * inside tests, i.e. cases where if garbage collection happened, then this + * should not trigger some misbehavior. You cannot rely on garbage collection + * successfully trigger, or that any particular unreachable object will be + * collected. + * + * @returns {Promise} A promise you should await to ensure garbage + * collection has had a chance to complete. + */ +self.garbageCollect = async () => { + // https://testutils.spec.whatwg.org/#the-testutils-namespace + if (self.TestUtils?.gc) { + return TestUtils.gc(); + } + + // Use --expose_gc for V8 (and Node.js) + // to pass this flag at chrome launch use: --js-flags="--expose-gc" + // Exposed in SpiderMonkey shell as well + if (self.gc) { + return self.gc(); + } + + // Present in some WebKit development environments + if (self.GCController) { + return GCController.collect(); + } + + console.warn( + 'Tests are running without the ability to do manual garbage collection. ' + + 'They will still work, but coverage will be suboptimal.'); + + for (var i = 0; i < 1000; i++) { + gcRec(10); + } + + function gcRec(n) { + if (n < 1) { + return {}; + } + + let temp = { i: "ab" + i + i / 100000 }; + temp += "foo"; + + gcRec(n - 1); + } +}; diff --git a/test/fixtures/wpt/common/media.js b/test/fixtures/wpt/common/media.js index e9b1e6b0fbe6ae..f2dc8612660495 100644 --- a/test/fixtures/wpt/common/media.js +++ b/test/fixtures/wpt/common/media.js @@ -47,9 +47,9 @@ function getMediaContentType(url) { var extension = new URL(url, location).pathname.split(".").pop(); var map = { "mp4": "video/mp4", - "ogv": "video/ogg", + "ogv": "application/ogg", "mp3": "audio/mp3", - "oga": "audio/ogg", + "oga": "application/ogg", }; return map[extension]; } diff --git a/test/fixtures/wpt/common/object-association.js b/test/fixtures/wpt/common/object-association.js index 458aae67db0cef..669c17c07b1ae5 100644 --- a/test/fixtures/wpt/common/object-association.js +++ b/test/fixtures/wpt/common/object-association.js @@ -1,58 +1,64 @@ "use strict"; -// For now this only has per-Window tests, but we could expand it to also test per-Document +// This is for testing whether an object (e.g., a global property) is associated with Window, or +// with Document. Recall that Window and Document are 1:1 except when doing a same-origin navigation +// away from the initial about:blank. In that case the Window object gets reused for the new +// Document. +// +// So: +// - If something is per-Window, then it should maintain its identity across an about:blank +// navigation. +// - If something is per-Document, then it should be recreated across an about:blank navigation. -/** - * Run tests for window[propertyName] after discarding the browsing context, navigating, etc. - * @param {string} propertyName - */ window.testIsPerWindow = propertyName => { - test(t => { + runTests(propertyName, assert_equals, "must not"); +}; + +window.testIsPerDocument = propertyName => { + runTests(propertyName, assert_not_equals, "must"); +}; + +function runTests(propertyName, equalityOrInequalityAsserter, mustOrMustNotReplace) { + async_test(t => { const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + assert_implements(before, `window.${propertyName} must be implemented`); - iframe.remove(); + iframe.onload = t.step_func_done(() => { + const after = frame[propertyName]; + equalityOrInequalityAsserter(after, before); + }); - const after = frame[propertyName]; - assert_equals(after, before, `window.${propertyName} should not change after iframe.remove()`); - }, `Discarding the browsing context must not change window.${propertyName}`); + iframe.src = "/common/blank.html"; + }, `Navigating from the initial about:blank ${mustOrMustNotReplace} replace window.${propertyName}`); - async_test(t => { + // Per spec, discarding a browsing context should not change any of the global objects. + test(() => { const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); - - // Note: cannot use step_func_done for this because it might be called twice, per the below comment. - iframe.onload = t.step_func(() => { - if (frame.location.href === "about:blank") { - // Browsers are not reliable on whether about:blank fires the load event; see - // https://github.com/whatwg/html/issues/490 - return; - } + assert_implements(before, `window.${propertyName} must be implemented`); - const after = frame[propertyName]; - assert_equals(after, before); - t.done(); - }); + iframe.remove(); - iframe.src = "/common/blank.html"; - }, `Navigating from the initial about:blank must not replace window.${propertyName}`); + const after = frame[propertyName]; + assert_equals(after, before, `window.${propertyName} should not change after iframe.remove()`); + }, `Discarding the browsing context must not change window.${propertyName}`); - // Per spec, document.open() should not change any of the Window state. + // Per spec, document.open() should not change any of the global objects. In historical versions + // of the spec, it did, so we test here. async_test(t => { const iframe = document.createElement("iframe"); iframe.onload = t.step_func_done(() => { const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + assert_implements(before, `window.${propertyName} must be implemented`); frame.document.open(); @@ -64,5 +70,5 @@ window.testIsPerWindow = propertyName => { iframe.src = "/common/blank.html"; document.body.appendChild(iframe); - }, `document.open() must replace window.${propertyName}`); -}; + }, `document.open() must not replace window.${propertyName}`); +} diff --git a/test/fixtures/wpt/common/proxy-all.sub.pac b/test/fixtures/wpt/common/proxy-all.sub.pac new file mode 100644 index 00000000000000..de601e5d7020e0 --- /dev/null +++ b/test/fixtures/wpt/common/proxy-all.sub.pac @@ -0,0 +1,3 @@ +function FindProxyForURL(url, host) { + return "PROXY {{host}}:{{ports[http][0]}}" +} diff --git a/test/fixtures/wpt/common/reftest-wait.js b/test/fixtures/wpt/common/reftest-wait.js index 0a30a197f07f4d..64fe9bfd7f54ae 100644 --- a/test/fixtures/wpt/common/reftest-wait.js +++ b/test/fixtures/wpt/common/reftest-wait.js @@ -18,3 +18,22 @@ function takeScreenshotDelayed(timeout) { takeScreenshot(); }, timeout); } + +/** + * Ensure that a precondition is met before waiting for a screenshot. + * @param {bool} condition - Fail the test if this evaluates to false + * @param {string} msg - Error message to write to the screenshot + */ +function failIfNot(condition, msg) { + const fail = () => { + (document.body || document.documentElement).textContent = `Precondition Failed: ${msg}`; + takeScreenshot(); + }; + if (!condition) { + if (document.readyState == "interactive") { + fail(); + } else { + document.addEventListener("DOMContentLoaded", fail, false); + } + } +} diff --git a/test/fixtures/wpt/common/sab.js b/test/fixtures/wpt/common/sab.js index 47d12970d393c1..a3ea610e165d0d 100644 --- a/test/fixtures/wpt/common/sab.js +++ b/test/fixtures/wpt/common/sab.js @@ -6,14 +6,14 @@ const createBuffer = (() => { } catch(e) { sabConstructor = null; } - return (type, length) => { + return (type, length, opts) => { if (type === "ArrayBuffer") { - return new ArrayBuffer(length); + return new ArrayBuffer(length, opts); } else if (type === "SharedArrayBuffer") { if (sabConstructor && sabConstructor.name !== "SharedArrayBuffer") { throw new Error("WebAssembly.Memory does not support shared:true"); } - return new sabConstructor(length); + return new sabConstructor(length, opts); } else { throw new Error("type has to be ArrayBuffer or SharedArrayBuffer"); } diff --git a/test/fixtures/wpt/common/security-features/resources/common.sub.js b/test/fixtures/wpt/common/security-features/resources/common.sub.js index 402ce9bbacf347..96ca280597bf29 100644 --- a/test/fixtures/wpt/common/security-features/resources/common.sub.js +++ b/test/fixtures/wpt/common/security-features/resources/common.sub.js @@ -485,9 +485,13 @@ function dedicatedWorkerUrlThatFetches(url) { .catch((e) => postMessage(e.message));`; } -function workerUrlThatImports(url) { +function workerUrlThatImports(url, additionalAttributes) { + let csp = ""; + if (additionalAttributes && additionalAttributes.contentSecurityPolicy) { + csp=`&contentSecurityPolicy=${additionalAttributes.contentSecurityPolicy}`; + } return `/common/security-features/subresource/static-import.py` + - `?import_url=${encodeURIComponent(url)}`; + `?import_url=${encodeURIComponent(url)}${csp}`; } function workerDataUrlThatImports(url) { @@ -630,6 +634,24 @@ function requestViaScript(url, additionalAttributes) { .then(event => wrapResult(event.data)); } +/** + * Creates a new script element that performs a dynamic import to `url`, and + * appends the script element to {@code document.body}. + * @param {string} url The src URL. + * @return {Promise} The promise for success/error events. + */ +function requestViaDynamicImport(url, additionalAttributes) { + const scriptUrl = `data:text/javascript,import("${url}");`; + const script = createElement( + "script", + Object.assign({"src": scriptUrl}, additionalAttributes), + document.body, + false); + + return bindEvents2(window, "message", script, "error", window, "error") + .then(event => wrapResult(event.data)); +} + /** * Creates a new form element, sets attributes, appends it to * {@code document.body} and submits the form. @@ -866,6 +888,10 @@ const subresourceMap = { path: "/common/security-features/subresource/script.py", invoker: requestViaScript, }, + "script-tag-dynamic-import": { + path: "/common/security-features/subresource/script.py", + invoker: requestViaDynamicImport, + }, "video-tag": { path: "/common/security-features/subresource/video.py", invoker: requestViaVideo, @@ -885,8 +911,8 @@ const subresourceMap = { }, "worker-import": { path: "/common/security-features/subresource/worker.py", - invoker: url => - requestViaDedicatedWorker(workerUrlThatImports(url), {type: "module"}), + invoker: (url, additionalAttributes) => + requestViaDedicatedWorker(workerUrlThatImports(url, additionalAttributes), {type: "module"}), }, "worker-import-data": { path: "/common/security-features/subresource/worker.py", @@ -903,8 +929,8 @@ const subresourceMap = { }, "sharedworker-import": { path: "/common/security-features/subresource/shared-worker.py", - invoker: url => - requestViaSharedWorker(workerUrlThatImports(url), {type: "module"}), + invoker: (url, additionalAttributes) => + requestViaSharedWorker(workerUrlThatImports(url, additionalAttributes), {type: "module"}), }, "sharedworker-import-data": { path: "/common/security-features/subresource/shared-worker.py", @@ -1087,6 +1113,10 @@ function invokeRequest(subresource, sourceContextList) { additionalAttributes[policyDelivery.key] = policyDelivery.value; } else if (policyDelivery.deliveryType === "rel-noref") { additionalAttributes["rel"] = "noreferrer"; + } else if (policyDelivery.deliveryType === "http-rp") { + additionalAttributes[policyDelivery.key] = policyDelivery.value; + } else if (policyDelivery.deliveryType === "meta") { + additionalAttributes[policyDelivery.key] = policyDelivery.value; } } diff --git a/test/fixtures/wpt/common/security-features/tools/spec.src.json b/test/fixtures/wpt/common/security-features/tools/spec.src.json index 0a46a1cd6d3182..4a84493f475b01 100644 --- a/test/fixtures/wpt/common/security-features/tools/spec.src.json +++ b/test/fixtures/wpt/common/security-features/tools/spec.src.json @@ -106,6 +106,7 @@ "object-tag", "picture-tag", "script-tag", + "script-tag-dynamic-import", "sharedworker-classic", "sharedworker-import", "sharedworker-import-data", @@ -327,26 +328,6 @@ ], "subresourcePolicyDeliveries": [] }, - "worker-classic-inherit": { - // This is applicable to upgrade-insecure-requests and mixed-content tests. - // Use "worker-classic" for referrer-policy. - "description": "dedicated workers should inherit its parent's policy.", - "sourceContextList": [ - { - "sourceContextType": "top", - "policyDeliveries": [ - "policy" - ] - }, - { - "sourceContextType": "worker-classic", - "policyDeliveries": [ - "anotherPolicy" - ] - } - ], - "subresourcePolicyDeliveries": [] - }, "worker-classic-data": { "description": "data: dedicated workers should inherit its parent's policy.", "sourceContextList": [ @@ -365,7 +346,6 @@ }, "worker-module": { // This is applicable to referrer-policy tests. - // Use "worker-module-inherit" for CSP (mixed-content, etc.). "description": "dedicated workers shouldn't inherit its parent's policy.", "sourceContextList": [ { @@ -383,26 +363,6 @@ ], "subresourcePolicyDeliveries": [] }, - "worker-module-inherit": { - // This is applicable to upgrade-insecure-requests and mixed-content tests. - // Use "worker-module" for referrer-policy. - "description": "dedicated workers should inherit its parent's policy.", - "sourceContextList": [ - { - "sourceContextType": "top", - "policyDeliveries": [ - "policy" - ] - }, - { - "sourceContextType": "worker-module", - "policyDeliveries": [ - "anotherPolicy" - ] - } - ], - "subresourcePolicyDeliveries": [] - }, "worker-module-data": { "description": "data: dedicated workers should inherit its parent's policy.", "sourceContextList": [ @@ -505,10 +465,8 @@ "iframe", "iframe-blank-inherit", "worker-classic", - "worker-classic-inherit", "worker-classic-data", "worker-module", - "worker-module-inherit", "worker-module-data", "sharedworker-classic", "sharedworker-classic-data", @@ -550,6 +508,7 @@ "object-tag", "picture-tag", "script-tag", + "script-tag-dynamic-import", "sharedworker-classic", "sharedworker-import", "sharedworker-import-data", diff --git a/test/fixtures/wpt/common/stringifiers.js b/test/fixtures/wpt/common/stringifiers.js index 18de6c8c5b32c5..8dadac1d4929d9 100644 --- a/test/fixtures/wpt/common/stringifiers.js +++ b/test/fixtures/wpt/common/stringifiers.js @@ -1,5 +1,5 @@ /** - * Runs tests for . + * Runs tests for . * @param {Object} aObject - object to test * @param {string} aAttribute - IDL attribute name that is annotated with `stringifier` * @param {boolean} aIsUnforgeable - whether the IDL attribute is `[LegacyUnforgeable]` diff --git a/test/fixtures/wpt/dom/events/document-level-touchmove-event-listener-passive-by-default.tentative.html b/test/fixtures/wpt/dom/events/document-level-touchmove-event-listener-passive-by-default.tentative.html deleted file mode 100644 index f3f0d58209fd8e..00000000000000 --- a/test/fixtures/wpt/dom/events/document-level-touchmove-event-listener-passive-by-default.tentative.html +++ /dev/null @@ -1,73 +0,0 @@ - -Default passive document level touchmove event listener test - - - - - - - -
-
- - - diff --git a/test/fixtures/wpt/dom/events/document-level-wheel-event-listener-passive-by-default.tentative.html b/test/fixtures/wpt/dom/events/document-level-wheel-event-listener-passive-by-default.tentative.html deleted file mode 100644 index b7224835fa398b..00000000000000 --- a/test/fixtures/wpt/dom/events/document-level-wheel-event-listener-passive-by-default.tentative.html +++ /dev/null @@ -1,51 +0,0 @@ - -Default passive document level wheel event listener manual test - - - - - - - -
This is a manual test since there is no way to synthesize wheel events. -Scroll by wheel in the middle of the page to run the test.
- - diff --git a/test/fixtures/wpt/encoding/gb18030-encoder.html b/test/fixtures/wpt/encoding/gb18030-encoder.html deleted file mode 100644 index 799d69274ef4fb..00000000000000 --- a/test/fixtures/wpt/encoding/gb18030-encoder.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - -
- diff --git a/test/fixtures/wpt/encoding/gbk-encoder.html b/test/fixtures/wpt/encoding/gbk-encoder.html deleted file mode 100644 index a6074f975d34fb..00000000000000 --- a/test/fixtures/wpt/encoding/gbk-encoder.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - -
- diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.html b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.html deleted file mode 100644 index b8fb0d04c44ee7..00000000000000 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.html b/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.html deleted file mode 100644 index 8c45683180070e..00000000000000 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gbk/gbk-decoder.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - diff --git a/test/fixtures/wpt/encoding/single-byte-decoder.html b/test/fixtures/wpt/encoding/single-byte-decoder.html deleted file mode 100644 index 70d8fb73eadb81..00000000000000 --- a/test/fixtures/wpt/encoding/single-byte-decoder.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - -
- diff --git a/test/fixtures/wpt/html/webappapis/timers/negative-setinterval.html b/test/fixtures/wpt/html/webappapis/timers/negative-setinterval.html deleted file mode 100644 index 663872cd1f3850..00000000000000 --- a/test/fixtures/wpt/html/webappapis/timers/negative-setinterval.html +++ /dev/null @@ -1,18 +0,0 @@ - -Negative timeout in setInterval - - - diff --git a/test/fixtures/wpt/html/webappapis/timers/negative-settimeout.html b/test/fixtures/wpt/html/webappapis/timers/negative-settimeout.html deleted file mode 100644 index b59fc8f22984c8..00000000000000 --- a/test/fixtures/wpt/html/webappapis/timers/negative-settimeout.html +++ /dev/null @@ -1,9 +0,0 @@ - -Negative timeout in setTimeout - - - diff --git a/test/fixtures/wpt/html/webappapis/timers/type-long-setinterval.html b/test/fixtures/wpt/html/webappapis/timers/type-long-setinterval.html deleted file mode 100644 index 7fb81ff29ac3a9..00000000000000 --- a/test/fixtures/wpt/html/webappapis/timers/type-long-setinterval.html +++ /dev/null @@ -1,14 +0,0 @@ - -Type long timeout for setInterval - - - diff --git a/test/fixtures/wpt/html/webappapis/timers/type-long-settimeout.html b/test/fixtures/wpt/html/webappapis/timers/type-long-settimeout.html deleted file mode 100644 index 4dc7d17ea5f13f..00000000000000 --- a/test/fixtures/wpt/html/webappapis/timers/type-long-settimeout.html +++ /dev/null @@ -1,9 +0,0 @@ - -Type long timeout for setTimeout - - - diff --git a/test/fixtures/wpt/resources/.gitignore b/test/fixtures/wpt/resources/.gitignore deleted file mode 100644 index 04fdeda1cc4ea1..00000000000000 --- a/test/fixtures/wpt/resources/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -ROBIN-TODO.txt -scratch -node_modules diff --git a/test/fixtures/wpt/resources/LICENSE b/test/fixtures/wpt/resources/LICENSE deleted file mode 100644 index 45896e6be2bd51..00000000000000 --- a/test/fixtures/wpt/resources/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -W3C 3-clause BSD License - -http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of works must retain the original copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the original copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name of the W3C nor the names of its contributors may be - used to endorse or promote products derived from this work without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/test/fixtures/wpt/resources/check-layout-th.js b/test/fixtures/wpt/resources/check-layout-th.js index 9cd8abc938d9fb..f14ca3246b8ea2 100644 --- a/test/fixtures/wpt/resources/check-layout-th.js +++ b/test/fixtures/wpt/resources/check-layout-th.js @@ -26,7 +26,11 @@ function assert_tolerance(actual, expected, message) } function checkDataKeys(node) { + // The purpose of this list of data-* attributes is simply to ensure typos + // in tests are caught. It is therefore "ok" to add to this list for + // specific tests. var validData = new Set([ + "data-anchor-polyfill", "data-expected-width", "data-expected-height", "data-offset-x", diff --git a/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js b/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js new file mode 100644 index 00000000000000..8ab08b0294c297 --- /dev/null +++ b/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js @@ -0,0 +1,24 @@ +/* + * 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 shadowRoot = template.parentNode.attachShadow({ mode }); + shadowRoot.appendChild(template.content); + template.remove(); + polyfill_declarative_shadow_dom(shadowRoot); + }); +} diff --git a/test/fixtures/wpt/resources/idlharness-shadowrealm.js b/test/fixtures/wpt/resources/idlharness-shadowrealm.js index 05c4a1affc8699..9484ca6f512ad0 100644 --- a/test/fixtures/wpt/resources/idlharness-shadowrealm.js +++ b/test/fixtures/wpt/resources/idlharness-shadowrealm.js @@ -21,11 +21,6 @@ function fetch_text(url) { * dependency (i.e. have already been seen). */ function idl_test_shadowrealm(srcs, deps) { - const script_urls = [ - "/resources/testharness.js", - "/resources/WebIDLParser.js", - "/resources/idlharness.js", - ]; promise_setup(async t => { const realm = new ShadowRealm(); // https://github.com/web-platform-tests/wpt/issues/31996 @@ -38,44 +33,29 @@ function idl_test_shadowrealm(srcs, deps) { isShadowRealm: function() { return true; }, }; undefined; `); - - const ss = await Promise.all(script_urls.map(url => fetch_text(url))); - for (const s of ss) { - realm.evaluate(s); - } const specs = await Promise.all(srcs.concat(deps).map(spec => { return fetch_text("/interfaces/" + spec + ".idl"); })); const idls = JSON.stringify(specs); - - const results = JSON.parse(await new Promise( - realm.evaluate(`(resolve,reject) => { - const idls = ${idls}; - add_completion_callback(function (tests, harness_status, asserts_run) { - resolve(JSON.stringify(tests)); - }); - - // Without the wrapping test, testharness.js will think it's done after it has run - // the first idlharness test. - test(() => { - const idl_array = new IdlArray(); - for (let i = 0; i < ${srcs.length}; i++) { - idl_array.add_idls(idls[i]); - } - for (let i = ${srcs.length}; i < ${srcs.length + deps.length}; i++) { - idl_array.add_dependency_idls(idls[i]); - } - idl_array.test(); - }, "setup"); - }`) - )); - - // We ran the tests in the ShadowRealm and gathered the results. Now treat them as if - // we'd run them directly here, so we can see them. - for (const {name, status, message} of results) { - // TODO: make this an API in testharness.js - needs RFC? - promise_test(t => {t.set_status(status, message); t.phase = t.phases.HAS_RESULT; t.done()}, name); - } - }, "outer setup"); + await new Promise( + realm.evaluate(`(resolve,reject) => { + (async () => { + await import("/resources/testharness.js"); + await import("/resources/WebIDLParser.js"); + await import("/resources/idlharness.js"); + const idls = ${idls}; + const idl_array = new IdlArray(); + for (let i = 0; i < ${srcs.length}; i++) { + idl_array.add_idls(idls[i]); + } + for (let i = ${srcs.length}; i < ${srcs.length + deps.length}; i++) { + idl_array.add_dependency_idls(idls[i]); + } + idl_array.test(); + })().then(resolve, (e) => reject(e.toString())); + }`) + ); + await fetch_tests_from_shadow_realm(realm); + }); } // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker: diff --git a/test/fixtures/wpt/resources/idlharness.js b/test/fixtures/wpt/resources/idlharness.js index d2fb0366c8022a..46aa11e5ca123c 100644 --- a/test/fixtures/wpt/resources/idlharness.js +++ b/test/fixtures/wpt/resources/idlharness.js @@ -2433,44 +2433,6 @@ IdlInterface.prototype.test_to_json_operation = function(desc, memberHolderObjec } }; -IdlInterface.prototype.test_member_iterable = function(member) -{ - subsetTestByKey(this.name, test, function() - { - var isPairIterator = member.idlType.length === 2; - var proto = this.get_interface_object().prototype; - var iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.iterator); - - assert_true(iteratorDesc.writable, "@@iterator property should be writable"); - assert_true(iteratorDesc.configurable, "@@iterator property should be configurable"); - assert_false(iteratorDesc.enumerable, "@@iterator property should not be enumerable"); - assert_equals(typeof iteratorDesc.value, "function", "@@iterator property should be a function"); - assert_equals(iteratorDesc.value.length, 0, "@@iterator function object length should be 0"); - assert_equals(iteratorDesc.value.name, isPairIterator ? "entries" : "values", "@@iterator function object should have the right name"); - - if (isPairIterator) { - assert_equals(proto["entries"], proto[Symbol.iterator], "entries method should be the same as @@iterator method"); - [ - ["entries", 0], - ["keys", 0], - ["values", 0], - ["forEach", 1] - ].forEach(([property, length]) => { - var desc = Object.getOwnPropertyDescriptor(proto, property); - assert_equals(typeof desc.value, "function", property + " property should be a function"); - assert_equals(desc.value.length, length, property + " function object should have the right length"); - assert_equals(desc.value.name, property, property + " function object should have the right name"); - }); - } else { - assert_equals(proto[Symbol.iterator], Array.prototype[Symbol.iterator], "@@iterator method should be the same as Array prototype's"); - ["entries", "keys", "values", "forEach", Symbol.iterator].forEach(property => { - var propertyName = property === Symbol.iterator ? "@@iterator" : property; - assert_equals(proto[property], Array.prototype[property], propertyName + " method should be the same as Array prototype's"); - }); - } - }.bind(this), this.name + " interface: iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">"); -}; - IdlInterface.prototype.test_member_maplike = function(member) { subsetTestByKey(this.name, test, () => { const proto = this.get_interface_object().prototype; @@ -2487,14 +2449,14 @@ IdlInterface.prototype.test_member_maplike = function(member) { methods.push( ["set", 2], ["delete", 1], - ["clear", 1] + ["clear", 0] ); } for (const [name, length] of methods) { const desc = Object.getOwnPropertyDescriptor(proto, name); assert_equals(typeof desc.value, "function", `${name} should be a function`); - assert_equals(desc.enumerable, false, `${name} enumerable`); + assert_equals(desc.enumerable, true, `${name} enumerable`); assert_equals(desc.configurable, true, `${name} configurable`); assert_equals(desc.writable, true, `${name} writable`); assert_equals(desc.value.length, length, `${name} function object length should be ${length}`); @@ -2510,10 +2472,10 @@ IdlInterface.prototype.test_member_maplike = function(member) { const sizeDesc = Object.getOwnPropertyDescriptor(proto, "size"); assert_equals(typeof sizeDesc.get, "function", `size getter should be a function`); assert_equals(sizeDesc.set, undefined, `size should not have a setter`); - assert_equals(sizeDesc.enumerable, false, `size enumerable`); + assert_equals(sizeDesc.enumerable, true, `size enumerable`); assert_equals(sizeDesc.configurable, true, `size configurable`); - assert_equals(sizeDesc.get.length, 0, `size getter length should have the right length`); - assert_equals(sizeDesc.get.name, "get size", `size getter have the right name`); + assert_equals(sizeDesc.get.length, 0, `size getter length`); + assert_equals(sizeDesc.get.name, "get size", `size getter name`); }, `${this.name} interface: maplike<${member.idlType.map(t => t.idlType).join(", ")}>`); }; @@ -2532,14 +2494,14 @@ IdlInterface.prototype.test_member_setlike = function(member) { methods.push( ["add", 1], ["delete", 1], - ["clear", 1] + ["clear", 0] ); } for (const [name, length] of methods) { const desc = Object.getOwnPropertyDescriptor(proto, name); assert_equals(typeof desc.value, "function", `${name} should be a function`); - assert_equals(desc.enumerable, false, `${name} enumerable`); + assert_equals(desc.enumerable, true, `${name} enumerable`); assert_equals(desc.configurable, true, `${name} configurable`); assert_equals(desc.writable, true, `${name} writable`); assert_equals(desc.value.length, length, `${name} function object length should be ${length}`); @@ -2555,42 +2517,92 @@ IdlInterface.prototype.test_member_setlike = function(member) { const sizeDesc = Object.getOwnPropertyDescriptor(proto, "size"); assert_equals(typeof sizeDesc.get, "function", `size getter should be a function`); assert_equals(sizeDesc.set, undefined, `size should not have a setter`); - assert_equals(sizeDesc.enumerable, false, `size enumerable`); + assert_equals(sizeDesc.enumerable, true, `size enumerable`); assert_equals(sizeDesc.configurable, true, `size configurable`); - assert_equals(sizeDesc.get.length, 0, `size getter length should have the right length`); - assert_equals(sizeDesc.get.name, "size", `size getter have the right name`); + assert_equals(sizeDesc.get.length, 0, `size getter length`); + assert_equals(sizeDesc.get.name, "get size", `size getter name`); }, `${this.name} interface: setlike<${member.idlType.map(t => t.idlType).join(", ")}>`); }; -IdlInterface.prototype.test_member_async_iterable = function(member) -{ - subsetTestByKey(this.name, test, function() - { - var isPairIterator = member.idlType.length === 2; - var proto = this.get_interface_object().prototype; - var iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.asyncIterator); +IdlInterface.prototype.test_member_iterable = function(member) { + subsetTestByKey(this.name, test, () => { + const isPairIterator = member.idlType.length === 2; + const proto = this.get_interface_object().prototype; - assert_true(iteratorDesc.writable, "@@asyncIterator property should be writable"); - assert_true(iteratorDesc.configurable, "@@asyncIterator property should be configurable"); - assert_false(iteratorDesc.enumerable, "@@asyncIterator property should not be enumerable"); - assert_equals(typeof iteratorDesc.value, "function", "@@asyncIterator property should be a function"); - assert_equals(iteratorDesc.value.length, 0, "@@asyncIterator function object length should be 0"); - assert_equals(iteratorDesc.value.name, isPairIterator ? "entries" : "values", "@@asyncIterator function object should have the right name"); + const methods = [ + ["entries", 0], + ["keys", 0], + ["values", 0], + ["forEach", 1] + ]; + + for (const [name, length] of methods) { + const desc = Object.getOwnPropertyDescriptor(proto, name); + assert_equals(typeof desc.value, "function", `${name} should be a function`); + assert_equals(desc.enumerable, true, `${name} enumerable`); + assert_equals(desc.configurable, true, `${name} configurable`); + assert_equals(desc.writable, true, `${name} writable`); + assert_equals(desc.value.length, length, `${name} function object length should be ${length}`); + assert_equals(desc.value.name, name, `${name} function object should have the right name`); + + if (!isPairIterator) { + assert_equals(desc.value, Array.prototype[name], `${name} equality with Array.prototype version`); + } + } + + const iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.iterator); + assert_equals(iteratorDesc.enumerable, false, `@@iterator enumerable`); + assert_equals(iteratorDesc.configurable, true, `@@iterator configurable`); + assert_equals(iteratorDesc.writable, true, `@@iterator writable`); if (isPairIterator) { - assert_equals(proto["entries"], proto[Symbol.asyncIterator], "entries method should be the same as @@asyncIterator method"); - ["entries", "keys", "values"].forEach(property => { - var desc = Object.getOwnPropertyDescriptor(proto, property); - assert_equals(typeof desc.value, "function", property + " property should be a function"); - assert_equals(desc.value.length, 0, property + " function object length should be 0"); - assert_equals(desc.value.name, property, property + " function object should have the right name"); - }); + assert_equals(iteratorDesc.value, proto.entries, `@@iterator equality with entries`); } else { - assert_equals(proto["values"], proto[Symbol.asyncIterator], "values method should be the same as @@asyncIterator method"); - assert_false("entries" in proto, "should not have an entries method"); - assert_false("keys" in proto, "should not have a keys method"); + assert_equals(iteratorDesc.value, Array.prototype[Symbol.iterator], `@@iterator equality with Array.prototype version`); } - }.bind(this), this.name + " interface: async iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">"); + }, `${this.name} interface: iterable<${member.idlType.map(t => t.idlType).join(", ")}>`); +}; + +IdlInterface.prototype.test_member_async_iterable = function(member) { + subsetTestByKey(this.name, test, () => { + const isPairIterator = member.idlType.length === 2; + const proto = this.get_interface_object().prototype; + + // Note that although the spec allows arguments, which will be passed to the @@asyncIterator + // method (which is either values or entries), those arguments must always be optional. So + // length of 0 is still correct for values and entries. + const methods = [ + ["values", 0], + ]; + + if (isPairIterator) { + methods.push( + ["entries", 0], + ["keys", 0] + ); + } + + for (const [name, length] of methods) { + const desc = Object.getOwnPropertyDescriptor(proto, name); + assert_equals(typeof desc.value, "function", `${name} should be a function`); + assert_equals(desc.enumerable, true, `${name} enumerable`); + assert_equals(desc.configurable, true, `${name} configurable`); + assert_equals(desc.writable, true, `${name} writable`); + assert_equals(desc.value.length, length, `${name} function object length should be ${length}`); + assert_equals(desc.value.name, name, `${name} function object should have the right name`); + } + + const iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.asyncIterator); + assert_equals(iteratorDesc.enumerable, false, `@@iterator enumerable`); + assert_equals(iteratorDesc.configurable, true, `@@iterator configurable`); + assert_equals(iteratorDesc.writable, true, `@@iterator writable`); + + if (isPairIterator) { + assert_equals(iteratorDesc.value, proto.entries, `@@iterator equality with entries`); + } else { + assert_equals(iteratorDesc.value, proto.values, `@@iterator equality with values`); + } + }, `${this.name} interface: async iterable<${member.idlType.map(t => t.idlType).join(", ")}>`); }; IdlInterface.prototype.test_member_stringifier = function(member) @@ -2656,6 +2668,7 @@ IdlInterface.prototype.test_member_stringifier = function(member) IdlInterface.prototype.test_members = function() { + var unexposed_members = new Set(); for (var i = 0; i < this.members.length; i++) { var member = this.members[i]; @@ -2664,15 +2677,18 @@ IdlInterface.prototype.test_members = function() } if (!exposed_in(exposure_set(member, this.exposureSet))) { - subsetTestByKey(this.name, test, function() { - // It's not exposed, so we shouldn't find it anywhere. - assert_false(member.name in this.get_interface_object(), - "The interface object must not have a property " + - format_value(member.name)); - assert_false(member.name in this.get_interface_object().prototype, - "The prototype object must not have a property " + - format_value(member.name)); - }.bind(this), this.name + " interface: member " + member.name); + if (!unexposed_members.has(member.name)) { + unexposed_members.add(member.name); + subsetTestByKey(this.name, test, function() { + // It's not exposed, so we shouldn't find it anywhere. + assert_false(member.name in this.get_interface_object(), + "The interface object must not have a property " + + format_value(member.name)); + assert_false(member.name in this.get_interface_object().prototype, + "The prototype object must not have a property " + + format_value(member.name)); + }.bind(this), this.name + " interface: member " + member.name); + } continue; } @@ -2751,21 +2767,26 @@ IdlInterface.prototype.test_object = function(desc) expected_typeof = "object"; } - this.test_primary_interface_of(desc, obj, exception, expected_typeof); + if (this.is_callback()) { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + } else { + this.test_primary_interface_of(desc, obj, exception, expected_typeof); - var current_interface = this; - while (current_interface) - { - if (!(current_interface.name in this.array.members)) + var current_interface = this; + while (current_interface) { - throw new IdlHarnessError("Interface " + current_interface.name + " not found (inherited by " + this.name + ")"); - } - if (current_interface.prevent_multiple_testing && current_interface.already_tested) - { - return; + if (!(current_interface.name in this.array.members)) + { + throw new IdlHarnessError("Interface " + current_interface.name + " not found (inherited by " + this.name + ")"); + } + if (current_interface.prevent_multiple_testing && current_interface.already_tested) + { + return; + } + current_interface.test_interface_of(desc, obj, exception, expected_typeof); + current_interface = this.array.members[current_interface.base]; } - current_interface.test_interface_of(desc, obj, exception, expected_typeof); - current_interface = this.array.members[current_interface.base]; } }; @@ -2838,17 +2859,23 @@ IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect return; } + var unexposed_properties = new Set(); for (var i = 0; i < this.members.length; i++) { var member = this.members[i]; if (member.untested) { continue; } - if (!exposed_in(exposure_set(member, this.exposureSet))) { - subsetTestByKey(this.name, test, function() { - assert_equals(exception, null, "Unexpected exception when evaluating object"); - assert_false(member.name in obj); - }.bind(this), this.name + " interface: " + desc + ' must not have property "' + member.name + '"'); + if (!exposed_in(exposure_set(member, this.exposureSet))) + { + if (!unexposed_properties.has(member.name)) + { + unexposed_properties.add(member.name); + subsetTestByKey(this.name, test, function() { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_false(member.name in obj); + }.bind(this), this.name + " interface: " + desc + ' must not have property "' + member.name + '"'); + } continue; } if (member.type == "attribute" && member.isUnforgeable) diff --git a/test/fixtures/wpt/resources/testdriver.js b/test/fixtures/wpt/resources/testdriver.js index 0737e64a50b313..76ae2834fdfb0a 100644 --- a/test/fixtures/wpt/resources/testdriver.js +++ b/test/fixtures/wpt/resources/testdriver.js @@ -78,8 +78,8 @@ * Trigger user interaction in order to grant additional privileges to * a provided function. * - * See `triggered by user activation - * `_. + * See `Tracking user activation + * `_. * * @example * var mediaElement = document.createElement('video'); @@ -184,6 +184,42 @@ return window.test_driver_internal.delete_all_cookies(context); }, + /** + * Get details for all cookies in the current context. + * See https://w3c.github.io/webdriver/#get-all-cookies + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Returns an array of cookies objects as defined in the spec: + * https://w3c.github.io/webdriver/#cookies + */ + get_all_cookies: function(context=null) { + return window.test_driver_internal.get_all_cookies(context); + }, + + /** + * Get details for a cookie in the current context by name if it exists. + * See https://w3c.github.io/webdriver/#get-named-cookie + * + * @param {String} name - The name of the cookie to get. + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Returns the matching cookie as defined in the spec: + * https://w3c.github.io/webdriver/#cookies + * Rejected if no such cookie exists. + */ + get_named_cookie: async function(name, context=null) { + let cookie = await window.test_driver_internal.get_named_cookie(name, context); + if (!cookie) { + throw new Error("no such cookie"); + } + return cookie; + }, + /** * Send keys to an element. * @@ -362,24 +398,22 @@ * * @example * await test_driver.set_permission({ name: "background-fetch" }, "denied"); - * await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted", true); + * await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted"); * - * @param {Object} descriptor - a `PermissionDescriptor - * `_ - * object + * @param {PermissionDescriptor} descriptor - a `PermissionDescriptor + * `_ + * dictionary. * @param {String} state - the state of the permission - * @param {boolean} one_realm - Optional. Whether the permission applies to only one realm * @param {WindowProxy} context - Browsing context in which * to run the call, or null for the current * browsing context. * @returns {Promise} fulfilled after the permission is set, or rejected if setting the * permission fails */ - set_permission: function(descriptor, state, one_realm=false, context=null) { + set_permission: function(descriptor, state, context=null) { let permission_params = { descriptor, state, - oneRealm: one_realm, }; return window.test_driver_internal.set_permission(permission_params, context); }, @@ -637,6 +671,14 @@ return Promise.reject(new Error("unimplemented")); }, + get_all_cookies: function(context=null) { + return Promise.reject(new Error("unimplemented")); + }, + + get_named_cookie: function(name, context=null) { + return Promise.reject(new Error("unimplemented")); + }, + send_keys: function(element, keys) { if (this.in_automation) { return Promise.reject(new Error('Not implemented')); diff --git a/test/fixtures/wpt/resources/testharness.css.headers b/test/fixtures/wpt/resources/testharness.css.headers deleted file mode 100644 index e828b629858d07..00000000000000 --- a/test/fixtures/wpt/resources/testharness.css.headers +++ /dev/null @@ -1,2 +0,0 @@ -Content-Type: text/css;charset=utf-8 -Cache-Control: max-age=3600 diff --git a/test/fixtures/wpt/resources/testharness.js b/test/fixtures/wpt/resources/testharness.js index 9ec328222097e0..112790bb1eeb87 100644 --- a/test/fixtures/wpt/resources/testharness.js +++ b/test/fixtures/wpt/resources/testharness.js @@ -494,7 +494,7 @@ ShellTestEnvironment.prototype.next_default_test_name = function() { var suffix = this.name_counter > 0 ? " " + this.name_counter : ""; this.name_counter++; - return "Untitled" + suffix; + return get_title() + suffix; }; ShellTestEnvironment.prototype.on_new_harness_properties = function() {}; @@ -2246,7 +2246,8 @@ ReadOnlyError: 0, VersionError: 0, OperationError: 0, - NotAllowedError: 0 + NotAllowedError: 0, + OptOutError: 0 }; var code_name_map = {}; @@ -2477,6 +2478,10 @@ this._user_defined_cleanup_count = 0; this._done_callbacks = []; + if (typeof AbortController === "function") { + this._abortController = new AbortController(); + } + // Tests declared following harness completion are likely an indication // of a programming error, but they cannot be reported // deterministically. @@ -2953,6 +2958,10 @@ this.phase = this.phases.CLEANING; + if (this._abortController) { + this._abortController.abort("Test cleanup"); + } + forEach(this.cleanup_callbacks, function(cleanup_callback) { var result; @@ -3046,6 +3055,16 @@ test._done_callbacks.length = 0; } + /** + * Gives an AbortSignal that will be aborted when the test finishes. + */ + Test.prototype.get_signal = function() { + if (!this._abortController) { + throw new Error("AbortController is not supported in this browser"); + } + return this._abortController.signal; + } + /** * A RemoteTest object mirrors a Test object on a remote worker. The * associated RemoteWorker updates the RemoteTest object in response to @@ -3822,7 +3841,9 @@ return; } - this.pending_remotes.push(this.create_remote_window(remote)); + var remoteContext = this.create_remote_window(remote); + this.pending_remotes.push(remoteContext); + return remoteContext.done; }; /** @@ -3837,7 +3858,7 @@ * @param {Window} window - The window to fetch tests from. */ function fetch_tests_from_window(window) { - tests.fetch_tests_from_window(window); + return tests.fetch_tests_from_window(window); } expose(fetch_tests_from_window, 'fetch_tests_from_window'); @@ -3871,7 +3892,7 @@ */ function begin_shadow_realm_tests(postMessage) { if (!(test_environment instanceof ShadowRealmTestEnvironment)) { - throw new Error("beign_shadow_realm_tests called in non-Shadow Realm environment"); + throw new Error("begin_shadow_realm_tests called in non-Shadow Realm environment"); } test_environment.begin(function (msg) { @@ -4733,7 +4754,7 @@ if ('META_TITLE' in global_scope && META_TITLE) { return META_TITLE; } - if ('location' in global_scope) { + if ('location' in global_scope && 'pathname' in location) { return location.pathname.substring(location.pathname.lastIndexOf('/') + 1, location.pathname.indexOf('.')); } return "Untitled"; diff --git a/test/fixtures/wpt/resources/webidl2/.gitignore b/test/fixtures/wpt/resources/webidl2/.gitignore deleted file mode 100644 index 1d72980cd7ea87..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -scratch -node_modules -lib-cov -browser-tests.html diff --git a/test/fixtures/wpt/resources/webidl2/.travis.yml b/test/fixtures/wpt/resources/webidl2/.travis.yml deleted file mode 100644 index 6dc8e2bdbaa6cf..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - node - - lts/* - - 6 diff --git a/test/fixtures/wpt/resources/webidl2/CHANGELOG.md b/test/fixtures/wpt/resources/webidl2/CHANGELOG.md deleted file mode 100644 index 91e22275e0700e..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/CHANGELOG.md +++ /dev/null @@ -1,292 +0,0 @@ -# Change Log - -## [v10.2.1](https://github.com/w3c/webidl2.js/tree/v10.2.1) (2018-03-09) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v10.2.0...v10.2.1) - -**Merged pull requests:** - -- Optimise tokenisation and whitespace skipping [\#139](https://github.com/w3c/webidl2.js/pull/139) ([ricea](https://github.com/ricea)) -- refactor: small syntax changes [\#137](https://github.com/w3c/webidl2.js/pull/137) ([saschanaz](https://github.com/saschanaz)) - -## [v10.2.0](https://github.com/w3c/webidl2.js/tree/v10.2.0) (2018-01-30) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v10.1.0...v10.2.0) - -**Merged pull requests:** - -- Type on union idlType [\#135](https://github.com/w3c/webidl2.js/pull/135) ([saschanaz](https://github.com/saschanaz)) -- feat: add argument/return type [\#134](https://github.com/w3c/webidl2.js/pull/134) ([saschanaz](https://github.com/saschanaz)) -- feat: add dictionary/typedef-type [\#133](https://github.com/w3c/webidl2.js/pull/133) ([saschanaz](https://github.com/saschanaz)) -- feat: add const-type for idlTypes [\#132](https://github.com/w3c/webidl2.js/pull/132) ([saschanaz](https://github.com/saschanaz)) -- feat: add types on idlTypes [\#131](https://github.com/w3c/webidl2.js/pull/131) ([saschanaz](https://github.com/saschanaz)) -- Auto acquisition for parser result changes [\#130](https://github.com/w3c/webidl2.js/pull/130) ([saschanaz](https://github.com/saschanaz)) - -## [v10.1.0](https://github.com/w3c/webidl2.js/tree/v10.1.0) (2018-01-19) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v10.0.0...v10.1.0) - -**Closed issues:** - -- Support `raises` and `setraises` [\#128](https://github.com/w3c/webidl2.js/issues/128) -- Support `legacycaller` [\#127](https://github.com/w3c/webidl2.js/issues/127) -- Improve "No semicolon after enum" message [\#119](https://github.com/w3c/webidl2.js/issues/119) - -**Merged pull requests:** - -- Let error messages include the current definition name [\#129](https://github.com/w3c/webidl2.js/pull/129) ([saschanaz](https://github.com/saschanaz)) - -## [v10.0.0](https://github.com/w3c/webidl2.js/tree/v10.0.0) (2017-12-20) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v9.0.0...v10.0.0) - -**Closed issues:** - -- Always return an array for idlType, etc. [\#113](https://github.com/w3c/webidl2.js/issues/113) -- Maintain writer.js or not? [\#109](https://github.com/w3c/webidl2.js/issues/109) - -**Merged pull requests:** - -- Remove typeExtAttrs from docs [\#124](https://github.com/w3c/webidl2.js/pull/124) ([saschanaz](https://github.com/saschanaz)) -- Remove iterator documentation [\#123](https://github.com/w3c/webidl2.js/pull/123) ([saschanaz](https://github.com/saschanaz)) -- Maintain writer.js [\#122](https://github.com/w3c/webidl2.js/pull/122) ([saschanaz](https://github.com/saschanaz)) -- BREAKING CHANGE: remove deprecated iterator operation [\#121](https://github.com/w3c/webidl2.js/pull/121) ([saschanaz](https://github.com/saschanaz)) -- Use for-of on tests [\#120](https://github.com/w3c/webidl2.js/pull/120) ([saschanaz](https://github.com/saschanaz)) -- docs\(README\): iterables ildType is always array [\#118](https://github.com/w3c/webidl2.js/pull/118) ([marcoscaceres](https://github.com/marcoscaceres)) - -## [v9.0.0](https://github.com/w3c/webidl2.js/tree/v9.0.0) (2017-11-30) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v8.1.0...v9.0.0) - -**Closed issues:** - -- Code quality [\#116](https://github.com/w3c/webidl2.js/issues/116) -- Unable to parse HTMLAllCollection interface [\#114](https://github.com/w3c/webidl2.js/issues/114) -- Add support for mixin syntax [\#112](https://github.com/w3c/webidl2.js/issues/112) -- Whitespace issues [\#111](https://github.com/w3c/webidl2.js/issues/111) - -**Merged pull requests:** - -- Consistent array type for iterable.idlType [\#117](https://github.com/w3c/webidl2.js/pull/117) ([saschanaz](https://github.com/saschanaz)) -- Revert "chore: drop Node 6 support \(\#102\)" [\#115](https://github.com/w3c/webidl2.js/pull/115) ([TimothyGu](https://github.com/TimothyGu)) - -## [v8.1.0](https://github.com/w3c/webidl2.js/tree/v8.1.0) (2017-11-03) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v8.0.1...v8.1.0) - -**Closed issues:** - -- Extended Attributes `rhs` should always be there [\#96](https://github.com/w3c/webidl2.js/issues/96) - -**Merged pull requests:** - -- Always add rhs property [\#110](https://github.com/w3c/webidl2.js/pull/110) ([saschanaz](https://github.com/saschanaz)) - -## [v8.0.1](https://github.com/w3c/webidl2.js/tree/v8.0.1) (2017-11-03) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v8.0.0...v8.0.1) - -**Fixed bugs:** - -- Comment order parsing bug [\#107](https://github.com/w3c/webidl2.js/issues/107) - -**Merged pull requests:** - -- Remove m postfix from all\_ws\(\) [\#108](https://github.com/w3c/webidl2.js/pull/108) ([saschanaz](https://github.com/saschanaz)) - -## [v8.0.0](https://github.com/w3c/webidl2.js/tree/v8.0.0) (2017-11-03) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v7.0.0...v8.0.0) - -**Closed issues:** - -- Remove creators support [\#100](https://github.com/w3c/webidl2.js/issues/100) -- Add mixin support [\#92](https://github.com/w3c/webidl2.js/issues/92) - -**Merged pull requests:** - -- Support mixins + includes statements [\#105](https://github.com/w3c/webidl2.js/pull/105) ([saschanaz](https://github.com/saschanaz)) -- chore: drop Node 6 support [\#102](https://github.com/w3c/webidl2.js/pull/102) ([marcoscaceres](https://github.com/marcoscaceres)) -- BREAKING CHANGE: drop creator support [\#101](https://github.com/w3c/webidl2.js/pull/101) ([saschanaz](https://github.com/saschanaz)) -- Normalize some whitespace to pass wpt's lint [\#99](https://github.com/w3c/webidl2.js/pull/99) ([foolip](https://github.com/foolip)) - -## [v7.0.0](https://github.com/w3c/webidl2.js/tree/v7.0.0) (2017-10-27) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v6.1.0...v7.0.0) - -**Closed issues:** - -- Type conversion on default values is destructive [\#94](https://github.com/w3c/webidl2.js/issues/94) -- extended attribute structure missing type [\#89](https://github.com/w3c/webidl2.js/issues/89) - -**Merged pull requests:** - -- BREAKING CHANGE: argument + default types should be string [\#95](https://github.com/w3c/webidl2.js/pull/95) ([marcoscaceres](https://github.com/marcoscaceres)) - -## [v6.1.0](https://github.com/w3c/webidl2.js/tree/v6.1.0) (2017-10-23) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v6.0.1...v6.1.0) - -**Merged pull requests:** - -- feat: give extended attributes a type [\#90](https://github.com/w3c/webidl2.js/pull/90) ([marcoscaceres](https://github.com/marcoscaceres)) - -## [v6.0.1](https://github.com/w3c/webidl2.js/tree/v6.0.1) (2017-10-18) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v6.0.0...v6.0.1) - -**Closed issues:** - -- Enum values should be objects [\#86](https://github.com/w3c/webidl2.js/issues/86) - -**Merged pull requests:** - -- Use ES2015 syntax for tests [\#88](https://github.com/w3c/webidl2.js/pull/88) ([saschanaz](https://github.com/saschanaz)) - -## [v6.0.0](https://github.com/w3c/webidl2.js/tree/v6.0.0) (2017-10-17) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v5.0.0...v6.0.0) - -**Merged pull requests:** - -- BREAKING CHANGE: ret enum value as object [\#87](https://github.com/w3c/webidl2.js/pull/87) ([marcoscaceres](https://github.com/marcoscaceres)) - -## [v5.0.0](https://github.com/w3c/webidl2.js/tree/v5.0.0) (2017-10-17) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v4.2.0...v5.0.0) - -**Closed issues:** - -- Unable to parse annotated types in generics [\#83](https://github.com/w3c/webidl2.js/issues/83) -- Drop support for Node 4, move to 6 LTS [\#82](https://github.com/w3c/webidl2.js/issues/82) - -**Merged pull requests:** - -- BREAKING CHANGE: Use ES2015 syntax [\#84](https://github.com/w3c/webidl2.js/pull/84) ([saschanaz](https://github.com/saschanaz)) - -## [v4.2.0](https://github.com/w3c/webidl2.js/tree/v4.2.0) (2017-10-16) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v4.1.0...v4.2.0) - -**Closed issues:** - -- Remove legacy caller support [\#78](https://github.com/w3c/webidl2.js/issues/78) -- Should report error for using duplicate names [\#77](https://github.com/w3c/webidl2.js/issues/77) - -**Merged pull requests:** - -- Check duplicated names [\#80](https://github.com/w3c/webidl2.js/pull/80) ([saschanaz](https://github.com/saschanaz)) -- Remove legacycaller [\#79](https://github.com/w3c/webidl2.js/pull/79) ([saschanaz](https://github.com/saschanaz)) -- Add "sequence" property to IDL Type AST definition [\#76](https://github.com/w3c/webidl2.js/pull/76) ([lerouche](https://github.com/lerouche)) - -## [v4.1.0](https://github.com/w3c/webidl2.js/tree/v4.1.0) (2017-07-04) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v4.0.0...v4.1.0) - -**Closed issues:** - -- Parsing error for annonated inner types of generic types [\#71](https://github.com/w3c/webidl2.js/issues/71) - -**Merged pull requests:** - -- Support TypeWithExtendedAttributes on generics [\#75](https://github.com/w3c/webidl2.js/pull/75) ([saschanaz](https://github.com/saschanaz)) - -## [v4.0.0](https://github.com/w3c/webidl2.js/tree/v4.0.0) (2017-06-27) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v3.0.2...v4.0.0) - -**Closed issues:** - -- Remove serializer-related productions [\#73](https://github.com/w3c/webidl2.js/issues/73) -- Records don't seem to be working right [\#72](https://github.com/w3c/webidl2.js/issues/72) -- Document namespace member output [\#59](https://github.com/w3c/webidl2.js/issues/59) - -**Merged pull requests:** - -- BREAKING CHANGE: remove serializers \(closes \#73\) [\#74](https://github.com/w3c/webidl2.js/pull/74) ([marcoscaceres](https://github.com/marcoscaceres)) -- Add documentation for namespaces [\#70](https://github.com/w3c/webidl2.js/pull/70) ([saschanaz](https://github.com/saschanaz)) - -## [v3.0.2](https://github.com/w3c/webidl2.js/tree/v3.0.2) (2017-05-29) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v3.0.1...v3.0.2) - -**Closed issues:** - -- Whitespace issues [\#64](https://github.com/w3c/webidl2.js/issues/64) - -**Merged pull requests:** - -- Test for latest LTS/stable node versions [\#69](https://github.com/w3c/webidl2.js/pull/69) ([saschanaz](https://github.com/saschanaz)) - -## [v3.0.1](https://github.com/w3c/webidl2.js/tree/v3.0.1) (2017-05-18) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v2.4.0...v3.0.1) - -**Closed issues:** - -- Is array syntax dead? [\#66](https://github.com/w3c/webidl2.js/issues/66) -- Remove exceptions support [\#65](https://github.com/w3c/webidl2.js/issues/65) - -**Merged pull requests:** - -- Fix whitespace error on parsing extended attributes [\#68](https://github.com/w3c/webidl2.js/pull/68) ([saschanaz](https://github.com/saschanaz)) -- Remove deprecated IDL arrays and exceptions [\#67](https://github.com/w3c/webidl2.js/pull/67) ([saschanaz](https://github.com/saschanaz)) - -## [v2.4.0](https://github.com/w3c/webidl2.js/tree/v2.4.0) (2017-04-12) -[Full Changelog](https://github.com/w3c/webidl2.js/compare/v2.1.0...v2.4.0) - -**Closed issues:** - -- Add support for Annotated Types [\#60](https://github.com/w3c/webidl2.js/issues/60) -- Question: Convert WebIDL -\> Javascript [\#56](https://github.com/w3c/webidl2.js/issues/56) -- Get Robin to give us push permissions on npm [\#54](https://github.com/w3c/webidl2.js/issues/54) -- Add support for records [\#53](https://github.com/w3c/webidl2.js/issues/53) -- module not supported? [\#52](https://github.com/w3c/webidl2.js/issues/52) -- Add support for namespaces [\#51](https://github.com/w3c/webidl2.js/issues/51) -- Export is not AMD compatible [\#48](https://github.com/w3c/webidl2.js/issues/48) -- Can't represent large constants [\#21](https://github.com/w3c/webidl2.js/issues/21) - -**Merged pull requests:** - -- Update webidl2.js [\#63](https://github.com/w3c/webidl2.js/pull/63) ([tqeto](https://github.com/tqeto)) -- Remove support for MapClass \(no longer valid in WebIDL\) [\#62](https://github.com/w3c/webidl2.js/pull/62) ([dontcallmedom](https://github.com/dontcallmedom)) -- Add support for annotated types [\#61](https://github.com/w3c/webidl2.js/pull/61) ([dontcallmedom](https://github.com/dontcallmedom)) -- Support namespaces [\#58](https://github.com/w3c/webidl2.js/pull/58) ([saschanaz](https://github.com/saschanaz)) -- Add support for records [\#57](https://github.com/w3c/webidl2.js/pull/57) ([TimothyGu](https://github.com/TimothyGu)) -- Refactor [\#50](https://github.com/w3c/webidl2.js/pull/50) ([marcoscaceres](https://github.com/marcoscaceres)) -- feat\(lib\): add AMD export support \(closes \#48\) [\#49](https://github.com/w3c/webidl2.js/pull/49) ([marcoscaceres](https://github.com/marcoscaceres)) - -## [v2.1.0](https://github.com/w3c/webidl2.js/tree/v2.1.0) (2016-08-12) -**Closed issues:** - -- Exception when parsing test/syntax/idl/typedef.widl [\#46](https://github.com/w3c/webidl2.js/issues/46) -- Wrong jsondiffpatch location [\#42](https://github.com/w3c/webidl2.js/issues/42) -- 'npm install' fails on building microtime [\#40](https://github.com/w3c/webidl2.js/issues/40) -- Can't represent union types in typedefs [\#38](https://github.com/w3c/webidl2.js/issues/38) -- tokenise\(\) assumes a specific property enumeration order [\#27](https://github.com/w3c/webidl2.js/issues/27) -- Add support for iterable\<\>, maplike\<\>, setlike\<\> declarations [\#24](https://github.com/w3c/webidl2.js/issues/24) -- WebIDL2 fails to parse `attribute Promise\\[\] baz` [\#19](https://github.com/w3c/webidl2.js/issues/19) -- Support for ExtendedAttributeIdentList \(current editor's draft\) [\#18](https://github.com/w3c/webidl2.js/issues/18) -- No Licensing Information [\#17](https://github.com/w3c/webidl2.js/issues/17) -- how to regenerate w3c idl files ? [\#14](https://github.com/w3c/webidl2.js/issues/14) -- What is lib/writer.js [\#13](https://github.com/w3c/webidl2.js/issues/13) -- Numerous tests are failing [\#7](https://github.com/w3c/webidl2.js/issues/7) -- Add support for missing types in ServiceWorker [\#5](https://github.com/w3c/webidl2.js/issues/5) -- How can I parse just a function? [\#3](https://github.com/w3c/webidl2.js/issues/3) -- Parser throws on nullable array of nullable array [\#2](https://github.com/w3c/webidl2.js/issues/2) -- Parser throws on nullable array of any [\#1](https://github.com/w3c/webidl2.js/issues/1) - -**Merged pull requests:** - -- Fix "default": undefined [\#47](https://github.com/w3c/webidl2.js/pull/47) ([mkwtys](https://github.com/mkwtys)) -- Replace expect.js with expct [\#45](https://github.com/w3c/webidl2.js/pull/45) ([halton](https://github.com/halton)) -- Correct jsondiffpatch location. [\#44](https://github.com/w3c/webidl2.js/pull/44) ([halton](https://github.com/halton)) -- Bump microtime to 2.1.1 [\#43](https://github.com/w3c/webidl2.js/pull/43) ([halton](https://github.com/halton)) -- Expand writer support [\#39](https://github.com/w3c/webidl2.js/pull/39) ([markandrus](https://github.com/markandrus)) -- Accept wider \(but still incomplete\) set of allowed syntax for extended attributes [\#37](https://github.com/w3c/webidl2.js/pull/37) ([mlogan](https://github.com/mlogan)) -- Add test for callback with multiple arguments. [\#36](https://github.com/w3c/webidl2.js/pull/36) ([tobie](https://github.com/tobie)) -- Iterables [\#34](https://github.com/w3c/webidl2.js/pull/34) ([motiz88](https://github.com/motiz88)) -- Allow trailing comma in enum value lists, per spec [\#33](https://github.com/w3c/webidl2.js/pull/33) ([motiz88](https://github.com/motiz88)) -- Allow typedefs within interfaces \(behind an opt-in flag\) [\#32](https://github.com/w3c/webidl2.js/pull/32) ([motiz88](https://github.com/motiz88)) -- In draft [\#31](https://github.com/w3c/webidl2.js/pull/31) ([othree](https://github.com/othree)) -- Add support for extended attributes identifier lists [\#29](https://github.com/w3c/webidl2.js/pull/29) ([tobie](https://github.com/tobie)) -- Make `attribute Promise\\[\] attr;` work. [\#26](https://github.com/w3c/webidl2.js/pull/26) ([jyasskin](https://github.com/jyasskin)) -- Parse required dictionary fields. [\#25](https://github.com/w3c/webidl2.js/pull/25) ([jyasskin](https://github.com/jyasskin)) -- Define the WebIDL2 property on self rather than window. [\#23](https://github.com/w3c/webidl2.js/pull/23) ([Ms2ger](https://github.com/Ms2ger)) -- Teach WebIDL2 to parse \[\] default values. [\#22](https://github.com/w3c/webidl2.js/pull/22) ([jyasskin](https://github.com/jyasskin)) -- Support ID list in extended attributes [\#20](https://github.com/w3c/webidl2.js/pull/20) ([othree](https://github.com/othree)) -- Make sure that `sequence` property of idl types is set to false if the type is actually `sequence`. [\#16](https://github.com/w3c/webidl2.js/pull/16) ([tobie](https://github.com/tobie)) -- Parametrized [\#15](https://github.com/w3c/webidl2.js/pull/15) ([tobie](https://github.com/tobie)) -- Add promise support [\#12](https://github.com/w3c/webidl2.js/pull/12) ([tobie](https://github.com/tobie)) -- Remove broken coverage support from travis for now. [\#11](https://github.com/w3c/webidl2.js/pull/11) ([tobie](https://github.com/tobie)) -- Add support for \[MapClass\(type, type\)\]. [\#10](https://github.com/w3c/webidl2.js/pull/10) ([tobie](https://github.com/tobie)) -- Incorporate tests from widlproc\[1\] and remove dependency on said project. [\#9](https://github.com/w3c/webidl2.js/pull/9) ([tobie](https://github.com/tobie)) -- README incorrectly recommended updating the widlproc submodule. [\#8](https://github.com/w3c/webidl2.js/pull/8) ([tobie](https://github.com/tobie)) -- Fix bug where instrumented version of webidl2 was loaded. [\#6](https://github.com/w3c/webidl2.js/pull/6) ([tobie](https://github.com/tobie)) -- Use https:// instead of git:// [\#4](https://github.com/w3c/webidl2.js/pull/4) ([Manishearth](https://github.com/Manishearth)) - - - -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/test/fixtures/wpt/resources/webidl2/LICENSE b/test/fixtures/wpt/resources/webidl2/LICENSE deleted file mode 100644 index fd21d439b09a8d..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Robin Berjon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/test/fixtures/wpt/resources/webidl2/README.md b/test/fixtures/wpt/resources/webidl2/README.md deleted file mode 100644 index 9a8f3f8e9c1dfb..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/README.md +++ /dev/null @@ -1,629 +0,0 @@ - -# WebIDL 2 - -[![NPM version](https://badge.fury.io/js/webidl2.svg)](http://badge.fury.io/js/webidl2) - -## Purpose - -This is a parser for the [WebIDL](http://dev.w3.org/2006/webapi/WebIDL/) language. If -you don't know what that is, then you probably don't need it. It is meant to be used -both in Node and in the browser (the parser likely works in other JS environments, but -not the test suite). - -## Installation - -Just the usual. For Node: - -```Bash -npm install webidl2 -``` - -In the browser: - -```HTML - -``` - -## Documentation - -The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree. - -### Parsing - -In Node, that happens with: - -```JS -var WebIDL2 = require("webidl2"); -var tree = WebIDL2.parse("string of WebIDL"); -``` - -In the browser: -```HTML - - -``` - -### Errors - -When there is a syntax error in the WebIDL, it throws an exception object with the following -properties: - -* `message`: the error message -* `line`: the line at which the error occurred. -* `input`: a short peek at the text at the point where the error happened -* `tokens`: the five tokens at the point of error, as understood by the tokeniser - (this is the same content as `input`, but seen from the tokeniser's point of view) - -The exception also has a `toString()` method that hopefully should produce a decent -error message. - -### AST (Abstract Syntax Tree) - -The `parse()` method returns a tree object representing the parse tree of the IDL. -Comment and white space are not represented in the AST. - -The root of this object is always an array of definitions (where definitions are -any of interfaces, dictionaries, callbacks, etc. โ€” anything that can occur at the root -of the IDL). - -### IDL Type - -This structure is used in many other places (operation return types, argument types, etc.). -It captures a WebIDL type with a number of options. Types look like this and are typically -attached to a field called `idlType`: - -```JS -{ - "type": "attribute-type", - "generic": null, - "idlType": "unsigned short", - "nullable": false, - "union": false, - "extAttrs": [...] -} -``` - -Where the fields are as follows: - -* `type`: String indicating where this type is used. Can be `null` if not applicable. -* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null` - otherwise. -* `idlType`: Can be different things depending on context. In most cases, this will just - be a string with the type name. But the reason this field isn't called "typeName" is - because it can take more complex values. If the type is a union, then this contains an - array of the types it unites. If it is a generic type, it contains the IDL type - description for the type in the sequence, the eventual value of the promise, etc. -* `nullable`: Boolean indicating whether this is nullable or not. -* `union`: Boolean indicating whether this is a union type or not. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Interface - -Interfaces look like this: - -```JS -{ - "type": "interface", - "name": "Animal", - "partial": false, - "members": [...], - "inheritance": null, - "extAttrs": [...] -}, { - "type": "interface", - "name": "Human", - "partial": false, - "members": [...], - "inheritance": "Animal", - "extAttrs": [...] -} -``` - -The fields are as follows: - -* `type`: Always "interface". -* `name`: The name of the interface. -* `partial`: A boolean indicating whether it's a partial interface. -* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. -* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise. - **NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make - sense. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Interface mixins - -Interfaces mixins look like this: - -```JS -{ - "type": "interface mixin", - "name": "Animal", - "partial": false, - "members": [...], - "extAttrs": [...] -}, { - "type": "interface mixin", - "name": "Human", - "partial": false, - "members": [...], - "extAttrs": [...] -} -``` - -The fields are as follows: - -* `type`: Always "interface mixin". -* `name`: The name of the interface mixin. -* `partial`: A boolean indicating whether it's a partial interface mixin. -* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Namespace - -Namespaces look like this: - -```JS -{ - "type": "namespace", - "name": "Console", - "partial": false, - "members": [...], - "extAttrs": [...] -} -``` - -The fields are as follows: - -* `type`: Always "namespace". -* `name`: The name of the namespace. -* `partial`: A boolean indicating whether it's a partial namespace. -* `members`: An array of namespace members (attributes and operations). Empty if there are none. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Callback Interfaces - -These are captured by the same structure as [Interfaces](#interface) except that -their `type` field is "callback interface". - -### Callback - -A callback looks like this: - -```JS -{ - "type": "callback", - "name": "AsyncOperationCallback", - "idlType": { - "type": "return-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "void", - "extAttrs": [] - }, - "arguments": [...], - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "callback". -* `name`: The name of the callback. -* `idlType`: An [IDL Type](#idl-type) describing what the callback returns. -* `arguments`: A list of [arguments](#arguments), as in function paramters. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Dictionary - -A dictionary looks like this: - -```JS -{ - "type": "dictionary", - "name": "PaintOptions", - "partial": false, - "members": [{ - "type": "field", - "name": "fillPattern", - "required": false, - "idlType": { - "type": "dictionary-type", - "sequence": false, - "generic": null, - "nullable": true, - "union": false, - "idlType": "DOMString", - "extAttrs": [...] - }, - "extAttrs": [], - "default": { - "type": "string", - "value": "black" - } - }], - "inheritance": null, - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "dictionary". -* `name`: The dictionary name. -* `partial`: Boolean indicating whether it's a partial dictionary. -* `members`: An array of members (see below). -* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -All the members are fields as follows: - -* `type`: Always "field". -* `name`: The name of the field. -* `required`: Boolean indicating whether this is a [required](https://heycam.github.io/webidl/#required-dictionary-member) field. -* `idlType`: An [IDL Type](#idl-type) describing what field's type. -* `extAttrs`: A list of [extended attributes](#extended-attributes). -* `default`: A [default value](#default-and-const-values), absent if there is none. - -### Enum - -An enum looks like this: - -```JS -{ - "type": "enum", - "name": "MealType", - "values": [ - { "type": "string", "value": "rice" }, - { "type": "string", "value": "noodles" }, - { "type": "string", "value": "other" } - ], - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "enum". -* `name`: The enum's name. -* `values`: An array of values. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Typedef - -A typedef looks like this: - -```JS -{ - "type": "typedef", - "idlType": { - "type": "typedef-type", - "sequence": true, - "generic": "sequence", - "nullable": false, - "union": false, - "idlType": { - "type": "typedef-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "Point", - "extAttrs": [...] - }, - "extAttrs": [...] - }, - "name": "PointSequence", - "extAttrs": [] -} -``` - - -The fields are as follows: - -* `type`: Always "typedef". -* `name`: The typedef's name. -* `idlType`: An [IDL Type](#idl-type) describing what typedef's type. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Implements - -An implements definition looks like this: - -```JS -{ - "type": "implements", - "target": "Node", - "implements": "EventTarget", - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "implements". -* `target`: The interface that implements another. -* `implements`: The interface that is being implemented by the target. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Includes - -An includes definition looks like this: - -```JS -{ - "type": "includes", - "target": "Node", - "includes": "EventTarget", - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "includes". -* `target`: The interface that includes an interface mixin. -* `includes`: The interface mixin that is being included by the target. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Operation Member - -An operation looks like this: -```JS -{ - "type": "operation", - "getter": false, - "setter": false, - "deleter": false, - "static": false, - "stringifier": false, - "idlType": { - "type": "return-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "void", - "extAttrs": [] - }, - "name": "intersection", - "arguments": [{ - "optional": false, - "variadic": true, - "extAttrs": [], - "idlType": { - "type": "argument-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "long", - "extAttrs": [...] - }, - "name": "ints" - }], - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "operation". -* `getter`: True if a getter operation. -* `setter`: True if a setter operation. -* `deleter`: True if a deleter operation. -* `static`: True if a static operation. -* `stringifier`: True if a stringifier operation. -* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent. -* `name`: The name of the operation. If a stringifier, may be `null`. -* `arguments`: An array of [arguments](#arguments) for the operation. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Attribute Member - -An attribute member looks like this: - -```JS -{ - "type": "attribute", - "static": false, - "stringifier": false, - "inherit": false, - "readonly": false, - "idlType": { - "type": "attribute-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "RegExp", - "extAttrs": [...] - }, - "name": "regexp", - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "attribute". -* `name`: The attribute's name. -* `static`: True if it's a static attribute. -* `stringifier`: True if it's a stringifier attribute. -* `inherit`: True if it's an inherit attribute. -* `readonly`: True if it's a read-only attribute. -* `idlType`: An [IDL Type](#idl-type) for the attribute. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Constant Member - -A constant member looks like this: - -```JS -{ - "type": "const", - "nullable": false, - "idlType": { - "type": "const-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "boolean" - "extAttrs": [] - }, - "name": "DEBUG", - "value": { - "type": "boolean", - "value": false - }, - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always "const". -* `nullable`: Whether its type is nullable. -* `idlType`: An [IDL Type](#idl-type) of the constant that represents a simple type, the type name. -* `name`: The name of the constant. -* `value`: The constant value as described by [Const Values](#default-and-const-values) -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Arguments - -The arguments (e.g. for an operation) look like this: - -```JS -{ - "arguments": [{ - "optional": false, - "variadic": true, - "extAttrs": [], - "idlType": { - "type": "argument-type", - "sequence": false, - "generic": null, - "nullable": false, - "union": false, - "idlType": "long", - "extAttrs": [...] - }, - "name": "ints" - }] -} -``` - -The fields are as follows: - -* `optional`: True if the argument is optional. -* `variadic`: True if the argument is variadic. -* `idlType`: An [IDL Type](#idl-type) describing the type of the argument. -* `name`: The argument's name. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - -### Extended Attributes - -Extended attributes are arrays of items that look like this: - -```JS -{ - "extAttrs": [{ - "name": "TreatNullAs", - "arguments": null, - "type": "extended-attribute", - "rhs": { - "type": "identifier", - "value": "EmptyString" - } - }] -} -``` - -The fields are as follows: - -* `name`: The extended attribute's name. -* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if - its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they - are listed here. Note that an empty arguments list will produce an empty array, - whereas the lack thereof will yield a `null`. If there is an `rhs` field then - they are the right-hand side's arguments, otherwise they apply to the extended - attribute directly. -* `type`: Always `"extended-attribute"`. -* `rhs`: If there is a right-hand side, this will capture its `type` (which can be - "identifier" or "identifier-list") and its `value`. - -### Default and Const Values - -Dictionary fields and operation arguments can take default values, and constants take -values, all of which have the following fields: - -* `type`: One of string, number, boolean, null, Infinity, NaN, or sequence. - -For string, number, boolean, and sequence: - -* `value`: The value of the given type, as a string. For sequence, the only possible value is `[]`. - -For Infinity: - -* `negative`: Boolean indicating whether this is negative Infinity or not. - -### `iterable<>`, `legacyiterable<>`, `maplike<>`, `setlike<>` declarations - -These appear as members of interfaces that look like this: - -```JS -{ - "type": "maplike", // or "legacyiterable" / "iterable" / "setlike" - "idlType": /* One or two types */ , - "readonly": false, // only for maplike and setlike - "extAttrs": [] -} -``` - -The fields are as follows: - -* `type`: Always one of "iterable", "legacyiterable", "maplike" or "setlike". -* `idlType`: An array with one or more [IDL Types](#idl-type) representing the declared type arguments. -* `readonly`: Whether the maplike or setlike is declared as read only. -* `extAttrs`: A list of [extended attributes](#extended-attributes). - - -## Testing - -### Running - -The test runs with mocha and expect.js. Normally, running mocha in the root directory -should be enough once you're set up. - -### Coverage - -Current test coverage, as documented in `coverage.html`, is 95%. You can run your own -coverage analysis with: - -```Bash -jscoverage lib lib-cov -``` - -That will create the lib-cov directory with instrumented code; the test suite knows -to use that if needed. You can then run the tests with: - -```Bash -JSCOV=1 mocha --reporter html-cov > coverage.html -``` - -Note that I've been getting weirdly overescaped results from the html-cov reporter, -so you might wish to try this instead: - -```Bash -JSCOV=1 mocha --reporter html-cov | sed "s/<//g" | sed "s/"/\"/g" > coverage.html -``` -### Browser tests - -In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This -will generate a `browser-tests.html` file that you can open in a browser. As of this -writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE -and older versions will happen progressively. diff --git a/test/fixtures/wpt/resources/webidl2/checker/index.html b/test/fixtures/wpt/resources/webidl2/checker/index.html deleted file mode 100644 index 9897d8572f22a0..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/checker/index.html +++ /dev/null @@ -1,55 +0,0 @@ - - - -WebIDL 2 Checker - - - - - - -

WebIDL Checker

-

This is an online checker for WebIDL built on the webidl2.js project.

-

Enter your WebIDL to check below:

- -
- -

Validation results:

- -

Parser output:

- -
-Pretty Print - - diff --git a/test/fixtures/wpt/resources/webidl2/coverage.html b/test/fixtures/wpt/resources/webidl2/coverage.html deleted file mode 100644 index 46e7ed324ec2c8..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/coverage.html +++ /dev/null @@ -1,341 +0,0 @@ -Coverage -

Coverage

95%
572
548
24

webidl2.js

95%
572
548
24
LineHitsSource
1
2
31(function () {
41 var tokenise = function (str) {
547 var tokens = []
6 , re = {
7 "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
8 , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
9 , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/
10 , "string": /^"[^"]*"/
11 , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
12 , "other": /^[^\t\n\r 0-9A-Z_a-z]/
13 }
14 , types = []
15 ;
16329 for (var k in re) types.push(k);
1747 while (str.length > 0) {
182914 var matched = false;
192914 for (var i = 0, n = types.length; i < n; i++) {
2013325 var type = types[i];
2113325 str = str.replace(re[type], function (tok) {
222914 tokens.push({ type: type, value: tok });
232914 matched = true;
242914 return "";
25 });
2616239 if (matched) break;
27 }
285828 if (matched) continue;
290 throw new Error("Token stream not progressing");
30 }
3147 return tokens;
32 };
33
341 var parse = function (tokens) {
3547 var line = 1;
3647 tokens = tokens.slice();
37
3847 var FLOAT = "float"
39 , INT = "integer"
40 , ID = "identifier"
41 , STR = "string"
42 , OTHER = "other"
43 ;
44
4547 var WebIDLParseError = function (str, line, input, tokens) {
460 this.message = str;
470 this.line = line;
480 this.input = input;
490 this.tokens = tokens;
50 };
5147 WebIDLParseError.prototype.toString = function () {
520 return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" +
53 JSON.stringify(this.tokens, null, 4);
54 };
55
5647 var error = function (str) {
570 var tok = "", numTokens = 0, maxTokens = 5;
580 while (numTokens < maxTokens && tokens.length > numTokens) {
590 tok += tokens[numTokens].value;
600 numTokens++;
61 }
620 throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5));
63 };
64
6547 var last_token = null;
66
6747 var consume = function (type, value) {
688778 if (!tokens.length || tokens[0].type !== type) return;
695470 if (typeof value === "undefined" || tokens[0].value === value) {
701738 last_token = tokens.shift();
711738 return last_token;
72 }
73 };
74
7547 var ws = function () {
766961 if (!tokens.length) return;
77 // console.log("tokens.length", tokens.length, tokens[0]);
786115 if (tokens[0].type === "whitespace") {
791172 var t = tokens.shift();
802294 t.value.replace(/\n/g, function (m) { line++; return m; });
811172 return t;
82 }
83 };
84
8547 var all_ws = function () {
865366 var t = { type: "whitespace", value: "" };
875366 while (true) {
886538 var w = ws();
8911904 if (!w) break;
901172 t.value += w.value;
91 }
926538 if (t.value.length > 0) return t;
93 };
94
9547 var integer_type = function () {
96273 var ret = "";
97273 all_ws();
98312 if (consume(ID, "unsigned")) ret = "unsigned ";
99273 all_ws();
100287 if (consume(ID, "short")) return ret + "short";
101259 if (consume(ID, "long")) {
10241 ret += "long";
10341 all_ws();
10443 if (consume(ID, "long")) return ret + " long";
10539 return ret;
106 }
107218 if (ret) error("Failed to parse integer type");
108 };
109
11047 var float_type = function () {
111218 var ret = "";
112218 all_ws();
113222 if (consume(ID, "unrestricted")) ret = "unrestricted ";
114218 all_ws();
115257 if (consume(ID, "float")) return ret + "float";
116182 if (consume(ID, "double")) return ret + "double";
117176 if (ret) error("Failed to parse float type");
118 };
119
12047 var primitive_type = function () {
121273 var num_type = integer_type() || float_type();
122370 if (num_type) return num_type;
123176 all_ws();
124186 if (consume(ID, "boolean")) return "boolean";
125167 if (consume(ID, "byte")) return "byte";
126168 if (consume(ID, "octet")) return "octet";
127 };
128
12947 var const_value = function () {
13017 if (consume(ID, "true")) return true;
13119 if (consume(ID, "false")) return false;
13217 if (consume(ID, "null")) return null;
13314 if (consume(ID, "Infinity")) return Infinity;
13413 if (consume(ID, "NaN")) return NaN;
13511 var ret = consume(FLOAT) || consume(INT);
13619 if (ret) return 1 * ret.value;
1373 var tok = consume(OTHER, "-");
1383 if (tok) {
1392 if (consume(ID, "Infinity")) return -Infinity;
1400 else tokens.unshift(tok);
141 }
142 };
143
14447 var type_suffix = function (obj) {
145249 while (true) {
146263 all_ws();
147263 if (consume(OTHER, "?")) {
14811 if (obj.nullable) error("Can't nullable more than once");
14911 obj.nullable = true;
150 }
151252 else if (consume(OTHER, "[")) {
1523 all_ws();
1533 consume(OTHER, "]") || error("Unterminated array type");
1545 if (!obj.array) obj.array = 1;
1551 else obj.array++;
156 }
157249 else return;
158 }
159 };
160
16147 var single_type = function () {
162261 var prim = primitive_type()
163 , ret = { sequence: false, nullable: false, array: false, union: false }
164 ;
165261 if (prim) {
16699 ret.idlType = prim;
167 }
168162 else if (consume(ID, "sequence")) {
1694 all_ws();
1704 if (!consume(OTHER, "<")) {
1710 ret.idlType = "sequence";
172 }
173 else {
1744 ret.sequence = true;
1754 ret.idlType = type() || error("Error parsing sequence type");
1764 all_ws();
1774 if (!consume(OTHER, ">")) error("Unterminated sequence");
1784 all_ws();
1795 if (consume(OTHER, "?")) ret.nullable = true;
1804 return ret;
181 }
182 }
183 else {
184158 var name = consume(ID);
185169 if (!name) return;
186147 ret.idlType = name.value;
187 }
188246 type_suffix(ret);
189246 if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
190246 return ret;
191 };
192
19347 var union_type = function () {
19411 all_ws();
19519 if (!consume(OTHER, "(")) return;
1963 var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] };
1973 var fst = type() || error("Union type with no content");
1983 ret.idlType.push(fst);
1993 while (true) {
2007 all_ws();
20110 if (!consume(ID, "or")) break;
2024 var typ = type() || error("No type after 'or' in union type");
2034 ret.idlType.push(typ);
204 }
2053 if (!consume(OTHER, ")")) error("Unterminated union type");
2063 type_suffix(ret);
2073 return ret;
208 };
209
21047 var type = function () {
211261 return single_type() || union_type();
212 };
213
21447 var argument = function () {
21579 var ret = { optional: false, variadic: false };
21679 ret.extAttrs = extended_attrs();
21779 all_ws();
21879 if (consume(ID, "optional")) {
2192 ret.optional = true;
2202 all_ws();
221 }
22279 ret.type = type();
22387 if (!ret.type) return;
22471 if (!ret.optional) {
22569 all_ws();
22669 if (tokens.length >= 3 &&
227 tokens[0].type === "other" && tokens[0].value === "." &&
228 tokens[1].type === "other" && tokens[1].value === "." &&
229 tokens[2].type === "other" && tokens[2].value === "."
230 ) {
2314 tokens.shift();
2324 tokens.shift();
2334 tokens.shift();
2344 ret.variadic = true;
235 }
236 }
23771 all_ws();
23871 var name = consume(ID) || error("No name in argument");
23971 ret.name = name.value;
24071 if (ret.optional) {
2412 all_ws();
2422 ret["default"] = default_();
243 }
24471 return ret;
245 };
246
24747 var argument_list = function () {
24859 var arg = argument(), ret = [];
24967 if (!arg) return ret;
25051 ret.push(arg);
25151 while (true) {
25271 all_ws();
253122 if (!consume(OTHER, ",")) return ret;
25420 all_ws();
25520 var nxt = argument() || error("Trailing comma in arguments list");
25620 ret.push(nxt);
257 }
258 };
259
26047 var simple_extended_attr = function () {
26117 all_ws();
26217 var name = consume(ID);
26317 if (!name) return;
26417 var ret = {
265 name: name.value
266 , "arguments": null
267 };
26817 all_ws();
26917 var eq = consume(OTHER, "=");
27017 if (eq) {
2715 all_ws();
2725 ret.rhs = consume(ID);
2735 if (!ret.rhs) return error("No right hand side to extended attribute assignment");
274 }
27517 all_ws();
27617 if (consume(OTHER, "(")) {
2772 ret["arguments"] = argument_list();
2782 all_ws();
2792 consume(OTHER, ")") || error("Unclosed argument in extended attribute");
280 }
28117 return ret;
282 };
283
284 // Note: we parse something simpler than the official syntax. It's all that ever
285 // seems to be used
28647 var extended_attrs = function () {
287415 var eas = [];
288415 all_ws();
289815 if (!consume(OTHER, "[")) return eas;
29015 eas[0] = simple_extended_attr() || error("Extended attribute with not content");
29115 all_ws();
29215 while (consume(OTHER, ",")) {
2932 all_ws();
2942 eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
2952 all_ws();
296 }
29715 consume(OTHER, "]") || error("No end of extended attribute");
29815 return eas;
299 };
300
30147 var default_ = function () {
30211 all_ws();
30311 if (consume(OTHER, "=")) {
3045 all_ws();
3055 var def = const_value();
3065 if (typeof def !== "undefined") {
3073 return def;
308 }
309 else {
3102 var str = consume(STR) || error("No value for default");
3112 return str;
312 }
313 }
314 };
315
31647 var const_ = function () {
317180 all_ws();
318348 if (!consume(ID, "const")) return;
31912 var ret = { type: "const", nullable: false };
32012 all_ws();
32112 var typ = primitive_type();
32212 if (!typ) {
3230 typ = consume(ID) || error("No type for const");
3240 typ = typ.value;
325 }
32612 ret.idlType = typ;
32712 all_ws();
32812 if (consume(OTHER, "?")) {
3291 ret.nullable = true;
3301 all_ws();
331 }
33212 var name = consume(ID) || error("No name for const");
33312 ret.name = name.value;
33412 all_ws();
33512 consume(OTHER, "=") || error("No value assignment for const");
33612 all_ws();
33712 var cnt = const_value();
33824 if (typeof cnt !== "undefined") ret.value = cnt;
3390 else error("No value for const");
34012 all_ws();
34112 consume(OTHER, ";") || error("Unterminated const");
34212 return ret;
343 };
344
34547 var inheritance = function () {
34689 all_ws();
34789 if (consume(OTHER, ":")) {
3489 all_ws();
3499 var inh = consume(ID) || error ("No type in inheritance");
3509 return inh.value;
351 }
352 };
353
35447 var operation_rest = function (ret) {
35556 all_ws();
35657 if (!ret) ret = {};
35756 var name = consume(ID);
35856 ret.name = name ? name.value : null;
35956 all_ws();
36056 consume(OTHER, "(") || error("Invalid operation");
36156 ret["arguments"] = argument_list();
36256 all_ws();
36356 consume(OTHER, ")") || error("Unterminated operation");
36456 all_ws();
36556 consume(OTHER, ";") || error("Unterminated operation");
36656 return ret;
367 };
368
36947 var callback = function () {
370144 all_ws();
371144 var ret;
372286 if (!consume(ID, "callback")) return;
3732 all_ws();
3742 var tok = consume(ID, "interface");
3752 if (tok) {
3761 tokens.unshift(tok);
3771 ret = interface_();
3781 ret.type = "callback interface";
3791 return ret;
380 }
3811 var name = consume(ID) || error("No name for callback");
3821 ret = { type: "callback", name: name.value };
3831 all_ws();
3841 consume(OTHER, "=") || error("No assignment in callback");
3851 all_ws();
3861 ret.idlType = return_type();
3871 all_ws();
3881 consume(OTHER, "(") || error("No arguments in callback");
3891 ret["arguments"] = argument_list();
3901 all_ws();
3911 consume(OTHER, ")") || error("Unterminated callback");
3921 all_ws();
3931 consume(OTHER, ";") || error("Unterminated callback");
3941 return ret;
395 };
396
39747 var attribute = function () {
398154 all_ws();
399154 var grabbed = []
400 , ret = {
401 type: "attribute"
402 , "static": false
403 , stringifier: false
404 , inherit: false
405 , readonly: false
406 };
407154 if (consume(ID, "static")) {
4082 ret["static"] = true;
4092 grabbed.push(last_token);
410 }
411152 else if (consume(ID, "stringifier")) {
4124 ret.stringifier = true;
4134 grabbed.push(last_token);
414 }
415154 var w = all_ws();
416159 if (w) grabbed.push(w);
417154 if (consume(ID, "inherit")) {
4181 if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
4191 ret.inherit = true;
4201 grabbed.push(last_token);
4211 var w = all_ws();
4222 if (w) grabbed.push(w);
423 }
424154 if (consume(ID, "readonly")) {
42532 ret.readonly = true;
42632 grabbed.push(last_token);
42732 var w = all_ws();
42864 if (w) grabbed.push(w);
429 }
430154 if (!consume(ID, "attribute")) {
43160 tokens = grabbed.concat(tokens);
43260 return;
433 }
43494 all_ws();
43594 ret.idlType = type() || error("No type in attribute");
43694 if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
43794 all_ws();
43894 var name = consume(ID) || error("No name in attribute");
43994 ret.name = name.value;
44094 all_ws();
44194 consume(OTHER, ";") || error("Unterminated attribute");
44294 return ret;
443 };
444
44547 var return_type = function () {
44661 var typ = type();
44761 if (!typ) {
4480 if (consume(ID, "void")) {
4490 return "void";
450 }
4510 else error("No return type");
452 }
45361 return typ;
454 };
455
45647 var operation = function () {
45760 all_ws();
45860 var ret = {
459 type: "operation"
460 , getter: false
461 , setter: false
462 , creator: false
463 , deleter: false
464 , legacycaller: false
465 , "static": false
466 , stringifier: false
467 };
46860 while (true) {
46978 all_ws();
47087 if (consume(ID, "getter")) ret.getter = true;
47174 else if (consume(ID, "setter")) ret.setter = true;
47265 else if (consume(ID, "creator")) ret.creator = true;
47365 else if (consume(ID, "deleter")) ret.deleter = true;
47462 else if (consume(ID, "legacycaller")) ret.legacycaller = true;
47560 else break;
476 }
47760 if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
47817 all_ws();
47917 ret.idlType = return_type();
48017 operation_rest(ret);
48117 return ret;
482 }
48343 if (consume(ID, "static")) {
4841 ret["static"] = true;
4851 ret.idlType = return_type();
4861 operation_rest(ret);
4871 return ret;
488 }
48942 else if (consume(ID, "stringifier")) {
4903 ret.stringifier = true;
4913 all_ws();
4924 if (consume(OTHER, ";")) return ret;
4932 ret.idlType = return_type();
4942 operation_rest(ret);
4952 return ret;
496 }
49739 ret.idlType = return_type();
49839 all_ws();
49939 if (consume(ID, "iterator")) {
5004 all_ws();
5014 ret.type = "iterator";
5024 if (consume(ID, "object")) {
5031 ret.iteratorObject = "object";
504 }
5053 else if (consume(OTHER, "=")) {
5062 all_ws();
5072 var name = consume(ID) || error("No right hand side in iterator");
5082 ret.iteratorObject = name.value;
509 }
5104 all_ws();
5114 consume(OTHER, ";") || error("Unterminated iterator");
5124 return ret;
513 }
514 else {
51535 operation_rest(ret);
51635 return ret;
517 }
518 };
519
52047 var identifiers = function (arr) {
5215 while (true) {
52211 all_ws();
52311 if (consume(OTHER, ",")) {
5246 all_ws();
5256 var name = consume(ID) || error("Trailing comma in identifiers list");
5266 arr.push(name.value);
527 }
5285 else break;
529 }
530 };
531
53247 var serialiser = function () {
533164 all_ws();
534318 if (!consume(ID, "serializer")) return;
53510 var ret = { type: "serializer" };
53610 all_ws();
53710 if (consume(OTHER, "=")) {
5388 all_ws();
5398 if (consume(OTHER, "{")) {
5405 ret.patternMap = true;
5415 all_ws();
5425 var id = consume(ID);
5435 if (id && id.value === "getter") {
5441 ret.names = ["getter"];
545 }
5464 else if (id && id.value === "inherit") {
5472 ret.names = ["inherit"];
5482 identifiers(ret.names);
549 }
5502 else if (id) {
5512 ret.names = [id.value];
5522 identifiers(ret.names);
553 }
554 else {
5550 ret.names = [];
556 }
5575 all_ws();
5585 consume(OTHER, "}") || error("Unterminated serializer pattern map");
559 }
5603 else if (consume(OTHER, "[")) {
5612 ret.patternList = true;
5622 all_ws();
5632 var id = consume(ID);
5642 if (id && id.value === "getter") {
5651 ret.names = ["getter"];
566 }
5671 else if (id) {
5681 ret.names = [id.value];
5691 identifiers(ret.names);
570 }
571 else {
5720 ret.names = [];
573 }
5742 all_ws();
5752 consume(OTHER, "]") || error("Unterminated serializer pattern list");
576 }
577 else {
5781 var name = consume(ID) || error("Invalid serializer");
5791 ret.name = name.value;
580 }
5818 all_ws();
5828 consume(OTHER, ";") || error("Unterminated serializer");
5838 return ret;
584 }
5852 else if (consume(OTHER, ";")) {
586 // noop, just parsing
587 }
588 else {
5891 ret.idlType = return_type();
5901 all_ws();
5911 ret.operation = operation_rest();
592 }
5932 return ret;
594 };
595
59647 var interface_ = function (isPartial) {
597144 all_ws();
598210 if (!consume(ID, "interface")) return;
59978 all_ws();
60078 var name = consume(ID) || error("No name for interface");
60178 var ret = {
602 type: "interface"
603 , name: name.value
604 , partial: false
605 , members: []
606 };
607155 if (!isPartial) ret.inheritance = inheritance() || null;
60878 all_ws();
60978 consume(OTHER, "{") || error("Bodyless interface");
61078 while (true) {
611251 all_ws();
612251 if (consume(OTHER, "}")) {
61378 all_ws();
61478 consume(OTHER, ";") || error("Missing semicolon after interface");
61578 return ret;
616 }
617173 var ea = extended_attrs();
618173 all_ws();
619173 var cnt = const_();
620173 if (cnt) {
6219 cnt.extAttrs = ea;
6229 ret.members.push(cnt);
6239 continue;
624 }
625164 var mem = serialiser() || attribute() || operation() || error("Unknown member");
626164 mem.extAttrs = ea;
627164 ret.members.push(mem);
628 }
629 };
630
63147 var partial = function () {
63266 all_ws();
633130 if (!consume(ID, "partial")) return;
6342 var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
6352 thing.partial = true;
6362 return thing;
637 };
638
63947 var dictionary = function (isPartial) {
64066 all_ws();
641128 if (!consume(ID, "dictionary")) return;
6424 all_ws();
6434 var name = consume(ID) || error("No name for dictionary");
6444 var ret = {
645 type: "dictionary"
646 , name: name.value
647 , partial: false
648 , members: []
649 };
6507 if (!isPartial) ret.inheritance = inheritance() || null;
6514 all_ws();
6524 consume(OTHER, "{") || error("Bodyless dictionary");
6534 while (true) {
65413 all_ws();
65513 if (consume(OTHER, "}")) {
6564 all_ws();
6574 consume(OTHER, ";") || error("Missing semicolon after dictionary");
6584 return ret;
659 }
6609 var ea = extended_attrs();
6619 all_ws();
6629 var typ = type() || error("No type for dictionary member");
6639 all_ws();
6649 var name = consume(ID) || error("No name for dictionary member");
6659 ret.members.push({
666 type: "field"
667 , name: name.value
668 , idlType: typ
669 , extAttrs: ea
670 , "default": default_()
671 });
6729 all_ws();
6739 consume(OTHER, ";") || error("Unterminated dictionary member");
674 }
675 };
676
67747 var exception = function () {
67861 all_ws();
679113 if (!consume(ID, "exception")) return;
6809 all_ws();
6819 var name = consume(ID) || error("No name for exception");
6829 var ret = {
683 type: "exception"
684 , name: name.value
685 , members: []
686 };
6879 ret.inheritance = inheritance() || null;
6889 all_ws();
6899 consume(OTHER, "{") || error("Bodyless exception");
6909 while (true) {
69116 all_ws();
69216 if (consume(OTHER, "}")) {
6939 all_ws();
6949 consume(OTHER, ";") || error("Missing semicolon after exception");
6959 return ret;
696 }
6977 var ea = extended_attrs();
6987 all_ws();
6997 var cnt = const_();
7007 if (cnt) {
7013 cnt.extAttrs = ea;
7023 ret.members.push(cnt);
703 }
704 else {
7054 var typ = type();
7064 all_ws();
7074 var name = consume(ID);
7084 all_ws();
7094 if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body");
7104 ret.members.push({
711 type: "field"
712 , name: name.value
713 , idlType: typ
714 , extAttrs: ea
715 });
716 }
717 }
718 };
719
72047 var enum_ = function () {
72152 all_ws();
722103 if (!consume(ID, "enum")) return;
7231 all_ws();
7241 var name = consume(ID) || error("No name for enum");
7251 var ret = {
726 type: "enum"
727 , name: name.value
728 , values: []
729 };
7301 all_ws();
7311 consume(OTHER, "{") || error("No curly for enum");
7321 var saw_comma = false;
7331 while (true) {
7344 all_ws();
7354 if (consume(OTHER, "}")) {
7361 all_ws();
7371 if (saw_comma) error("Trailing comma in enum");
7381 consume(OTHER, ";") || error("No semicolon after enum");
7391 return ret;
740 }
7413 var val = consume(STR) || error("Unexpected value in enum");
7423 ret.values.push(val.value.replace(/"/g, ""));
7433 all_ws();
7443 if (consume(OTHER, ",")) {
7452 all_ws();
7462 saw_comma = true;
747 }
748 else {
7491 saw_comma = false;
750 }
751 }
752 };
753
75447 var typedef = function () {
75551 all_ws();
75699 if (!consume(ID, "typedef")) return;
7573 var ret = {
758 type: "typedef"
759 };
7603 all_ws();
7613 ret.extAttrs = extended_attrs();
7623 all_ws();
7633 ret.idlType = type() || error("No type in typedef");
7643 all_ws();
7653 var name = consume(ID) || error("No name in typedef");
7663 ret.name = name.value;
7673 all_ws();
7683 consume(OTHER, ";") || error("Unterminated typedef");
7693 return ret;
770 };
771
77247 var implements_ = function () {
77348 all_ws();
77448 var target = consume(ID);
77595 if (!target) return;
7761 var w = all_ws();
7771 if (consume(ID, "implements")) {
7781 var ret = {
779 type: "implements"
780 , target: target.value
781 };
7821 all_ws();
7831 var imp = consume(ID) || error("Incomplete implements statement");
7841 ret["implements"] = imp.value;
7851 all_ws();
7861 consume(OTHER, ";") || error("No terminating ; for implements statement");
7871 return ret;
788 }
789 else {
790 // rollback
7910 tokens.unshift(w);
7920 tokens.unshift(target);
793 }
794 };
795
79647 var definition = function () {
797144 return callback() ||
798 interface_() ||
799 partial() ||
800 dictionary() ||
801 exception() ||
802 enum_() ||
803 typedef() ||
804 implements_()
805 ;
806 };
807
80847 var definitions = function () {
80947 if (!tokens.length) return [];
81047 var defs = [];
81147 while (true) {
812144 var ea = extended_attrs()
813 , def = definition();
814144 if (!def) {
81547 if (ea.length) error("Stray extended attributes");
81647 break;
817 }
81897 def.extAttrs = ea;
81997 defs.push(def);
820 }
82147 return defs;
822 };
82347 var res = definitions();
82447 if (tokens.length) error("Unrecognised tokens");
82547 return res;
826 };
827
8281 var obj = {
829 parse: function (str) {
83047 var tokens = tokenise(str);
831 // console.log(tokens);
83247 return parse(tokens);
833 }
834 };
8351 if (typeof module !== "undefined" && module.exports) {
8361 module.exports = obj;
837 }
838 else {
8390 window.WebIDL2 = obj;
840 }
841}());
diff --git a/test/fixtures/wpt/resources/webidl2/index.js b/test/fixtures/wpt/resources/webidl2/index.js deleted file mode 100644 index 09f9eb46aa78f4..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("./lib/webidl2.js"); diff --git a/test/fixtures/wpt/resources/webidl2/lib/writer.js b/test/fixtures/wpt/resources/webidl2/lib/writer.js deleted file mode 100644 index b3097a6f8a74e4..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/lib/writer.js +++ /dev/null @@ -1,221 +0,0 @@ -"use strict"; - -(() => { - function write(ast, opt = {}) { - const noop = str => str; - const optNames = "type".split(" "); - const context = []; - for (const o of optNames) { - if (!opt[o]) opt[o] = noop; - } - - function literal(it) { - return it.value; - }; - function type(it) { - if (typeof it === "string") return opt.type(it); // XXX should maintain some context - let ret = extended_attributes(it.extAttrs); - if (it.union) ret += `(${it.idlType.map(type).join(" or ")})`; - else { - if (it.generic) ret += `${it.generic}<`; - if (Array.isArray(it.idlType)) ret += it.idlType.map(type).join(", "); - else ret += type(it.idlType); - if (it.generic) ret += ">"; - } - if (it.nullable) ret += "?"; - - return ret; - }; - function const_value(it) { - const tp = it.type; - if (tp === "boolean") return it.value ? "true" : "false"; - else if (tp === "null") return "null"; - else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity"; - else if (tp === "NaN") return "NaN"; - else if (tp === "number") return it.value; - else if (tp === "sequence") return "[]"; - else return `"${it.value}"`; - }; - function argument(arg) { - let ret = extended_attributes(arg.extAttrs); - if (arg.optional) ret += "optional "; - ret += type(arg.idlType); - if (arg.variadic) ret += "..."; - ret += ` ${arg.escapedName}`; - if (arg.default) ret += ` = ${const_value(arg.default)}`; - return ret; - }; - function make_ext_at(it) { - context.unshift(it); - let ret = it.name; - if (it.rhs) { - if (it.rhs.type === "identifier-list") ret += `=(${it.rhs.value.join(",")})`; - else ret += `=${it.rhs.value}`; - } - if (it.arguments) ret += `(${it.arguments.length ? it.arguments.map(argument).join(",") : ""})`; - context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec - return ret; - }; - function extended_attributes(eats) { - if (!eats || !eats.length) return ""; - return `[${eats.map(make_ext_at).join(", ")}]`; - }; - - const modifiers = "getter setter deleter stringifier static".split(" "); - function operation(it) { - let ret = extended_attributes(it.extAttrs); - if (it.stringifier && !it.idlType) return "stringifier;"; - for (const mod of modifiers) { - if (it[mod]) ret += mod + " "; - } - ret += type(it.idlType) + " "; - if (it.name) ret += it.escapedName; - ret += `(${it.arguments.map(argument).join(",")});`; - return ret; - }; - - function attribute(it) { - let ret = extended_attributes(it.extAttrs); - if (it.static) ret += "static "; - if (it.stringifier) ret += "stringifier "; - if (it.inherit) ret += "inherit "; - if (it.readonly) ret += "readonly "; - ret += `attribute ${type(it.idlType)} ${it.escapedName};`; - return ret; - }; - - function interface_(it) { - let ret = extended_attributes(it.extAttrs); - if (it.partial) ret += "partial "; - ret += `interface ${it.name} `; - if (it.inheritance) ret += `: ${it.inheritance} `; - ret += `{${iterate(it.members)}};`; - return ret; - }; - - function interface_mixin(it) { - let ret = extended_attributes(it.extAttrs); - if (it.partial) ret += "partial "; - ret += `interface mixin ${it.name} `; - ret += `{${iterate(it.members)}};`; - return ret; - } - - function namespace(it) { - let ret = extended_attributes(it.extAttrs); - if (it.partial) ret += "partial "; - ret += `namespace ${it.name} `; - ret += `{${iterate(it.members)}};`; - return ret; - } - - function dictionary(it) { - let ret = extended_attributes(it.extAttrs); - if (it.partial) ret += "partial "; - ret += `dictionary ${it.name} `; - if (it.inheritance) ret += `: ${it.inheritance} `; - ret += `{${iterate(it.members)}};`; - return ret; - }; - function field(it) { - let ret = extended_attributes(it.extAttrs); - if (it.required) ret += "required "; - ret += `${type(it.idlType)} ${it.escapedName}`; - if (it.default) ret += ` = ${const_value(it.default)}`; - ret += ";"; - return ret; - }; - function const_(it) { - const ret = extended_attributes(it.extAttrs); - return `${ret}const ${type(it.idlType)}${it.nullable ? "?" : ""} ${it.name} = ${const_value(it.value)};`; - }; - function typedef(it) { - let ret = extended_attributes(it.extAttrs); - ret += `typedef ${extended_attributes(it.typeExtAttrs)}`; - return `${ret}${type(it.idlType)} ${it.name};`; - }; - function implements_(it) { - const ret = extended_attributes(it.extAttrs); - return `${ret}${it.target} implements ${it.implements};`; - }; - function includes(it) { - const ret = extended_attributes(it.extAttrs); - return `${ret}${it.target} includes ${it.includes};`; - }; - function callback(it) { - const ret = extended_attributes(it.extAttrs); - return `${ret}callback ${it.name} = ${type(it.idlType)}(${it.arguments.map(argument).join(",")});`; - }; - function enum_(it) { - let ret = extended_attributes(it.extAttrs); - ret += `enum ${it.name} {`; - for (const v of it.values) { - ret += `"${v.value}",`; - } - return ret + "};"; - }; - function iterable(it) { - return `iterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; - }; - function legacyiterable(it) { - return `legacyiterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; - }; - function maplike(it) { - return `${it.readonly ? "readonly " : ""}maplike<${it.idlType.map(type).join(", ")}>;`; - }; - function setlike(it) { - return `${it.readonly ? "readonly " : ""}setlike<${type(it.idlType[0])}>;`; - }; - function callbackInterface(it) { - return `callback ${interface_(it)}`; - }; - - const table = { - interface: interface_, - "interface mixin": interface_mixin, - namespace, - operation, - attribute, - dictionary, - field, - const: const_, - typedef, - implements: implements_, - includes, - callback, - enum: enum_, - iterable, - legacyiterable, - maplike, - setlike, - "callback interface": callbackInterface - }; - function dispatch(it) { - const dispatcher = table[it.type]; - if (!dispatcher) { - throw new Error(`Type "${it.type}" is unsupported`) - } - return table[it.type](it); - }; - function iterate(things) { - if (!things) return; - let ret = ""; - for (const thing of things) ret += dispatch(thing); - return ret; - }; - return iterate(ast); - }; - - - const obj = { - write - }; - - if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = obj; - } else if (typeof define === 'function' && define.amd) { - define([], () => obj); - } else { - (self || window).WebIDL2Writer = obj; - } -})(); diff --git a/test/fixtures/wpt/resources/webidl2/package-lock.json b/test/fixtures/wpt/resources/webidl2/package-lock.json deleted file mode 100644 index b0581037fe9434..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/package-lock.json +++ /dev/null @@ -1,700 +0,0 @@ -{ - "name": "webidl2", - "version": "13.0.3", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz", - "integrity": "sha512-eVXQSbu/RimU6OKcK2/gDJVTFcxXJI4sHbIqw2mhwMZeQ2as/8AhS9DGkEDoHMBBNJZ5B0US63lF56x+KDcxiA==", - "dev": true, - "requires": { - "@babel/highlight": "7.0.0-beta.40" - } - }, - "@babel/highlight": { - "version": "7.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.40.tgz", - "integrity": "sha512-mOhhTrzieV6VO7odgzFGFapiwRK0ei8RZRhfzHhb6cpX3QM8XXuCLXWjN8qBB7JReDdUR80V3LFfFrGUYevhNg==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "diff-match-patch": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.0.tgz", - "integrity": "sha1-HMPIOkkNZ/ldkeOfatHy4Ia2MEg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - } - }, - "expect": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.0.tgz", - "integrity": "sha512-Fiy862jT3qc70hwIHwwCBNISmaqBrfWKKrtqyMJ6iwZr+6KXtcnHojZFtd63TPRvRl8EQTJ+YXYy2lK6/6u+Hw==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "jest-diff": "^22.4.0", - "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^22.4.0", - "jest-message-util": "^22.4.0", - "jest-regex-util": "^22.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "growl": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", - "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "jest-diff": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.0.tgz", - "integrity": "sha512-+/t20WmnkOkB8MOaGaPziI8zWKxquMvYw4Ub+wOzi7AUhmpFXz43buWSxVoZo4J5RnCozpGbX3/FssjJ5KV9Nw==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^22.4.0" - } - }, - "jest-get-type": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.1.0.tgz", - "integrity": "sha512-nD97IVOlNP6fjIN5i7j5XRH+hFsHL7VlauBbzRvueaaUe70uohrkz7pL/N8lx/IAwZRTJ//wOdVgh85OgM7g3w==", - "dev": true - }, - "jest-matcher-utils": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz", - "integrity": "sha512-03m3issxUXpWMwDYTfmL8hRNewUB0yCRTeXPm+eq058rZxLHD9f5NtSSO98CWHqe4UyISIxd9Ao9iDVjHWd2qg==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "pretty-format": "^22.4.0" - } - }, - "jest-message-util": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.0.tgz", - "integrity": "sha512-eyCJB0T3hrlpFF2FqQoIB093OulP+1qvATQmD3IOgJgMGqPL6eYw8TbC5P/VCWPqKhGL51xvjIIhow5eZ2wHFw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0-beta.35", - "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-regex-util": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.1.0.tgz", - "integrity": "sha512-on0LqVS6Xeh69sw3d1RukVnur+lVOl3zkmb0Q54FHj9wHoq6dbtWqb3TSlnVUyx36hqjJhjgs/QLqs07Bzu72Q==", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "jsondiffpatch": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.3.5.tgz", - "integrity": "sha512-v7eaGLDMCHXH+fsIaZhptEUJmS8EJpunq7IM4cc4vIT/kSRAkaZ6ZF4ebiNcyUelL0znbvj6o2B5Gh9v7Og0BQ==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "diff-match-patch": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", - "dev": true - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.4.tgz", - "integrity": "sha512-nMOpAPFosU1B4Ix1jdhx5e3q7XO55ic5a8cgYvW27CequcEY+BabS0kUVL1Cw1V5PuVHZWeNRWFLmEPexo79VA==", - "dev": true, - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.11.0", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.3", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "4.4.0" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "pretty-format": { - "version": "22.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.0.tgz", - "integrity": "sha512-pvCxP2iODIIk9adXlo4S3GRj0BrJiil68kByAa1PrgG97c1tClh9dLMgp3Z6cHFZrclaABt0UH8PIhwHuFLqYA==", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "randomatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", - "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", - "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", - "dev": true - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - } -} diff --git a/test/fixtures/wpt/resources/webidl2/package.json b/test/fixtures/wpt/resources/webidl2/package.json deleted file mode 100644 index 92faccafa813fb..00000000000000 --- a/test/fixtures/wpt/resources/webidl2/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "webidl2", - "description": "A WebIDL Parser", - "version": "13.0.3", - "contributors": [ - "Robin Berjon (https://berjon.com)", - "Marcos Caceres (https://marcosc.com)", - "Kagami Sascha Rosylight ", - "Timothy Gu " - ], - "license": "W3C", - "dependencies": {}, - "devDependencies": { - "expect": "22.4.0", - "jsondiffpatch": "0.3.5", - "mocha": "5.0.4" - }, - "scripts": { - "test": "mocha", - "acquire": "node test/util/acquire.js" - }, - "repository": "git://github.com/w3c/webidl2.js", - "main": "index.js", - "files": [ - "lib/*" - ] -} diff --git a/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.window.js b/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js similarity index 88% rename from test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.window.js rename to test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js index 15400f69340451..d2b37f00a9d697 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.window.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js @@ -1,3 +1,5 @@ +// META: global=window,worker + promise_test(async t => { const error = new Error('cannot proceed'); const rs = new ReadableStream({ @@ -5,7 +7,7 @@ promise_test(async t => { pull: t.step_func((controller) => { const buffer = controller.byobRequest.view.buffer; // Detach the buffer. - postMessage(buffer, '*', [buffer]); + structuredClone(buffer, { transfer: [buffer] }); // Try to enqueue with a new buffer. assert_throws_js(TypeError, () => controller.enqueue(new Uint8Array([42]))); diff --git a/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js b/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js index f7e2d06ae5cdf3..e578176777adaf 100644 --- a/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js +++ b/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js @@ -1,5 +1,6 @@ // META: global=window,worker // META: script=../resources/test-utils.js +// META: script=/common/gc.js 'use strict'; promise_test(async () => { diff --git a/test/fixtures/wpt/streams/resources/test-utils.js b/test/fixtures/wpt/streams/resources/test-utils.js index fb34e270ff3718..5ff8fc8cec939a 100644 --- a/test/fixtures/wpt/streams/resources/test-utils.js +++ b/test/fixtures/wpt/streams/resources/test-utils.js @@ -47,26 +47,6 @@ self.constructorThrowsForAll = (constructor, firstArgs) => { 'constructor should throw a TypeError')); }; -self.garbageCollect = async () => { - if (self.TestUtils?.gc) { - // https://testutils.spec.whatwg.org/#the-testutils-namespace - await TestUtils.gc(); - } else if (self.gc) { - // Use --expose_gc for V8 (and Node.js) - // to pass this flag at chrome launch use: --js-flags="--expose-gc" - // Exposed in SpiderMonkey shell as well - self.gc(); - } else if (self.GCController) { - // Present in some WebKit development environments - GCController.collect(); - } else { - /* eslint-disable no-console */ - console.warn('Tests are running without the ability to do manual garbage collection. They will still work, but ' + - 'coverage will be suboptimal.'); - /* eslint-enable no-console */ - } -}; - self.delay = ms => new Promise(resolve => step_timeout(resolve, ms)); // For tests which verify that the implementation doesn't do something it shouldn't, it's better not to use a diff --git a/test/fixtures/wpt/streams/transferable/gc-crash.html b/test/fixtures/wpt/streams/transferable/gc-crash.html new file mode 100644 index 00000000000000..0d331e6be08059 --- /dev/null +++ b/test/fixtures/wpt/streams/transferable/gc-crash.html @@ -0,0 +1,17 @@ + + + + diff --git a/test/fixtures/wpt/url/url-constructor.html b/test/fixtures/wpt/url/url-constructor.html deleted file mode 100644 index 7ddcdc88170c20..00000000000000 --- a/test/fixtures/wpt/url/url-constructor.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - -
- diff --git a/test/fixtures/wpt/url/url-origin.html b/test/fixtures/wpt/url/url-origin.html deleted file mode 100644 index fccb643ed6c806..00000000000000 --- a/test/fixtures/wpt/url/url-origin.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - -
- diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index f3a49312328e6d..8dd0c82e0c4cce 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -1,6 +1,6 @@ { "common": { - "commit": "03c5072affa496c5fd2a506e5c40d23e36b5e3aa", + "commit": "dbd648158d337580885e70a54f929daf215211a0", "path": "common" }, "console": { @@ -24,13 +24,9 @@ "path": "fetch/data-urls/resources" }, "FileAPI": { - "commit": "3b279420d40afea32506e823f9ac005448f4f3d8", + "commit": "1e432c4550a1595888d7c9eb26d90895e9e7e022", "path": "FileAPI" }, - "FileAPI/file": { - "commit": "c01f637cca43f0e08ce8e4269121dcd89ccbdd82", - "path": "FileAPI/file" - }, "hr-time": { "commit": "34cafd797e58dad280d20040eee012d49ccfa91f", "path": "hr-time" @@ -64,11 +60,11 @@ "path": "resource-timing" }, "resources": { - "commit": "fbf1e7d24776b6da144dbca45c22d39dc0512d2d", + "commit": "919874f84ff3703365063e749161a34af38c3d2a", "path": "resources" }, "streams": { - "commit": "9e5ef42bd34b5b19b76d0d4cb19012e52c222664", + "commit": "51750bc8d749bd80930506f603940a6bafda459f", "path": "streams" }, "url": { @@ -94,5 +90,9 @@ "webidl/ecmascript-binding/es-exceptions": { "commit": "a370aad338d6ed743abb4d2c6ae84a7f1058558c", "path": "webidl/ecmascript-binding/es-exceptions" + }, + "webmessaging/broadcastchannel": { + "commit": "e97fac4791931fb7455ba3fad759d362c7108b09", + "path": "webmessaging/broadcastchannel" } } diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/blobs.html b/test/fixtures/wpt/webmessaging/broadcastchannel/blobs.html index 1f0e2f1f1d6050..ab5096b63c19b0 100644 --- a/test/fixtures/wpt/webmessaging/broadcastchannel/blobs.html +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/blobs.html @@ -2,6 +2,7 @@ + @@ -7,66 +8,349 @@ - - + + diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/opaque-origin.html b/test/fixtures/wpt/webmessaging/broadcastchannel/opaque-origin.html index c10e0cb22256a0..e09d935244b8b6 100644 --- a/test/fixtures/wpt/webmessaging/broadcastchannel/opaque-origin.html +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/opaque-origin.html @@ -2,6 +2,7 @@ + @@ -26,9 +27,166 @@ assert_equals(e.data.messageOrigin, "null"); resolve(); }), {once: true}); + t.add_cleanup(() => { document.body.removeChild(ifr) }); document.body.appendChild(ifr); }); }, "Opaque origin should be serialized to \"null\""); + + +const iframe_src = (channel_name, iframe_name) => `data:text/html,`; + +promise_test(t => { + return new Promise((resolve, reject) => { + const channel_name = "opaque-origin-test-2"; + const bc1 = new BroadcastChannel(channel_name); + bc1.onmessage = t.unreached_func("Received message from an opaque origin"); + + // We'll create an iframe and have it send a BroadcastChannel message + // between two instances. Once the message is received, it will postMessage + // back and we'll repeat this with another iframe. If the first + // BroadcastChannel message is received by `bc1`, or if the second + // BroadcastChannel message is received by `bc1` or `bc2` in the first + // iframe, then the test should fail. + + window.addEventListener("message", e => { + if(e.data == "iframe1-done") { + let iframe2 = document.createElement("iframe"); + iframe2.src = iframe_src(channel_name, "iframe2"); + t.add_cleanup(() => { document.body.removeChild(iframe2) }); + document.body.appendChild(iframe2); + } else if(e.data == "iframe2-done") { + resolve(); + } else if(e.data == "fail") { + reject("One opaque origin received a message from the other"); + } else { + reject("An unexpected error occurred"); + } + }); + + let iframe1 = document.createElement("iframe"); + iframe1.src = iframe_src(channel_name, "iframe1"); + t.add_cleanup(() => { document.body.removeChild(iframe1) }); + document.body.appendChild(iframe1); + }); +}, "BroadcastChannel messages from opaque origins should be self-contained"); + +const data_url_worker_src = (channel_name, worker_name) => { + const source = ` +const handler = (reply) => { + let bc2 = new BroadcastChannel("${channel_name}"); + bc2.onmessage = (e) => { + if (e.data == "from-${worker_name}") { + reply("${worker_name}-done"); + } else { + reply("fail"); + } + }; + let bc3 = new BroadcastChannel("${channel_name}"); + bc3.postMessage("from-${worker_name}"); +}; +// For dedicated workers: +self.addEventListener("message", () => handler(self.postMessage)); +// For shared workers: +self.addEventListener("connect", (e) => { + var port = e.ports[0]; + port.onmessage = () => handler(msg => port.postMessage(msg)); + port.start(); + +}); +`; + return "data:,".concat(encodeURIComponent(source)); +} + +promise_test(t => { + return new Promise((resolve, reject) => { + const channel_name = "opaque-origin-test-3"; + const bc1 = new BroadcastChannel(channel_name); + bc1.onmessage = e => { reject("Received message from an opaque origin"); }; + + // Same as the previous test but with data URL dedicated workers (which + // should have opaque origins per the HTML spec). + const worker_name_prefix = "data-url-dedicated-worker"; + const worker_1_name = `${worker_name_prefix}-1`; + const worker_2_name = `${worker_name_prefix}-2`; + + const handler = e => { + if(e.data == `${worker_1_name}-done`) { + const worker2 = new Worker(data_url_worker_src(channel_name, worker_2_name)); + t.add_cleanup(() => worker2.terminate()); + worker2.addEventListener("message", handler); + worker2.postMessage("go!"); + } else if(e.data == `${worker_2_name}-done`) { + resolve(); + } else if(e.data == "fail") { + reject("One opaque origin received a message from the other"); + } else { + reject("An unexpected error occurred"); + } + }; + + let worker1 = new Worker(data_url_worker_src(channel_name, worker_1_name)); + t.add_cleanup(() => worker1.terminate()); + worker1.addEventListener("message", handler); + worker1.postMessage("go!"); + }); +}, "BroadcastChannel messages from data URL dedicated workers should be self-contained"); + +promise_test(() => { + return new Promise((resolve, reject) => { + const channel_name = "opaque-origin-test-4"; + const bc1 = new BroadcastChannel(channel_name); + + // Same as the previous test but with data URL shared workers (which + // should have opaque origins per the HTML spec). + const worker_name_prefix = "data-url-shared-worker"; + const worker_1_name = `${worker_name_prefix}-1`; + const worker_2_name = `${worker_name_prefix}-2`; + + const handler = e => { + if (e.data == `${worker_1_name}-done`) { + const worker_script = data_url_worker_src(channel_name, worker_2_name); + const worker2 = new SharedWorker(worker_script, worker_2_name); + worker2.port.addEventListener("message", handler); + worker2.port.start(); + worker2.port.postMessage("go!"); + } else if(e.data == `${worker_2_name}-done`) { + resolve(); + } else if(e.data == "fail") { + reject("One opaque origin received a message from the other"); + } else { + reject("An unexpected error occurred"); + } + }; + + bc1.onmessage = e => { + if (e.data == "go!") { + const worker_script = data_url_worker_src(channel_name, worker_1_name); + const worker1 = new SharedWorker(worker_script, worker_1_name); + worker1.port.addEventListener("message", handler); + worker1.port.start(); + worker1.port.postMessage("go!"); + } else { + reject("Received message from an opaque origin"); + } + }; + + // Ensure that the BroadcastChannel instance above can receive messages + // before we create the first shared worker. + const bc2 = new BroadcastChannel(channel_name); + bc2.postMessage("go!"); + }); +}, "BroadcastChannel messages from data URL shared workers should be self-contained"); //--> diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/resources/worker.js b/test/fixtures/wpt/webmessaging/broadcastchannel/resources/worker.js index df23072bc99f95..ee2d51a2542567 100644 --- a/test/fixtures/wpt/webmessaging/broadcastchannel/resources/worker.js +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/resources/worker.js @@ -1,6 +1,8 @@ +importScripts("/common/gc.js"); + var c; -function handler(e, reply) { +async function handler(e, reply) { if (e.data.ping) { c.postMessage(e.data.ping); return; @@ -9,9 +11,7 @@ function handler(e, reply) { (() => { c.postMessage({blob: new Blob(e.data.blob)}); })(); - // TODO(https://github.com/web-platform-tests/wpt/issues/7899): Change to - // some sort of cross-browser GC trigger. - if (self.gc) self.gc(); + await garbageCollect(); } c = new BroadcastChannel(e.data.channel); let messages = []; diff --git a/test/wpt/status/FileAPI/blob.json b/test/wpt/status/FileAPI/blob.json index 902ac232dd4872..017d931d7abdc4 100644 --- a/test/wpt/status/FileAPI/blob.json +++ b/test/wpt/status/FileAPI/blob.json @@ -17,6 +17,7 @@ "ArrayBuffer elements of the blobParts array should be supported.", "Passing typed arrays as elements of the blobParts array should work.", "Passing a Float64Array as element of the blobParts array should work.", + "Passing BigInt typed arrays as elements of the blobParts array should work.", "Array with two blobs", "Array with two buffers", "Array with two bufferviews", @@ -43,5 +44,12 @@ }, "Blob-slice.any.js": { "skip": "Depends on File API" + }, + "Blob-stream.any.js": { + "fail": { + "expected": [ + "Reading Blob.stream() with BYOB reader" + ] + } } } diff --git a/test/wpt/status/streams.json b/test/wpt/status/streams.json index 9899c581d9f96e..187b1758741785 100644 --- a/test/wpt/status/streams.json +++ b/test/wpt/status/streams.json @@ -1,4 +1,11 @@ { + "idlharness.any.js": { + "fail": { + "expected": [ + "ReadableStream interface: async iterable" + ] + } + }, "queuing-strategies-size-function-per-global.window.js": { "skip": "Browser-specific test" }, diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json index a0957dccb53c73..c333559537f6a9 100644 --- a/test/wpt/status/url.json +++ b/test/wpt/status/url.json @@ -9,7 +9,9 @@ "historical.any.js": { "requires": ["small-icu"], "fail": { + "note": "We are faking location with a URL object for the sake of the testharness and it has searchParams.", "expected": [ + "searchParams on location object", "URL: no structured serialize/deserialize support", "URLSearchParams: no structured serialize/deserialize support" ] diff --git a/test/wpt/test-streams.js b/test/wpt/test-streams.js index faf906efb2ef74..71c25fbd56b20c 100644 --- a/test/wpt/test-streams.js +++ b/test/wpt/test-streams.js @@ -6,30 +6,5 @@ const runner = new WPTRunner('streams'); // Set a script that will be executed in the worker before running the tests. runner.pretendGlobalThisAs('Window'); -runner.setInitScript(` - // Simulate global postMessage for enqueue-with-detached-buffer.window.js - function postMessage(value, origin, transferList) { - const mc = new MessageChannel(); - mc.port1.postMessage(value, transferList); - mc.port2.close(); - } - - // TODO(@jasnell): This is a bit of a hack to get the idl harness test - // working. Later we should investigate a better approach. - // See: https://github.com/nodejs/node/pull/39062#discussion_r659383373 - Object.defineProperties(global, { - DedicatedWorkerGlobalScope: { - get() { - // Pretend that we're a DedicatedWorker, but *only* for the - // IDL harness. For everything else, keep the JavaScript shell - // environment. - if (new Error().stack.includes('idlharness.js')) - return global.constructor; - else - return function() {}; - } - } - }); -`); runner.runJsTests(); diff --git a/test/wpt/test-url.js b/test/wpt/test-url.js index f8ba3c3839d642..fc84c22a275c38 100644 --- a/test/wpt/test-url.js +++ b/test/wpt/test-url.js @@ -13,7 +13,4 @@ runner.setScriptModifier((obj) => { } }); runner.pretendGlobalThisAs('Window'); -runner.setInitScript(` - globalThis.location ||= {}; -`); runner.runJsTests();