From d8732e89e41024efda5f9af258e5103da11ed825 Mon Sep 17 00:00:00 2001 From: David Ortner Date: Tue, 14 May 2024 00:27:26 +0200 Subject: [PATCH] fix: [#1397] HTMLAnchorElement, HTMLButtonElement, HTMLInputElement and HTMLLabelElement should check for if a dispatched click event is of type MouseEvent and not PointerEvent which the check previously checked for --- .../html-anchor-element/HTMLAnchorElement.ts | 4 +-- .../html-button-element/HTMLButtonElement.ts | 6 ++--- .../html-input-element/HTMLInputElement.ts | 10 ++++---- .../html-label-element/HTMLLabelElement.ts | 6 ++--- .../HTMLAnchorElement.test.ts | 3 ++- .../HTMLButtonElement.test.ts | 6 +++-- .../HTMLInputElement.test.ts | 7 +++--- .../HTMLLabelElement.test.ts | 25 +++++++++++++++++++ 8 files changed, 48 insertions(+), 19 deletions(-) diff --git a/packages/happy-dom/src/nodes/html-anchor-element/HTMLAnchorElement.ts b/packages/happy-dom/src/nodes/html-anchor-element/HTMLAnchorElement.ts index aed0a7c18..42146e045 100644 --- a/packages/happy-dom/src/nodes/html-anchor-element/HTMLAnchorElement.ts +++ b/packages/happy-dom/src/nodes/html-anchor-element/HTMLAnchorElement.ts @@ -7,7 +7,7 @@ import NamedNodeMap from '../../named-node-map/NamedNodeMap.js'; import HTMLAnchorElementNamedNodeMap from './HTMLAnchorElementNamedNodeMap.js'; import Event from '../../event/Event.js'; import EventPhaseEnum from '../../event/EventPhaseEnum.js'; -import PointerEvent from '../../event/events/PointerEvent.js'; +import MouseEvent from '../../event/events/MouseEvent.js'; /** * HTML Anchor Element. @@ -499,7 +499,7 @@ export default class HTMLAnchorElement extends HTMLElement implements IHTMLHyper if ( event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) && !event.defaultPrevented diff --git a/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts b/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts index 216daffd5..12c1b9f40 100644 --- a/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts +++ b/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts @@ -10,8 +10,8 @@ import HTMLLabelElement from '../html-label-element/HTMLLabelElement.js'; import Node from '../node/Node.js'; import NodeList from '../node/NodeList.js'; import HTMLButtonElementNamedNodeMap from './HTMLButtonElementNamedNodeMap.js'; -import PointerEvent from '../../event/events/PointerEvent.js'; import { URL } from 'url'; +import MouseEvent from '../../event/events/MouseEvent.js'; const BUTTON_TYPES = ['submit', 'reset', 'button', 'menu']; @@ -295,7 +295,7 @@ export default class HTMLButtonElement extends HTMLElement { public override dispatchEvent(event: Event): boolean { if ( event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && event.eventPhase === EventPhaseEnum.none && this.disabled ) { @@ -306,7 +306,7 @@ export default class HTMLButtonElement extends HTMLElement { if ( event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) && this[PropertySymbol.isConnected] diff --git a/packages/happy-dom/src/nodes/html-input-element/HTMLInputElement.ts b/packages/happy-dom/src/nodes/html-input-element/HTMLInputElement.ts index 566293ce0..d15b1820d 100644 --- a/packages/happy-dom/src/nodes/html-input-element/HTMLInputElement.ts +++ b/packages/happy-dom/src/nodes/html-input-element/HTMLInputElement.ts @@ -18,8 +18,8 @@ import HTMLInputElementDateUtility from './HTMLInputElementDateUtility.js'; import HTMLLabelElementUtility from '../html-label-element/HTMLLabelElementUtility.js'; import NamedNodeMap from '../../named-node-map/NamedNodeMap.js'; import HTMLInputElementNamedNodeMap from './HTMLInputElementNamedNodeMap.js'; -import PointerEvent from '../../event/events/PointerEvent.js'; import { URL } from 'url'; +import MouseEvent from '../../event/events/MouseEvent.js'; /** * HTML Input Element. @@ -1305,7 +1305,7 @@ export default class HTMLInputElement extends HTMLElement { // Do nothing if the input element is disabled and the event is a click event. if ( event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && event.eventPhase === EventPhaseEnum.none && this.disabled ) { @@ -1320,7 +1320,7 @@ export default class HTMLInputElement extends HTMLElement { (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) && event.type === 'click' && - event instanceof PointerEvent + event instanceof MouseEvent ) { const inputType = this.type; if (inputType === 'checkbox' || inputType === 'radio') { @@ -1336,7 +1336,7 @@ export default class HTMLInputElement extends HTMLElement { (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) && event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && this[PropertySymbol.isConnected] ) { const inputType = this.type; @@ -1364,7 +1364,7 @@ export default class HTMLInputElement extends HTMLElement { (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) && event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && previousCheckedValue !== null ) { const inputType = this.type; diff --git a/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts b/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts index 74833b03d..d448927c5 100644 --- a/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts +++ b/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts @@ -3,7 +3,7 @@ import * as PropertySymbol from '../../PropertySymbol.js'; import HTMLFormElement from '../html-form-element/HTMLFormElement.js'; import Event from '../../event/Event.js'; import EventPhaseEnum from '../../event/EventPhaseEnum.js'; -import PointerEvent from '../../event/events/PointerEvent.js'; +import MouseEvent from '../../event/events/MouseEvent.js'; /** * HTML Label Element. @@ -77,12 +77,12 @@ export default class HTMLLabelElement extends HTMLElement { if ( event.type === 'click' && - event instanceof PointerEvent && + event instanceof MouseEvent && (event.eventPhase === EventPhaseEnum.atTarget || event.eventPhase === EventPhaseEnum.bubbling) ) { const control = this.control; if (control && event.target !== control) { - control.dispatchEvent(new PointerEvent('click', { bubbles: true, cancelable: true })); + control.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); } } diff --git a/packages/happy-dom/test/nodes/html-anchor-element/HTMLAnchorElement.test.ts b/packages/happy-dom/test/nodes/html-anchor-element/HTMLAnchorElement.test.ts index 859ed565d..771d46f7d 100644 --- a/packages/happy-dom/test/nodes/html-anchor-element/HTMLAnchorElement.test.ts +++ b/packages/happy-dom/test/nodes/html-anchor-element/HTMLAnchorElement.test.ts @@ -7,6 +7,7 @@ import Request from '../../../src/fetch/Request.js'; import Response from '../../../src/fetch/Response.js'; import Fetch from '../../../src/fetch/Fetch.js'; import Browser from '../../../src/browser/Browser.js'; +import MouseEvent from '../../../src/event/events/MouseEvent.js'; describe('HTMLAnchorElement', () => { let window: Window; @@ -347,7 +348,7 @@ describe('HTMLAnchorElement', () => { const element = window.document.createElement('a'); element.href = 'https://www.example.com'; window.document.body.appendChild(element); - element.dispatchEvent(new PointerEvent('click')); + element.dispatchEvent(new MouseEvent('click')); const newWindow = page.mainFrame.window; diff --git a/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts b/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts index 8c1fe28cf..832b12dfc 100644 --- a/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts +++ b/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts @@ -7,6 +7,8 @@ import HTMLElement from '../../../src/nodes/html-element/HTMLElement.js'; import HTMLFormElement from '../../../src/nodes/html-form-element/HTMLFormElement.js'; import ValidityState from '../../../src/validity-state/ValidityState.js'; import { beforeEach, afterEach, describe, it, expect } from 'vitest'; +import MouseEvent from '../../../src/event/events/MouseEvent.js'; +import PointerEvent from '../../../src/event/events/PointerEvent.js'; describe('HTMLButtonElement', () => { let window: Window; @@ -352,7 +354,7 @@ describe('HTMLButtonElement', () => { submitter = (event).submitter; }); - button.click(); + button.dispatchEvent(new MouseEvent('click')); expect(submitTriggeredCount).toBe(1); expect(submitter).toBe(button); @@ -376,7 +378,7 @@ describe('HTMLButtonElement', () => { submitter = (event).submitter; }); - button.click(); + button.dispatchEvent(new PointerEvent('click')); expect(submitTriggeredCount).toBe(1); expect(submitter).toBe(button); diff --git a/packages/happy-dom/test/nodes/html-input-element/HTMLInputElement.test.ts b/packages/happy-dom/test/nodes/html-input-element/HTMLInputElement.test.ts index 8ea799d52..b0d2bddc6 100644 --- a/packages/happy-dom/test/nodes/html-input-element/HTMLInputElement.test.ts +++ b/packages/happy-dom/test/nodes/html-input-element/HTMLInputElement.test.ts @@ -12,6 +12,7 @@ import DOMExceptionNameEnum from '../../../src/exception/DOMExceptionNameEnum.js import SubmitEvent from '../../../src/event/events/SubmitEvent.js'; import { beforeEach, describe, it, expect } from 'vitest'; import PointerEvent from '../../../src/event/events/PointerEvent.js'; +import MouseEvent from '../../../src/event/events/MouseEvent.js'; describe('HTMLInputElement', () => { let window: Window; @@ -1150,7 +1151,7 @@ describe('HTMLInputElement', () => { element.addEventListener('change', () => (isChangeTriggered = true)); // "input" and "change" events should only be triggered if connected to DOM - element.dispatchEvent(new PointerEvent('click')); + element.dispatchEvent(new MouseEvent('click')); expect(isInputTriggered).toBe(false); expect(isChangeTriggered).toBe(false); @@ -1158,14 +1159,14 @@ describe('HTMLInputElement', () => { document.body.appendChild(element); - element.dispatchEvent(new PointerEvent('click')); + element.dispatchEvent(new MouseEvent('click')); // "input" and "change" events should now have been triggered as it is connected to DOM expect(isInputTriggered).toBe(true); expect(isChangeTriggered).toBe(true); expect(element.checked).toBe(false); - element.dispatchEvent(new PointerEvent('click')); + element.dispatchEvent(new MouseEvent('click')); expect(element.checked).toBe(true); }); diff --git a/packages/happy-dom/test/nodes/html-label-element/HTMLLabelElement.test.ts b/packages/happy-dom/test/nodes/html-label-element/HTMLLabelElement.test.ts index 88a61b1e7..0d685db9a 100644 --- a/packages/happy-dom/test/nodes/html-label-element/HTMLLabelElement.test.ts +++ b/packages/happy-dom/test/nodes/html-label-element/HTMLLabelElement.test.ts @@ -4,6 +4,7 @@ import HTMLLabelElement from '../../../src/nodes/html-label-element/HTMLLabelEle import HTMLInputElement from '../../../src/nodes/html-input-element/HTMLInputElement.js'; import PointerEvent from '../../../src/event/events/PointerEvent.js'; import { beforeEach, describe, it, expect } from 'vitest'; +import MouseEvent from '../../../src/event/events/MouseEvent.js'; describe('HTMLLabelElement', () => { let window: Window; @@ -103,5 +104,29 @@ describe('HTMLLabelElement', () => { expect(labelClickCount).toBe(2); expect(inputClickCount).toBe(1); }); + + it('Supports MouseEvent.', () => { + const input = document.createElement('input'); + const span = document.createElement('span'); + + input.type = 'checkbox'; + + span.appendChild(input); + element.appendChild(span); + + let labelClickCount = 0; + let inputClickCount = 0; + + element.addEventListener('click', () => labelClickCount++); + input.addEventListener('click', () => inputClickCount++); + + expect(input.checked).toBe(false); + + element.dispatchEvent(new MouseEvent('click')); + + expect(input.checked).toBe(true); + expect(labelClickCount).toBe(2); + expect(inputClickCount).toBe(1); + }); }); });