From 73a3672ca65c4cdf040a02cecccf0d59cc5e49aa Mon Sep 17 00:00:00 2001 From: David Ortner Date: Tue, 25 Feb 2025 00:49:11 +0100 Subject: [PATCH] fix: [#1614] Fixes issue where change event wasn't triggered for an input inside of a label (#1743) * fix: [#1605] Fixes issue when using filtering in TreeWalker, which caused it not to work according to spec * fix: [#1605] Fixes issue when using filtering in TreeWalker, which caused it not to work according to spec * chore: [#1614] Fixes issue where input change event wasnt triggered when clicking on an element inside of a label * chore: [#1614] Fixes issue where input change event wasnt triggered when clicking on an element inside of a label --- .../html-label-element/HTMLLabelElement.ts | 3 +- .../HTMLLabelElement.test.ts | 40 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) 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 3f5e79754..302c7d330 100644 --- a/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts +++ b/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts @@ -113,7 +113,8 @@ export default class HTMLLabelElement extends HTMLElement { if ( !event[PropertySymbol.defaultPrevented] && event.type === 'click' && - event.eventPhase === EventPhaseEnum.none && + (event.eventPhase === EventPhaseEnum.atTarget || + event.eventPhase === EventPhaseEnum.bubbling) && event instanceof MouseEvent ) { const control = this.control; 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 0809f314b..2aa1b31e3 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 @@ -2,7 +2,6 @@ import Window from '../../../src/window/Window.js'; import Document from '../../../src/nodes/document/Document.js'; import HTMLLabelElement from '../../../src/nodes/html-label-element/HTMLLabelElement.js'; 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'; @@ -171,5 +170,44 @@ describe('HTMLLabelElement', () => { expect(input.checked).toBe(false); expect(inputClickCount).toBe(0); }); + + it('It triggers "change" event on the control element when clicking on a span inside the label.', () => { + const div = document.createElement('div'); + div.innerHTML = ` + + `; + let isChangeFired = false; + + document.body.appendChild(div); + + div.querySelector('input')?.addEventListener('change', () => (isChangeFired = true)); + + div.querySelector('span')?.click(); + + expect(isChangeFired).toBe(true); + }); + + it('Doesn\'t trigger "change" event a second time when clicking on control element inside of a label.', () => { + const div = document.createElement('div'); + div.innerHTML = ` + + `; + let changeFiredCount = 0; + + document.body.appendChild(div); + + div.querySelector('input')?.addEventListener('change', () => changeFiredCount++); + + div.querySelector('input')?.click(); + + expect(changeFiredCount).toBe(1); + expect(div.querySelector('input')?.checked).toBe(true); + }); }); });