From 9575913f99b60e9f8cdad5d9dc7cc258b1494495 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 15 Jan 2026 16:05:48 +0100 Subject: [PATCH 1/3] build: add embedtest into native suite Instead of adding a separate command to run the embedtest, since it's now run by the node binary via tools/test.py and test/embedding/test-embedding.js, put embedding into the native suite in test scripts. This helps adding more embedding tests into the folder and run them automatically without listing them one by one in the scripts. PR-URL: https://github.com/nodejs/node/pull/61357 Reviewed-By: Anna Henningsen Reviewed-By: Stefan Stojanovic --- Makefile | 4 +--- vcbuild.bat | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 4dfced1c8de07d..71f12062dd92e9 100644 --- a/Makefile +++ b/Makefile @@ -301,7 +301,6 @@ coverage-report-js: ## Report JavaScript coverage results. cctest: all ## Run the C++ tests using the built `cctest` executable. @out/$(BUILDTYPE)/$@ --gtest_filter=$(GTEST_FILTER) - '$(OUT_NODE)' ./test/embedding/test-embedding.js .PHONY: list-gtests list-gtests: ## List all available C++ gtests. @@ -571,7 +570,7 @@ test-all-suites: | clear-stalled test-build bench-addons-build doc-only ## Run a $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) test/* JS_SUITES ?= default -NATIVE_SUITES ?= addons js-native-api node-api +NATIVE_SUITES ?= addons js-native-api node-api embedding # CI_* variables should be kept synchronized with the ones in vcbuild.bat CI_NATIVE_SUITES ?= $(NATIVE_SUITES) benchmark CI_JS_SUITES ?= $(JS_SUITES) pummel @@ -613,7 +612,6 @@ test-ci: | clear-stalled bench-addons-build build-addons build-js-native-api-tes $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_JS_SUITES) $(CI_NATIVE_SUITES) $(CI_DOC) - '$(OUT_NODE)' ./test/embedding/test-embedding.js $(info Clean up any leftover processes, error if found.) ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ diff --git a/vcbuild.bat b/vcbuild.bat index 18b0f3aa6fdaed..9f324c7e5b8ae0 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -11,7 +11,7 @@ if /i "%arg:~-4%"=="help" goto help cd %~dp0 set JS_SUITES=default -set NATIVE_SUITES=addons js-native-api node-api +set NATIVE_SUITES=addons js-native-api node-api embedding @rem CI_* variables should be kept synchronized with the ones in Makefile set "CI_NATIVE_SUITES=%NATIVE_SUITES% benchmark" set "CI_JS_SUITES=%JS_SUITES% pummel" @@ -736,9 +736,6 @@ if not exist "%config%\cctest.exe" echo cctest.exe not found. Run "vcbuild test" echo running 'cctest %cctest_args%' "%config%\cctest" %cctest_args% if %errorlevel% neq 0 set exit_code=%errorlevel% -echo running '%node_exe% test\embedding\test-embedding.js' -"%node_exe%" test\embedding\test-embedding.js -if %errorlevel% neq 0 set exit_code=%errorlevel% :run-test-py echo running 'python tools\test.py %test_args%' python tools\test.py %test_args% From 1654684633aff288d9214352fbd94de4d4cca58b Mon Sep 17 00:00:00 2001 From: Xavier Stouder Date: Thu, 15 Jan 2026 17:33:26 +0100 Subject: [PATCH 2/3] esm: ensure watch mode restarts after syntax errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move watch dependency reporting earlier in module resolution to ensure file dependencies are tracked even when parsing fails. Fixes: https://github.com/nodejs/node/issues/61153 PR-URL: https://github.com/nodejs/node/pull/61232 Reviewed-By: Aviv Keller Reviewed-By: Moshe Atlow Reviewed-By: Joyee Cheung Reviewed-By: Juan José Arboleda --- lib/internal/modules/esm/loader.js | 11 +- ...t-watch-mode-restart-esm-loading-error.mjs | 126 ++++++++++++++++++ 2 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 test/sequential/test-watch-mode-restart-esm-loading-error.mjs diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 40dafb59687b28..0bff0763fcf58f 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -542,6 +542,12 @@ class ModuleLoader { */ #getOrCreateModuleJobAfterResolve(parentURL, resolveResult, request, requestType) { const { url, format } = resolveResult; + + if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { + const type = requestType === kRequireInImportedCJS ? 'require' : 'import'; + process.send({ [`watch:${type}`]: [url] }); + } + // TODO(joyeecheung): update the module requests to use importAttributes as property names. const importAttributes = resolveResult.importAttributes ?? request.attributes; let job = this.loadCache.get(url, importAttributes.type); @@ -570,11 +576,6 @@ class ModuleLoader { assert(moduleOrModulePromise instanceof ModuleWrap, `Expected ModuleWrap for loading ${url}`); } - if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { - const type = requestType === kRequireInImportedCJS ? 'require' : 'import'; - process.send({ [`watch:${type}`]: [url] }); - } - const { ModuleJob, ModuleJobSync } = require('internal/modules/esm/module_job'); // TODO(joyeecheung): use ModuleJobSync for kRequireInImportedCJS too. const ModuleJobCtor = (requestType === kImportInRequiredESM ? ModuleJobSync : ModuleJob); diff --git a/test/sequential/test-watch-mode-restart-esm-loading-error.mjs b/test/sequential/test-watch-mode-restart-esm-loading-error.mjs new file mode 100644 index 00000000000000..9d937aa2ed93cb --- /dev/null +++ b/test/sequential/test-watch-mode-restart-esm-loading-error.mjs @@ -0,0 +1,126 @@ +import * as common from '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; +import assert from 'node:assert'; +import path from 'node:path'; +import { execPath } from 'node:process'; +import { spawn } from 'node:child_process'; +import { writeFileSync } from 'node:fs'; +import { inspect } from 'node:util'; +import { createInterface } from 'node:readline'; + +if (common.isIBMi) + common.skip('IBMi does not support `fs.watch()`'); + +let tmpFiles = 0; +function createTmpFile(content = 'console.log("running");', ext = '.js', basename = tmpdir.path) { + const file = path.join(basename, `${tmpFiles++}${ext}`); + writeFileSync(file, content); + return file; +} + +function runInBackground({ args = [], options = {}, completed = 'Completed running', shouldFail = false }) { + let future = Promise.withResolvers(); + let child; + let stderr = ''; + let stdout = []; + + const run = () => { + args.unshift('--no-warnings'); + child = spawn(execPath, args, { encoding: 'utf8', stdio: 'pipe', ...options }); + + child.stderr.on('data', (data) => { + stderr += data; + }); + + const rl = createInterface({ input: child.stdout }); + rl.on('line', (data) => { + if (!data.startsWith('Waiting for graceful termination') && !data.startsWith('Gracefully restarted')) { + stdout.push(data); + if (data.startsWith(completed)) { + future.resolve({ stderr, stdout }); + future = Promise.withResolvers(); + stdout = []; + stderr = ''; + } else if (data.startsWith('Failed running')) { + if (shouldFail) { + future.resolve({ stderr, stdout }); + } else { + future.reject({ stderr, stdout }); + } + future = Promise.withResolvers(); + stdout = []; + stderr = ''; + } + } + }); + }; + + return { + async done() { + child?.kill(); + future.resolve(); + return { stdout, stderr }; + }, + restart(timeout = 1000) { + if (!child) { + run(); + } + const timer = setTimeout(() => { + if (!future.resolved) { + child.kill(); + future.reject(new Error('Timed out waiting for restart')); + } + }, timeout); + return future.promise.finally(() => { + clearTimeout(timer); + }); + }, + }; +} + +tmpdir.refresh(); + +// Create initial file with valid code +const initialContent = `console.log('hello, world');`; +const file = createTmpFile(initialContent, '.mjs'); + +const { done, restart } = runInBackground({ + args: ['--watch', file], + completed: 'Completed running', + shouldFail: true, +}); + +try { + const { stdout, stderr } = await restart(); + assert.strictEqual(stderr, ''); + assert.deepStrictEqual(stdout, [ + 'hello, world', + `Completed running ${inspect(file)}. Waiting for file changes before restarting...`, + ]); + + // Update file with syntax error + const syntaxErrorContent = `console.log('hello, wor`; + writeFileSync(file, syntaxErrorContent); + + // Wait for the failed restart + const { stderr: stderr2, stdout: stdout2 } = await restart(); + assert.match(stderr2, /SyntaxError: Invalid or unexpected token/); + assert.deepStrictEqual(stdout2, [ + `Restarting ${inspect(file)}`, + `Failed running ${inspect(file)}. Waiting for file changes before restarting...`, + ]); + + writeFileSync(file, `console.log('hello again, world');`); + + const { stderr: stderr3, stdout: stdout3 } = await restart(); + + // Verify it recovered and ran successfully + assert.strictEqual(stderr3, ''); + assert.deepStrictEqual(stdout3, [ + `Restarting ${inspect(file)}`, + 'hello again, world', + `Completed running ${inspect(file)}. Waiting for file changes before restarting...`, + ]); +} finally { + await done(); +} From ec49a09bbb61eb89efa0b5e1723beda9c438803d Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Thu, 15 Jan 2026 11:51:10 -0500 Subject: [PATCH 3/3] test: add webidl web-platform tests PR-URL: https://github.com/nodejs/node/pull/61316 Reviewed-By: Matthew Aitken Reviewed-By: Jason Zhang Reviewed-By: Chengzhong Wu Reviewed-By: Mattias Buelens --- test/fixtures/wpt/README.md | 1 + test/fixtures/wpt/versions.json | 4 + test/fixtures/wpt/webidl/META.yml | 3 + test/fixtures/wpt/webidl/README.md | 1 + test/fixtures/wpt/webidl/current-realm.html | 168 +++++++++++ .../ecmascript-binding/allow-resizable.html | 31 ++ ...tes-accessors-unique-function-objects.html | 35 +++ .../builtin-function-properties.any.js | 23 ++ .../class-string-interface.any.js | 62 ++++ ...ss-string-iterator-prototype-object.any.js | 51 ++++ ...s-string-named-properties-object.window.js | 23 ++ .../ecmascript-binding/constructors.html | 132 ++++++++ .../default-iterator-object.html | 27 ++ .../default-toJSON-cross-realm.html | 26 ++ .../global-immutable-prototype.any.js | 25 ++ .../global-mutable-prototype.any.js | 27 ++ ...bject-implicit-this-value-cross-realm.html | 97 ++++++ .../global-object-implicit-this-value.any.js | 85 ++++++ .../ecmascript-binding/has-instance.html | 26 ++ .../interface-object-set-receiver.html | 37 +++ .../ecmascript-binding/interface-object.html | 28 ++ ...ce-prototype-constructor-set-receiver.html | 36 +++ .../interface-prototype-object.html | 15 + .../invalid-this-value-cross-realm.html | 45 +++ .../iterator-invalidation-foreach.html | 40 +++ .../iterator-prototype-object.html | 47 +++ .../legacy-callback-interface-object.html | 69 +++++ .../legacy-factor-function-subclass.window.js | 13 + ...tory-function-builtin-properties.window.js | 6 + .../DefineOwnProperty.html | 165 ++++++++++ .../GetOwnProperty.html | 84 ++++++ .../OwnPropertyKeys.html | 65 ++++ .../legacy-platform-object/Set.html | 94 ++++++ .../legacy-platform-object/helper.js | 22 ++ .../no-regexp-special-casing.any.js | 47 +++ ...vable-array-no-leak-of-internals.window.js | 18 ++ .../observable-array-ownkeys.window.js | 34 +++ .../ecmascript-binding/put-forwards.html | 148 +++++++++ ...ter-throws-if-defineownproperty-fails.html | 38 +++ .../sequence-conversion.html | 157 ++++++++++ .../ecmascript-binding/setter-argument.html | 176 +++++++++++ .../support/constructors-support.html | 8 + .../support/create-realm.js | 12 + .../support/dummy-iframe.html | 7 + .../window-named-properties-object.html | 284 ++++++++++++++++++ test/fixtures/wpt/webidl/idlharness.any.js | 17 ++ test/wpt/status/webidl.json | 70 +++++ test/wpt/test-webidl.js | 8 + 48 files changed, 2637 insertions(+) create mode 100644 test/fixtures/wpt/webidl/META.yml create mode 100644 test/fixtures/wpt/webidl/README.md create mode 100644 test/fixtures/wpt/webidl/current-realm.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/allow-resizable.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/attributes-accessors-unique-function-objects.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/builtin-function-properties.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/class-string-interface.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/class-string-iterator-prototype-object.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/class-string-named-properties-object.window.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/constructors.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/default-iterator-object.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/default-toJSON-cross-realm.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/global-immutable-prototype.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/global-mutable-prototype.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value-cross-realm.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/has-instance.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/interface-object-set-receiver.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/interface-object.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-constructor-set-receiver.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-object.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/invalid-this-value-cross-realm.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/iterator-invalidation-foreach.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/iterator-prototype-object.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-callback-interface-object.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-factor-function-subclass.window.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-factory-function-builtin-properties.window.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/DefineOwnProperty.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/GetOwnProperty.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/OwnPropertyKeys.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/Set.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/helper.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/no-regexp-special-casing.any.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/observable-array-no-leak-of-internals.window.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/observable-array-ownkeys.window.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/put-forwards.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/replaceable-setter-throws-if-defineownproperty-fails.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/sequence-conversion.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/setter-argument.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/support/constructors-support.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/support/create-realm.js create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/support/dummy-iframe.html create mode 100644 test/fixtures/wpt/webidl/ecmascript-binding/window-named-properties-object.html create mode 100644 test/fixtures/wpt/webidl/idlharness.any.js create mode 100644 test/wpt/status/webidl.json create mode 100644 test/wpt/test-webidl.js diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index b9efc4c439dcf0..56a72c047d8d68 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -35,6 +35,7 @@ Last update: - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi - web-locks: https://github.com/web-platform-tests/wpt/tree/10a122a6bc/web-locks - WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/1e4933113d/WebCryptoAPI +- webidl: https://github.com/web-platform-tests/wpt/tree/63ca529a02/webidl - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/2f96fa1996/webidl/ecmascript-binding/es-exceptions - webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel - webstorage: https://github.com/web-platform-tests/wpt/tree/1d2c5fb36a/webstorage diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index e23cf07cf49863..72ce782e262d21 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -99,6 +99,10 @@ "commit": "1e4933113d2028e092d07a9e865db8f606b21026", "path": "WebCryptoAPI" }, + "webidl": { + "commit": "63ca529a021fec15b2996db82fd7dd04c11abe85", + "path": "webidl" + }, "webidl/ecmascript-binding/es-exceptions": { "commit": "2f96fa19966d6bc19e979a09479ac8a7aa337c54", "path": "webidl/ecmascript-binding/es-exceptions" diff --git a/test/fixtures/wpt/webidl/META.yml b/test/fixtures/wpt/webidl/META.yml new file mode 100644 index 00000000000000..9a1192f6704842 --- /dev/null +++ b/test/fixtures/wpt/webidl/META.yml @@ -0,0 +1,3 @@ +spec: https://webidl.spec.whatwg.org/ +suggested_reviewers: + - yuki3 diff --git a/test/fixtures/wpt/webidl/README.md b/test/fixtures/wpt/webidl/README.md new file mode 100644 index 00000000000000..136a7649981ea4 --- /dev/null +++ b/test/fixtures/wpt/webidl/README.md @@ -0,0 +1 @@ +Tests for the [Web IDL Standard](https://webidl.spec.whatwg.org/). diff --git a/test/fixtures/wpt/webidl/current-realm.html b/test/fixtures/wpt/webidl/current-realm.html new file mode 100644 index 00000000000000..29e07d1f79edc0 --- /dev/null +++ b/test/fixtures/wpt/webidl/current-realm.html @@ -0,0 +1,168 @@ + + + +Current Realm + + +
+ + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/allow-resizable.html b/test/fixtures/wpt/webidl/ecmascript-binding/allow-resizable.html new file mode 100644 index 00000000000000..54daa57bce676a --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/allow-resizable.html @@ -0,0 +1,31 @@ + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/attributes-accessors-unique-function-objects.html b/test/fixtures/wpt/webidl/ecmascript-binding/attributes-accessors-unique-function-objects.html new file mode 100644 index 00000000000000..167f55bcef7ead --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/attributes-accessors-unique-function-objects.html @@ -0,0 +1,35 @@ + + +All attributes accessors are unique function objects + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/builtin-function-properties.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/builtin-function-properties.any.js new file mode 100644 index 00000000000000..885bb441ead442 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/builtin-function-properties.any.js @@ -0,0 +1,23 @@ +"use strict"; + +test(() => { + const ownPropKeys = Reflect.ownKeys(Blob).slice(0, 3); + assert_array_equals(ownPropKeys, ["length", "name", "prototype"]); +}, 'Constructor property enumeration order of "length", "name", and "prototype"'); + +test(() => { + assert_own_property(Blob.prototype, "slice"); + + const ownPropKeys = Reflect.ownKeys(Blob.prototype.slice).slice(0, 2); + assert_array_equals(ownPropKeys, ["length", "name"]); +}, 'Method property enumeration order of "length" and "name"'); + +test(() => { + assert_own_property(Blob.prototype, "size"); + + const desc = Reflect.getOwnPropertyDescriptor(Blob.prototype, "size"); + assert_equals(typeof desc.get, "function"); + + const ownPropKeys = Reflect.ownKeys(desc.get).slice(0, 2); + assert_array_equals(ownPropKeys, ["length", "name"]); +}, 'Getter property enumeration order of "length" and "name"'); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/class-string-interface.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-interface.any.js new file mode 100644 index 00000000000000..ee792d5368389b --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-interface.any.js @@ -0,0 +1,62 @@ +"use strict"; + +test(() => { + assert_own_property(Blob.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(Blob.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "Blob", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); + +test(() => { + assert_not_own_property(new Blob(), Symbol.toStringTag); +}, "@@toStringTag must not exist on the instance"); + +test(() => { + assert_equals(Object.prototype.toString.call(Blob.prototype), "[object Blob]"); +}, "Object.prototype.toString applied to the prototype"); + +test(() => { + assert_equals(Object.prototype.toString.call(new Blob()), "[object Blob]"); +}, "Object.prototype.toString applied to an instance"); + +test(t => { + assert_own_property(Blob.prototype, Symbol.toStringTag, "Precondition for this test: @@toStringTag on the prototype"); + + t.add_cleanup(() => { + Object.defineProperty(Blob.prototype, Symbol.toStringTag, { value: "Blob" }); + }); + + Object.defineProperty(Blob.prototype, Symbol.toStringTag, { value: "NotABlob" }); + assert_equals(Object.prototype.toString.call(Blob.prototype), "[object NotABlob]", "prototype"); + assert_equals(Object.prototype.toString.call(new Blob()), "[object NotABlob]", "instance"); +}, "Object.prototype.toString applied after modifying the prototype's @@toStringTag"); + +test(t => { + const instance = new Blob(); + assert_not_own_property(instance, Symbol.toStringTag, "Precondition for this test: no @@toStringTag on the instance"); + + Object.defineProperty(instance, Symbol.toStringTag, { value: "NotABlob" }); + assert_equals(Object.prototype.toString.call(instance), "[object NotABlob]"); +}, "Object.prototype.toString applied to the instance after modifying the instance's @@toStringTag"); + +// Chrome had a bug (https://bugs.chromium.org/p/chromium/issues/detail?id=793406) where if there +// was no @@toStringTag in the prototype, it would fall back to a magic class string. This tests +// that the bug is fixed. + +test(() => { + const instance = new Blob(); + Object.setPrototypeOf(instance, null); + + assert_equals(Object.prototype.toString.call(instance), "[object Object]"); +}, "Object.prototype.toString applied to a null-prototype instance"); + +// This test must be last. +test(() => { + delete Blob.prototype[Symbol.toStringTag]; + + assert_equals(Object.prototype.toString.call(Blob.prototype), "[object Object]", "prototype"); + assert_equals(Object.prototype.toString.call(new Blob()), "[object Object]", "instance"); +}, "Object.prototype.toString applied after deleting @@toStringTag"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/class-string-iterator-prototype-object.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-iterator-prototype-object.any.js new file mode 100644 index 00000000000000..5ca549d69cff81 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-iterator-prototype-object.any.js @@ -0,0 +1,51 @@ +"use strict"; + +const iteratorProto = Object.getPrototypeOf((new URLSearchParams()).entries()); + +test(() => { + assert_own_property(iteratorProto, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(iteratorProto, Symbol.toStringTag); + assert_equals(propDesc.value, "URLSearchParams Iterator", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists with the appropriate descriptor"); + +test(() => { + assert_equals(Object.prototype.toString.call(iteratorProto), "[object URLSearchParams Iterator]"); +}, "Object.prototype.toString"); + +test(t => { + assert_own_property(iteratorProto, Symbol.toStringTag, "Precondition for this test: @@toStringTag exists"); + + t.add_cleanup(() => { + Object.defineProperty(iteratorProto, Symbol.toStringTag, { value: "URLSearchParams Iterator" }); + }); + + Object.defineProperty(iteratorProto, Symbol.toStringTag, { value: "Not URLSearchParams Iterator" }); + assert_equals(Object.prototype.toString.call(iteratorProto), "[object Not URLSearchParams Iterator]"); +}, "Object.prototype.toString applied after modifying @@toStringTag"); + +// Chrome had a bug (https://bugs.chromium.org/p/chromium/issues/detail?id=793406) where if there +// was no @@toStringTag, it would fall back to a magic class string. This tests that the bug is +// fixed. + +test(() => { + const iterator = (new URLSearchParams()).keys(); + assert_equals(Object.prototype.toString.call(iterator), "[object URLSearchParams Iterator]"); + + Object.setPrototypeOf(iterator, null); + assert_equals(Object.prototype.toString.call(iterator), "[object Object]"); +}, "Object.prototype.toString applied to a null-prototype instance"); + +test(t => { + const proto = Object.getPrototypeOf(iteratorProto); + t.add_cleanup(() => { + Object.setPrototypeOf(iteratorProto, proto); + }); + + Object.setPrototypeOf(iteratorProto, null); + + assert_equals(Object.prototype.toString.call(iteratorProto), "[object URLSearchParams Iterator]"); +}, "Object.prototype.toString applied after nulling the prototype"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/class-string-named-properties-object.window.js b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-named-properties-object.window.js new file mode 100644 index 00000000000000..a427a2f8142e53 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/class-string-named-properties-object.window.js @@ -0,0 +1,23 @@ +"use strict"; + +const namedPropertiesObject = Object.getPrototypeOf(Window.prototype); + +test(() => { + assert_own_property(namedPropertiesObject, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(namedPropertiesObject, Symbol.toStringTag); + assert_equals(propDesc.value, "WindowProperties", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists with the appropriate descriptor"); + +test(() => { + assert_equals(Object.prototype.toString.call(namedPropertiesObject), "[object WindowProperties]"); +}, "Object.prototype.toString"); + +// Chrome had a bug (https://bugs.chromium.org/p/chromium/issues/detail?id=793406) where if there +// was no @@toStringTag, it would fall back to a magic class string. Tests for this are present in +// the sibling class-string*.any.js tests. However, the named properties object always fails calls +// to [[DefineOwnProperty]] or [[SetPrototypeOf]] per the Web IDL spec, so there is no way to +// trigger the buggy behavior for it. diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/constructors.html b/test/fixtures/wpt/webidl/ecmascript-binding/constructors.html new file mode 100644 index 00000000000000..61993a6200ed56 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/constructors.html @@ -0,0 +1,132 @@ + + +Realm for constructed objects + + +
+ diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/default-iterator-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/default-iterator-object.html new file mode 100644 index 00000000000000..c7e9188521a2ae --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/default-iterator-object.html @@ -0,0 +1,27 @@ + + +Default iterator objects + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/default-toJSON-cross-realm.html b/test/fixtures/wpt/webidl/ecmascript-binding/default-toJSON-cross-realm.html new file mode 100644 index 00000000000000..79c3097f339b58 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/default-toJSON-cross-realm.html @@ -0,0 +1,26 @@ + + +Cross-realm [Default] toJSON() creates result object in its realm + + + + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/global-immutable-prototype.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/global-immutable-prototype.any.js new file mode 100644 index 00000000000000..6291c3ae935608 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/global-immutable-prototype.any.js @@ -0,0 +1,25 @@ +// META: global=window,worker +// META: title=Immutability of the global prototype chain + +const objects = []; +setup(() => { + for (let object = self; object; object = Object.getPrototypeOf(object)) { + objects.push(object); + } +}); + +test(() => { + for (const object of objects) { + assert_throws_js(TypeError, () => { + Object.setPrototypeOf(object, {}); + }); + } +}, "Setting to a different prototype"); + +test(() => { + for (const object of objects) { + const expected = Object.getPrototypeOf(object); + Object.setPrototypeOf(object, expected); + assert_equals(Object.getPrototypeOf(object), expected); + } +}, "Setting to the same prototype"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/global-mutable-prototype.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/global-mutable-prototype.any.js new file mode 100644 index 00000000000000..eba96e9adf4647 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/global-mutable-prototype.any.js @@ -0,0 +1,27 @@ +// META: global=shadowrealm +// META: title=Mutability of the global prototype chain + +const objects = []; +setup(() => { + for (let object = self; object; object = Object.getPrototypeOf(object)) { + objects.push(object); + } +}); + +test(() => { + for (const object of objects) { + const proto = Object.getPrototypeOf(object); + const plainObject = {}; + Object.setPrototypeOf(object, plainObject); + assert_equals(Object.getPrototypeOf(object), plainObject); + Object.setPrototypeOf(object, proto); + } +}, "Setting to a different prototype"); + +test(() => { + for (const object of objects) { + const expected = Object.getPrototypeOf(object); + Object.setPrototypeOf(object, expected); + assert_equals(Object.getPrototypeOf(object), expected); + } +}, "Setting to the same prototype"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value-cross-realm.html b/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value-cross-realm.html new file mode 100644 index 00000000000000..b9939b801cbd80 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value-cross-realm.html @@ -0,0 +1,97 @@ + + +Cross-realm getter / setter / operation doesn't use lexical global object if |this| value is incompatible object / null / undefined + + + + + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value.any.js new file mode 100644 index 00000000000000..4c159c67519c0b --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/global-object-implicit-this-value.any.js @@ -0,0 +1,85 @@ +// META: global=window,worker + +// https://webidl.spec.whatwg.org/#dfn-attribute-getter (step 1.1.2.1) +// https://webidl.spec.whatwg.org/#dfn-attribute-setter (step 4.5.1) +// https://webidl.spec.whatwg.org/#dfn-create-operation-function (step 2.1.2.1) + +const notGlobalObject = Object.create(Object.getPrototypeOf(globalThis)); + +test(() => { + assert_throws_js(TypeError, () => { Object.create(globalThis).self; }); + assert_throws_js(TypeError, () => { getGlobalPropertyDescriptor("location").get.call(notGlobalObject); }); + assert_throws_js(TypeError, () => { Reflect.get(globalThis, "navigator", notGlobalObject); }); + assert_throws_js(TypeError, () => { new Proxy(globalThis, {}).onerror; }); +}, "Global object's getter throws when called on incompatible object"); + +test(() => { + assert_throws_js(TypeError, () => { Object.create(globalThis).origin = origin; }); + assert_throws_js(TypeError, () => { getGlobalPropertyDescriptor("onerror").set.call(notGlobalObject, onerror); }); + assert_throws_js(TypeError, () => { Reflect.set(globalThis, "onoffline", onoffline, notGlobalObject); }); + assert_throws_js(TypeError, () => { new Proxy(globalThis, {}).ononline = ononline; }); +}, "Global object's setter throws when called on incompatible object"); + +test(() => { + assert_throws_js(TypeError, () => { Object.create(globalThis).setInterval(() => {}, 100); }); + assert_throws_js(TypeError, () => { clearTimeout.call(notGlobalObject, () => {}); }); + assert_throws_js(TypeError, () => { Reflect.apply(btoa, notGlobalObject, [""]); }); + assert_throws_js(TypeError, () => { new Proxy(globalThis, {}).removeEventListener("foo", () => {}); }); +}, "Global object's operation throws when called on incompatible object"); + +if (typeof document !== "undefined") { + test(() => { + assert_throws_js(TypeError, () => { Object.getOwnPropertyDescriptor(window, "document").get.call(document.all); }); + }, "Global object's getter throws when called on incompatible object (document.all)"); + + test(() => { + assert_throws_js(TypeError, () => { Object.getOwnPropertyDescriptor(window, "name").set.call(document.all); }); + }, "Global object's setter throws when called on incompatible object (document.all)"); + + test(() => { + assert_throws_js(TypeError, () => { focus.call(document.all); }); + }, "Global object's operation throws when called on incompatible object (document.all)"); +} + +// An engine might have different code path for calling a function from outer scope to implement step 1.b.iii of https://tc39.es/ecma262/#sec-evaluatecall +const locationGetter = getGlobalPropertyDescriptor("location").get; +test(() => { + assert_equals(getGlobalPropertyDescriptor("self").get.call(null), self); + assert_equals((() => locationGetter())(), location); + assert_equals(Reflect.get(globalThis, "origin", null), origin); + assert_equals(Reflect.get(globalThis, "onoffline", undefined), onoffline); +}, "Global object's getter works when called on null / undefined"); + +test(() => { + const fn = () => {}; + + // origin is [Replaceable] + getGlobalPropertyDescriptor("origin").set.call(null, "foo"); + assert_equals(origin, "foo"); + getGlobalPropertyDescriptor("onerror").set.call(undefined, fn); + assert_equals(onerror, fn); + assert_true(Reflect.set(globalThis, "onoffline", fn, null)); + assert_equals(onoffline, fn); + + const ononlineSetter = getGlobalPropertyDescriptor("ononline").set; + (() => { ononlineSetter(fn); })(); + assert_equals(ononline, fn); +}, "Global object's setter works when called on null / undefined"); + +// An engine might have different code path for calling a function from outer scope to implement step 1.b.iii of https://tc39.es/ecma262/#sec-evaluatecall +const __addEventListener = addEventListener; +test(() => { + assert_equals(atob.call(null, ""), ""); + assert_equals(typeof (0, setInterval)(() => {}, 100), "number"); + + (() => { __addEventListener("foo", event => { event.preventDefault(); }); })(); + const __dispatchEvent = dispatchEvent; + (() => { assert_false(__dispatchEvent(new Event("foo", { cancelable: true }))); })(); +}, "Global object's operation works when called on null / undefined"); + +function getGlobalPropertyDescriptor(key) { + for (let obj = globalThis; obj; obj = Object.getPrototypeOf(obj)) { + const desc = Object.getOwnPropertyDescriptor(obj, key); + if (desc) return desc; + } +} diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/has-instance.html b/test/fixtures/wpt/webidl/ecmascript-binding/has-instance.html new file mode 100644 index 00000000000000..caf0be47290607 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/has-instance.html @@ -0,0 +1,26 @@ + + +instanceof behavior + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/interface-object-set-receiver.html b/test/fixtures/wpt/webidl/ecmascript-binding/interface-object-set-receiver.html new file mode 100644 index 00000000000000..ca75a96bbad52e --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/interface-object-set-receiver.html @@ -0,0 +1,37 @@ + + +window.Interface is defined on [[Set]] receiver + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/interface-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/interface-object.html new file mode 100644 index 00000000000000..132c61ddaed4a3 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/interface-object.html @@ -0,0 +1,28 @@ + + +Interface objects + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-constructor-set-receiver.html b/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-constructor-set-receiver.html new file mode 100644 index 00000000000000..64a2da8eb2da2d --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-constructor-set-receiver.html @@ -0,0 +1,36 @@ + + +Interface.prototype.constructor is defined on [[Set]] receiver + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-object.html new file mode 100644 index 00000000000000..299bcf926dc23d --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/interface-prototype-object.html @@ -0,0 +1,15 @@ + + +Interface prototype objects + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/invalid-this-value-cross-realm.html b/test/fixtures/wpt/webidl/ecmascript-binding/invalid-this-value-cross-realm.html new file mode 100644 index 00000000000000..0535115ac61f43 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/invalid-this-value-cross-realm.html @@ -0,0 +1,45 @@ + + +Cross-realm getter / setter / operation doesn't use lexical global object to throw an error for incompatible |this| value + + + + + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/iterator-invalidation-foreach.html b/test/fixtures/wpt/webidl/ecmascript-binding/iterator-invalidation-foreach.html new file mode 100644 index 00000000000000..9d2e3b9cb25ce6 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/iterator-invalidation-foreach.html @@ -0,0 +1,40 @@ + + +Behavior of iterators when modified within foreach + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/iterator-prototype-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/iterator-prototype-object.html new file mode 100644 index 00000000000000..7859c1e46ac464 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/iterator-prototype-object.html @@ -0,0 +1,47 @@ + + +Iterator prototype objects + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-callback-interface-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-callback-interface-object.html new file mode 100644 index 00000000000000..627d29507f7dad --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-callback-interface-object.html @@ -0,0 +1,69 @@ + + +Legacy callback interface objects + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factor-function-subclass.window.js b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factor-function-subclass.window.js new file mode 100644 index 00000000000000..1fd64f41bb2e8e --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factor-function-subclass.window.js @@ -0,0 +1,13 @@ +"use strict"; + +test(() => { + class CustomImage extends Image {} + var instance = new CustomImage(); + + assert_equals( + Object.getPrototypeOf(instance), CustomImage.prototype, + "Object.getPrototypeOf(instance) === CustomImage.prototype"); + + assert_true(instance instanceof CustomImage, "instance instanceof CustomImage"); + assert_true(instance instanceof HTMLImageElement, "instance instanceof HTMLImageElement"); +}, "[LegacyFactoryFunction] can be subclassed and correctly handles NewTarget"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factory-function-builtin-properties.window.js b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factory-function-builtin-properties.window.js new file mode 100644 index 00000000000000..fc5c48aca380c0 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-factory-function-builtin-properties.window.js @@ -0,0 +1,6 @@ +"use strict"; + +test(() => { + const ownPropKeys = Reflect.ownKeys(Image).slice(0, 3); + assert_array_equals(ownPropKeys, ["length", "name", "prototype"]); +}, 'Legacy factory function property enumeration order of "length", "name", and "prototype"'); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/DefineOwnProperty.html b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/DefineOwnProperty.html new file mode 100644 index 00000000000000..bd7ba19c1a90b6 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/DefineOwnProperty.html @@ -0,0 +1,165 @@ + + +Legacy platform objects [[DefineOwnProperty]] method + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/GetOwnProperty.html b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/GetOwnProperty.html new file mode 100644 index 00000000000000..be3bcc61f0a3aa --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/GetOwnProperty.html @@ -0,0 +1,84 @@ + + +Legacy platform objects [[GetOwnProperty]] method + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/OwnPropertyKeys.html b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/OwnPropertyKeys.html new file mode 100644 index 00000000000000..d33980517b1a94 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/OwnPropertyKeys.html @@ -0,0 +1,65 @@ + + +Legacy platform objects [[OwnPropertyKeys]] method + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/Set.html b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/Set.html new file mode 100644 index 00000000000000..1390b51cd03b51 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/Set.html @@ -0,0 +1,94 @@ + + +Legacy platform objects [[Set]] method + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/helper.js b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/helper.js new file mode 100644 index 00000000000000..01c1d00694eb9b --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/legacy-platform-object/helper.js @@ -0,0 +1,22 @@ +function assert_prop_desc_equals(object, property_key, expected) { + let actual = Object.getOwnPropertyDescriptor(object, property_key); + if (expected === undefined) { + assert_equals( + actual, undefined, + "(assert_prop_desc_equals: no property descriptor expected)"); + return; + } + for (p in actual) { + assert_true( + expected.hasOwnProperty(p), + "(assert_prop_desc_equals: property '" + p + "' is not expected)"); + assert_equals( + actual[p], expected[p], + "(assert_prop_desc_equals: property '" + p + "')"); + } + for (p in expected) { + assert_true( + actual.hasOwnProperty(p), + "(assert_prop_desc_equals: expected property '" + p + "' missing)"); + } +} diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/no-regexp-special-casing.any.js b/test/fixtures/wpt/webidl/ecmascript-binding/no-regexp-special-casing.any.js new file mode 100644 index 00000000000000..4446dbf69c02ab --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/no-regexp-special-casing.any.js @@ -0,0 +1,47 @@ +"use strict"; +// RegExps used to be special-cased in Web IDL, but that was removed in +// https://github.com/heycam/webidl/commit/bbb2bde. These tests check that implementations no longer +// do any such special-casing. + +test(() => { + const regExp = new RegExp(); + regExp.message = "some message"; + + const errorEvent = new ErrorEvent("type", regExp); + + assert_equals(errorEvent.message, "some message"); +}, "Conversion to a dictionary works"); + +test(() => { + const messageChannel = new MessageChannel(); + const regExp = new RegExp(); + regExp[Symbol.iterator] = function* () { + yield messageChannel.port1; + }; + + const messageEvent = new MessageEvent("type", { ports: regExp }); + + assert_array_equals(messageEvent.ports, [messageChannel.port1]); +}, "Conversion to a sequence works"); + +promise_test(async () => { + const regExp = new RegExp(); + + const response = new Response(regExp); + + assert_equals(await response.text(), "/(?:)/"); +}, "Can convert a RegExp to a USVString"); + +test(() => { + let functionCalled = false; + + const regExp = new RegExp(); + regExp.handleEvent = () => { + functionCalled = true; + }; + + self.addEventListener("testevent", regExp); + self.dispatchEvent(new Event("testevent")); + + assert_true(functionCalled); +}, "Can be used as an object implementing a callback interface"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-no-leak-of-internals.window.js b/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-no-leak-of-internals.window.js new file mode 100644 index 00000000000000..f93464005d017f --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-no-leak-of-internals.window.js @@ -0,0 +1,18 @@ +"use strict"; + +test(() => { + const observableArray = document.adoptedStyleSheets; + + let leaked_target = null; + let leaked_handler = null; + + let target_leaker = (target) => { leaked_target = target; return null; }; + Object.defineProperty(Object.prototype, "getPrototypeOf", {get: function() { + leaked_handler = this; + return target_leaker; + }}) + Object.getPrototypeOf(observableArray); + + assert_equals(leaked_target, null, "The proxy target leaked."); + assert_equals(leaked_handler, null, "The proxy handler leaked."); +}, "ObservableArray's internals won't leak"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-ownkeys.window.js b/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-ownkeys.window.js new file mode 100644 index 00000000000000..29b537c4750a38 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/observable-array-ownkeys.window.js @@ -0,0 +1,34 @@ +"use strict"; + +test(() => { + const observableArray = document.adoptedStyleSheets; + assert_array_equals( + Object.getOwnPropertyNames(observableArray), + ["length"], + "Initially only \"length\"."); + + observableArray["zzz"] = true; + observableArray["aaa"] = true; + assert_array_equals( + Object.getOwnPropertyNames(observableArray), + ["length", "zzz", "aaa"], + "Own properties whose key is a string have been added."); + + observableArray[0] = new CSSStyleSheet(); + observableArray[1] = new CSSStyleSheet(); + assert_array_equals( + Object.getOwnPropertyNames(observableArray), + ["0", "1", "length", "zzz", "aaa"], + "Own properties whose key is an array index have been added."); + + observableArray[Symbol.toStringTag] = "string_tag"; + observableArray[Symbol.toPrimitive] = "primitive"; + assert_array_equals( + Object.getOwnPropertyNames(observableArray), + ["0", "1", "length", "zzz", "aaa"], + "Own properties whose key is a symbol have been added (non-symbol)."); + assert_array_equals( + Object.getOwnPropertySymbols(observableArray), + [Symbol.toStringTag, Symbol.toPrimitive], + "Own properties whose key is a symbol have been added (symbol)."); +}, "ObservableArray's ownKeys trap"); diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/put-forwards.html b/test/fixtures/wpt/webidl/ecmascript-binding/put-forwards.html new file mode 100644 index 00000000000000..7d99d65aa21385 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/put-forwards.html @@ -0,0 +1,148 @@ + + +[PutForwards] behavior + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/replaceable-setter-throws-if-defineownproperty-fails.html b/test/fixtures/wpt/webidl/ecmascript-binding/replaceable-setter-throws-if-defineownproperty-fails.html new file mode 100644 index 00000000000000..872bbff9604265 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/replaceable-setter-throws-if-defineownproperty-fails.html @@ -0,0 +1,38 @@ + + +[Replaceable] setter throws TypeError if [[DefineOwnProperty]] fails + + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/sequence-conversion.html b/test/fixtures/wpt/webidl/ecmascript-binding/sequence-conversion.html new file mode 100644 index 00000000000000..40764e9f577603 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/sequence-conversion.html @@ -0,0 +1,157 @@ + + +Sequence conversion + + + + + + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/setter-argument.html b/test/fixtures/wpt/webidl/ecmascript-binding/setter-argument.html new file mode 100644 index 00000000000000..bfa4291b236533 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/setter-argument.html @@ -0,0 +1,176 @@ + + +Setter should treat no arguments as undefined + + + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/support/constructors-support.html b/test/fixtures/wpt/webidl/ecmascript-binding/support/constructors-support.html new file mode 100644 index 00000000000000..3b2616170b1d4f --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/support/constructors-support.html @@ -0,0 +1,8 @@ + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/support/create-realm.js b/test/fixtures/wpt/webidl/ecmascript-binding/support/create-realm.js new file mode 100644 index 00000000000000..45ded884fc1f22 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/support/create-realm.js @@ -0,0 +1,12 @@ +"use strict"; + +function createRealm(t) { + return new Promise(resolve => { + const iframe = document.createElement("iframe"); + t.add_cleanup(() => { iframe.remove(); }); + iframe.onload = () => { resolve(iframe.contentWindow); }; + iframe.name = "dummy"; + iframe.src = "support/dummy-iframe.html"; + document.body.append(iframe); + }); +} diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/support/dummy-iframe.html b/test/fixtures/wpt/webidl/ecmascript-binding/support/dummy-iframe.html new file mode 100644 index 00000000000000..3f773ae6f811ac --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/support/dummy-iframe.html @@ -0,0 +1,7 @@ + + +foo + + diff --git a/test/fixtures/wpt/webidl/ecmascript-binding/window-named-properties-object.html b/test/fixtures/wpt/webidl/ecmascript-binding/window-named-properties-object.html new file mode 100644 index 00000000000000..cc4976890683f4 --- /dev/null +++ b/test/fixtures/wpt/webidl/ecmascript-binding/window-named-properties-object.html @@ -0,0 +1,284 @@ + + +Internal methods of Window's named properties object + + + + + + diff --git a/test/fixtures/wpt/webidl/idlharness.any.js b/test/fixtures/wpt/webidl/idlharness.any.js new file mode 100644 index 00000000000000..f8b285c485c43a --- /dev/null +++ b/test/fixtures/wpt/webidl/idlharness.any.js @@ -0,0 +1,17 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: global=window,dedicatedworker,shadowrealm-in-window + +"use strict"; + +idl_test( + ['webidl'], + [], + idl_array => { + idl_array.add_objects({ + DOMException: ['new DOMException()', + 'new DOMException("my message")', + 'new DOMException("my message", "myName")'] + }); + } +); diff --git a/test/wpt/status/webidl.json b/test/wpt/status/webidl.json new file mode 100644 index 00000000000000..b29a000a9d8b92 --- /dev/null +++ b/test/wpt/status/webidl.json @@ -0,0 +1,70 @@ +{ + "ecmascript-binding/class-string-named-properties-object.window.js": { + "fail": { + "expected": [ + "evaluation in WPTRunner.runJsTests()" + ] + } + }, + "ecmascript-binding/global-immutable-prototype.any.js": { + "fail": { + "expected": [ + "Setting to a different prototype" + ] + } + }, + "ecmascript-binding/global-mutable-prototype.any.js": { + "fail": { + "expected": [ + "Setting to a different prototype" + ] + } + }, + "ecmascript-binding/global-object-implicit-this-value.any.js": { + "fail": { + "expected": [ + "Global object's getter throws when called on incompatible object", + "Global object's setter throws when called on incompatible object", + "Global object's operation throws when called on incompatible object", + "Global object's getter works when called on null / undefined", + "Global object's setter works when called on null / undefined", + "evaluation in WPTRunner.runJsTests()" + ] + } + }, + "ecmascript-binding/legacy-factor-function-subclass.window.js": { + "fail": { + "expected": [ + "[LegacyFactoryFunction] can be subclassed and correctly handles NewTarget" + ] + } + }, + "ecmascript-binding/legacy-factory-function-builtin-properties.window.js": { + "fail": { + "expected": [ + "Legacy factory function property enumeration order of \"length\", \"name\", and \"prototype\"" + ] + } + }, + "ecmascript-binding/no-regexp-special-casing.any.js": { + "fail": { + "expected": [ + "Can be used as an object implementing a callback interface" + ] + } + }, + "ecmascript-binding/observable-array-no-leak-of-internals.window.js": { + "fail": { + "expected": [ + "ObservableArray's internals won't leak" + ] + } + }, + "ecmascript-binding/observable-array-ownkeys.window.js": { + "fail": { + "expected": [ + "ObservableArray's ownKeys trap" + ] + } + } +} diff --git a/test/wpt/test-webidl.js b/test/wpt/test-webidl.js new file mode 100644 index 00000000000000..682616608ea169 --- /dev/null +++ b/test/wpt/test-webidl.js @@ -0,0 +1,8 @@ +'use strict'; + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('webidl'); + +runner.runJsTests();