diff --git a/.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch b/.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch new file mode 100644 index 00000000..6d44a423 --- /dev/null +++ b/.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch @@ -0,0 +1,255 @@ +diff --git a/lib/jsdom/living/events/SubmitEvent-impl.js b/lib/jsdom/living/events/SubmitEvent-impl.js +new file mode 100644 +index 0000000000000000000000000000000000000000..2a9886e1369c7f6ee55abe697cb3b870034bee06 +--- /dev/null ++++ b/lib/jsdom/living/events/SubmitEvent-impl.js +@@ -0,0 +1,13 @@ ++"use strict"; ++ ++const EventImpl = require("./Event-impl").implementation; ++ ++const SubmitEventInit = require("../generated/SubmitEventInit"); ++ ++// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-submitevent-interface ++class SubmitEventImpl extends EventImpl {} ++SubmitEventImpl.defaultInit = SubmitEventInit.convert(undefined, undefined); ++ ++module.exports = { ++ implementation: SubmitEventImpl ++}; +diff --git a/lib/jsdom/living/generated/SubmitEvent.js b/lib/jsdom/living/generated/SubmitEvent.js +new file mode 100644 +index 0000000000000000000000000000000000000000..c35c4083d4ca58a3bedffd5621cc602ff97043e7 +--- /dev/null ++++ b/lib/jsdom/living/generated/SubmitEvent.js +@@ -0,0 +1,144 @@ ++"use strict"; ++ ++const conversions = require("webidl-conversions"); ++const utils = require("./utils.js"); ++ ++const SubmitEventInit = require("./SubmitEventInit.js"); ++const implSymbol = utils.implSymbol; ++const ctorRegistrySymbol = utils.ctorRegistrySymbol; ++const Event = require("./Event.js"); ++ ++const interfaceName = "SubmitEvent"; ++ ++exports.is = value => { ++ return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation; ++}; ++exports.isImpl = value => { ++ return utils.isObject(value) && value instanceof Impl.implementation; ++}; ++exports.convert = (globalObject, value, { context = "The provided value" } = {}) => { ++ if (exports.is(value)) { ++ return utils.implForWrapper(value); ++ } ++ throw new globalObject.TypeError(`${context} is not of type 'SubmitEvent'.`); ++}; ++ ++function makeWrapper(globalObject, newTarget) { ++ let proto; ++ if (newTarget !== undefined) { ++ proto = newTarget.prototype; ++ } ++ ++ if (!utils.isObject(proto)) { ++ proto = globalObject[ctorRegistrySymbol]["SubmitEvent"].prototype; ++ } ++ ++ return Object.create(proto); ++} ++ ++exports.create = (globalObject, constructorArgs, privateData) => { ++ const wrapper = makeWrapper(globalObject); ++ return exports.setup(wrapper, globalObject, constructorArgs, privateData); ++}; ++ ++exports.createImpl = (globalObject, constructorArgs, privateData) => { ++ const wrapper = exports.create(globalObject, constructorArgs, privateData); ++ return utils.implForWrapper(wrapper); ++}; ++ ++exports._internalSetup = (wrapper, globalObject) => { ++ Event._internalSetup(wrapper, globalObject); ++}; ++ ++exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => { ++ privateData.wrapper = wrapper; ++ ++ exports._internalSetup(wrapper, globalObject); ++ Object.defineProperty(wrapper, implSymbol, { ++ value: new Impl.implementation(globalObject, constructorArgs, privateData), ++ configurable: true ++ }); ++ ++ wrapper[implSymbol][utils.wrapperSymbol] = wrapper; ++ if (Impl.init) { ++ Impl.init(wrapper[implSymbol]); ++ } ++ return wrapper; ++}; ++ ++exports.new = (globalObject, newTarget) => { ++ const wrapper = makeWrapper(globalObject, newTarget); ++ ++ exports._internalSetup(wrapper, globalObject); ++ Object.defineProperty(wrapper, implSymbol, { ++ value: Object.create(Impl.implementation.prototype), ++ configurable: true ++ }); ++ ++ wrapper[implSymbol][utils.wrapperSymbol] = wrapper; ++ if (Impl.init) { ++ Impl.init(wrapper[implSymbol]); ++ } ++ return wrapper[implSymbol]; ++}; ++ ++const exposed = new Set(["Window"]); ++ ++exports.install = (globalObject, globalNames) => { ++ if (!globalNames.some(globalName => exposed.has(globalName))) { ++ return; ++ } ++ ++ const ctorRegistry = utils.initCtorRegistry(globalObject); ++ class SubmitEvent extends globalObject.Event { ++ constructor(type) { ++ if (arguments.length < 1) { ++ throw new globalObject.TypeError( ++ `Failed to construct 'SubmitEvent': 1 argument required, but only ${arguments.length} present.` ++ ); ++ } ++ const args = []; ++ { ++ let curArg = arguments[0]; ++ curArg = conversions["DOMString"](curArg, { ++ context: "Failed to construct 'SubmitEvent': parameter 1", ++ globals: globalObject ++ }); ++ args.push(curArg); ++ } ++ { ++ let curArg = arguments[1]; ++ curArg = SubmitEventInit.convert(globalObject, curArg, { ++ context: "Failed to construct 'SubmitEvent': parameter 2" ++ }); ++ args.push(curArg); ++ } ++ return exports.setup(Object.create(new.target.prototype), globalObject, args); ++ } ++ ++ get submitter() { ++ const esValue = this !== null && this !== undefined ? this : globalObject; ++ ++ if (!exports.is(esValue)) { ++ throw new globalObject.TypeError( ++ "'get submitter' called on an object that is not a valid instance of SubmitEvent." ++ ); ++ } ++ ++ return utils.tryWrapperForImpl(esValue[implSymbol]["submitter"]); ++ } ++ } ++ Object.defineProperties(SubmitEvent.prototype, { ++ submitter: { enumerable: true }, ++ [Symbol.toStringTag]: { value: "SubmitEvent", configurable: true } ++ }); ++ ctorRegistry[interfaceName] = SubmitEvent; ++ ++ Object.defineProperty(globalObject, interfaceName, { ++ configurable: true, ++ writable: true, ++ value: SubmitEvent ++ }); ++}; ++ ++const Impl = require("../events/SubmitEvent-impl.js"); +diff --git a/lib/jsdom/living/generated/SubmitEventInit.js b/lib/jsdom/living/generated/SubmitEventInit.js +new file mode 100644 +index 0000000000000000000000000000000000000000..a911318c72571a1e4c8e866cb74e997c7744d461 +--- /dev/null ++++ b/lib/jsdom/living/generated/SubmitEventInit.js +@@ -0,0 +1,36 @@ ++"use strict"; ++ ++const conversions = require("webidl-conversions"); ++const utils = require("./utils.js"); ++ ++const HTMLElement = require("./HTMLElement.js"); ++const EventInit = require("./EventInit.js"); ++ ++exports._convertInherit = (globalObject, obj, ret, { context = "The provided value" } = {}) => { ++ EventInit._convertInherit(globalObject, obj, ret, { context }); ++ ++ { ++ const key = "submitter"; ++ let value = obj === undefined || obj === null ? undefined : obj[key]; ++ if (value !== undefined) { ++ if (value === null || value === undefined) { ++ value = null; ++ } else { ++ value = HTMLElement.convert(globalObject, value, { context: context + " has member 'submitter' that" }); ++ } ++ ret[key] = value; ++ } else { ++ ret[key] = null; ++ } ++ } ++}; ++ ++exports.convert = (globalObject, obj, { context = "The provided value" } = {}) => { ++ if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") { ++ throw new globalObject.TypeError(`${context} is not an object.`); ++ } ++ ++ const ret = Object.create(null); ++ exports._convertInherit(globalObject, obj, ret, { context }); ++ return ret; ++}; +diff --git a/lib/jsdom/living/interfaces.js b/lib/jsdom/living/interfaces.js +index d64eafb729fbe99e75ccc7697ecdd818d5a20f00..9c766b0dd08b13a322e8efe57ab137e84504b723 100644 +--- a/lib/jsdom/living/interfaces.js ++++ b/lib/jsdom/living/interfaces.js +@@ -130,6 +130,7 @@ const generatedInterfaces = { + StorageEvent: require("./generated/StorageEvent"), + ProgressEvent: require("./generated/ProgressEvent"), + PageTransitionEvent: require("./generated/PageTransitionEvent"), ++ SubmitEvent: require("./generated/SubmitEvent"), + + UIEvent: require("./generated/UIEvent"), + FocusEvent: require("./generated/FocusEvent"), +diff --git a/lib/jsdom/living/nodes/HTMLFormElement-impl.js b/lib/jsdom/living/nodes/HTMLFormElement-impl.js +index 1ab508a6f27445171b8143374ff1fae24f3bbfa6..d611fa3243e3c452d8625ba2c79c29a2b82e5e82 100644 +--- a/lib/jsdom/living/nodes/HTMLFormElement-impl.js ++++ b/lib/jsdom/living/nodes/HTMLFormElement-impl.js +@@ -9,6 +9,7 @@ const { formOwner, isListed, isSubmittable, isSubmitButton } = require("../helpe + const HTMLFormControlsCollection = require("../generated/HTMLFormControlsCollection"); + const notImplemented = require("../../browser/not-implemented"); + const { parseURLToResultingURLRecord } = require("../helpers/document-base-url"); ++const SubmitEvent = require("../generated/SubmitEvent"); + + const encTypes = new Set([ + "application/x-www-form-urlencoded", +@@ -87,8 +88,8 @@ class HTMLFormElementImpl extends HTMLElementImpl { + notImplemented("HTMLFormElement.prototype.submit", this._ownerDocument._defaultView); + } + +- requestSubmit(submitter = undefined) { +- if (submitter !== undefined) { ++ requestSubmit(submitter = null) { ++ if (submitter !== null) { + if (!isSubmitButton(submitter)) { + throw new TypeError("The specified element is not a submit button"); + } +@@ -106,7 +107,7 @@ class HTMLFormElementImpl extends HTMLElementImpl { + return; + } + +- if (!fireAnEvent("submit", this, undefined, { bubbles: true, cancelable: true })) { ++ if (!fireAnEvent("submit", this, SubmitEvent, { bubbles: true, cancelable: true, submitter })) { + return; + } + diff --git a/package.json b/package.json index 61be75a7..c0838567 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,8 @@ "resolutions": { "mq-polyfill@1.1.8": "patch:mq-polyfill@npm:1.1.8#.yarn/patches/mq-polyfill-npm-1.1.8-62fe162439.patch", "react-error-overlay": "6.0.9", - "react-dev-utils@^12.0.1": "patch:react-dev-utils@npm:12.0.1#.yarn/patches/react-dev-utils-npm-12.0.1-83ba06e3ee.patch" + "react-dev-utils@^12.0.1": "patch:react-dev-utils@npm:12.0.1#.yarn/patches/react-dev-utils-npm-12.0.1-83ba06e3ee.patch", + "jsdom@^20.0.0": "patch:jsdom@npm%3A20.0.0#./.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch" }, "jest": { "roots": [ diff --git a/yarn.lock b/yarn.lock index af95bee4..996393cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10923,7 +10923,7 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^20.0.0": +"jsdom@npm:20.0.0": version: 20.0.0 resolution: "jsdom@npm:20.0.0" dependencies: @@ -10963,6 +10963,46 @@ __metadata: languageName: node linkType: hard +"jsdom@patch:jsdom@npm%3A20.0.0#./.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch::locator=%40pybricks%2Fpybricks-code%40workspace%3A.": + version: 20.0.0 + resolution: "jsdom@patch:jsdom@npm%3A20.0.0#./.yarn/patches/jsdom-npm-20.0.0-9c1ad43ab8.patch::version=20.0.0&hash=37efc2&locator=%40pybricks%2Fpybricks-code%40workspace%3A." + dependencies: + abab: ^2.0.6 + acorn: ^8.7.1 + acorn-globals: ^6.0.0 + cssom: ^0.5.0 + cssstyle: ^2.3.0 + data-urls: ^3.0.2 + decimal.js: ^10.3.1 + domexception: ^4.0.0 + escodegen: ^2.0.0 + form-data: ^4.0.0 + html-encoding-sniffer: ^3.0.0 + http-proxy-agent: ^5.0.0 + https-proxy-agent: ^5.0.1 + is-potential-custom-element-name: ^1.0.1 + nwsapi: ^2.2.0 + parse5: ^7.0.0 + saxes: ^6.0.0 + symbol-tree: ^3.2.4 + tough-cookie: ^4.0.0 + w3c-hr-time: ^1.0.2 + w3c-xmlserializer: ^3.0.0 + webidl-conversions: ^7.0.0 + whatwg-encoding: ^2.0.0 + whatwg-mimetype: ^3.0.0 + whatwg-url: ^11.0.0 + ws: ^8.8.0 + xml-name-validator: ^4.0.0 + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 642f7fee80de51473cde95ce683d9c10ff7e97971dcb9b0cf1743d9ec49755c8fbaa3fecf23a6d54b2da1646234970aa0d30011620d381eb8b6fa465013d1966 + languageName: node + linkType: hard + "jsesc@npm:^2.5.1": version: 2.5.2 resolution: "jsesc@npm:2.5.2"