diff --git a/packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts b/packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts index 9e4a59af4..4d564aaf5 100644 --- a/packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts +++ b/packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts @@ -13,12 +13,10 @@ export default class HTMLElementUtility { * @param element Element. */ public static blur(element: HTMLElement | SVGElement): void { - const document = element[PropertySymbol.ownerDocument]; + const target = element[PropertySymbol.proxy] || element; + const document = target[PropertySymbol.ownerDocument]; - if ( - document[PropertySymbol.activeElement] !== element || - !element[PropertySymbol.isConnected] - ) { + if (document[PropertySymbol.activeElement] !== target || !target[PropertySymbol.isConnected]) { return; } @@ -28,7 +26,7 @@ export default class HTMLElementUtility { document[PropertySymbol.clearCache](); - element.dispatchEvent( + target.dispatchEvent( new FocusEvent('blur', { relatedTarget, bubbles: false, @@ -36,7 +34,7 @@ export default class HTMLElementUtility { cancelable: true }) ); - element.dispatchEvent( + target.dispatchEvent( new FocusEvent('focusout', { relatedTarget, bubbles: true, @@ -52,17 +50,15 @@ export default class HTMLElementUtility { * @param element Element. */ public static focus(element: HTMLElement | SVGElement): void { - const document = element[PropertySymbol.ownerDocument]; + const target = element[PropertySymbol.proxy] || element; + const document = target[PropertySymbol.ownerDocument]; - if ( - document[PropertySymbol.activeElement] === element || - !element[PropertySymbol.isConnected] - ) { + if (document[PropertySymbol.activeElement] === target || !target[PropertySymbol.isConnected]) { return; } // Set the next active element so `blur` can use it for `relatedTarget`. - document[PropertySymbol.nextActiveElement] = element; + document[PropertySymbol.nextActiveElement] = target; const relatedTarget = document[PropertySymbol.activeElement]; @@ -73,18 +69,18 @@ export default class HTMLElementUtility { // Clean up after blur, so it does not affect next blur call. document[PropertySymbol.nextActiveElement] = null; - document[PropertySymbol.activeElement] = element; + document[PropertySymbol.activeElement] = target; document[PropertySymbol.clearCache](); - element.dispatchEvent( + target.dispatchEvent( new FocusEvent('focus', { relatedTarget, bubbles: false, composed: true }) ); - element.dispatchEvent( + target.dispatchEvent( new FocusEvent('focusin', { relatedTarget, bubbles: true, diff --git a/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts b/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts index 25434e967..fff4f1372 100644 --- a/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts +++ b/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts @@ -644,6 +644,16 @@ describe('HTMLSelectElement', () => { }); }); + describe('focus()', () => { + it('Should set Document.activeElement to the proxy.', () => { + document.body.appendChild(element); + element.focus(); + expect(document.activeElement).toBe(element); + element.blur(); + expect(document.activeElement).toBe(document.body); + }); + }); + for (const method of ['checkValidity', 'reportValidity']) { describe(`${method}()`, () => { it('Returns "true" if the field is "disabled".', () => {