diff --git a/packages/happy-dom/src/query-selector/QuerySelector.ts b/packages/happy-dom/src/query-selector/QuerySelector.ts index e6fb311ec..3a7b60c80 100644 --- a/packages/happy-dom/src/query-selector/QuerySelector.ts +++ b/packages/happy-dom/src/query-selector/QuerySelector.ts @@ -16,6 +16,11 @@ type IDocumentPositionAndElement = { element: IElement; }; +/** + * Invalid Selector RegExp. + */ +const INVALID_SELECTOR_REGEXP = /^[.#\[]?\d/; + /** * Utility for query selection in an HTML element. * @@ -35,7 +40,7 @@ export default class QuerySelector { ): INodeList { if (selector === '') { throw new Error( - "Failed to execute 'querySelectorAll' on 'Element': The provided selector is empty." + `Failed to execute 'querySelectorAll' on '${node.constructor.name}': The provided selector is empty.` ); } @@ -43,11 +48,9 @@ export default class QuerySelector { return new NodeList(); } - if (/^[.#\[]?\d/.test(selector)) { + if (INVALID_SELECTOR_REGEXP.test(selector)) { throw new Error( - "Failed to execute 'querySelectorAll' on 'Element': '" + - selector + - "' is not a valid selector." + `Failed to execute 'querySelectorAll' on '${node.constructor.name}': '${selector}' is not a valid selector.` ); } @@ -87,10 +90,10 @@ export default class QuerySelector { public static querySelector( node: IElement | IDocument | IDocumentFragment, selector: string - ): IElement { + ): IElement | null { if (selector === '') { throw new Error( - "Failed to execute 'querySelector' on 'Element': The provided selector is empty." + `Failed to execute 'querySelector' on '${node.constructor.name}': The provided selector is empty.` ); } @@ -98,11 +101,9 @@ export default class QuerySelector { return null; } - if (/^[.#\[]?\d/.test(selector)) { + if (INVALID_SELECTOR_REGEXP.test(selector)) { throw new Error( - "Failed to execute 'querySelector' on 'Element': '" + - selector + - "' is not a valid selector." + `Failed to execute 'querySelector' on '${node.constructor.name}': '${selector}' is not a valid selector.` ); } @@ -128,12 +129,22 @@ export default class QuerySelector { * @returns Result. */ public static match(element: IElement, selector: string): ISelectorMatch | null { + if (!selector) { + return null; + } + if (selector === '*') { return { priorityWeight: 1 }; } + if (INVALID_SELECTOR_REGEXP.test(selector)) { + throw new Error( + `Failed to execute 'match' on '${element.constructor.name}': '${selector}' is not a valid selector.` + ); + } + for (const items of SelectorParser.getSelectorGroups(selector)) { const result = this.matchSelector(element, element, items.reverse()); diff --git a/packages/happy-dom/test/query-selector/QuerySelector.test.ts b/packages/happy-dom/test/query-selector/QuerySelector.test.ts index b21df10c0..caa3d1445 100644 --- a/packages/happy-dom/test/query-selector/QuerySelector.test.ts +++ b/packages/happy-dom/test/query-selector/QuerySelector.test.ts @@ -975,6 +975,22 @@ describe('QuerySelector', () => { expect(elements.length).toBe(0); }); + + it('Throws an error when providing an invalid selector', () => { + const div = document.createElement('div'); + expect(() => div.querySelectorAll('1')).toThrowError( + "Failed to execute 'querySelectorAll' on 'HTMLElement': '1' is not a valid selector." + ); + expect(() => div.querySelectorAll('[1')).toThrowError( + "Failed to execute 'querySelectorAll' on 'HTMLElement': '[1' is not a valid selector." + ); + expect(() => div.querySelectorAll('.1')).toThrowError( + "Failed to execute 'querySelectorAll' on 'HTMLElement': '.1' is not a valid selector." + ); + expect(() => div.querySelectorAll('#1')).toThrowError( + "Failed to execute 'querySelectorAll' on 'HTMLElement': '#1' is not a valid selector." + ); + }); }); describe('querySelector', () => { @@ -1127,35 +1143,19 @@ describe('QuerySelector', () => { expect(element2 === div.children[0]).toBe(true); }); - it('querySelector Trhow an error when provide selector is a invalid value', () => { + it('Throws an error when providing an invalid selector', () => { const div = document.createElement('div'); expect(() => div.querySelector('1')).toThrowError( - "Failed to execute 'querySelector' on 'Element': '1' is not a valid selector." + "Failed to execute 'querySelector' on 'HTMLElement': '1' is not a valid selector." ); expect(() => div.querySelector('[1')).toThrowError( - "Failed to execute 'querySelector' on 'Element': '[1' is not a valid selector." + "Failed to execute 'querySelector' on 'HTMLElement': '[1' is not a valid selector." ); expect(() => div.querySelector('.1')).toThrowError( - "Failed to execute 'querySelector' on 'Element': '.1' is not a valid selector." + "Failed to execute 'querySelector' on 'HTMLElement': '.1' is not a valid selector." ); expect(() => div.querySelector('#1')).toThrowError( - "Failed to execute 'querySelector' on 'Element': '#1' is not a valid selector." - ); - }); - - it('querySelectorAll Trhow an error when provide selector is a invalid value', () => { - const div = document.createElement('div'); - expect(() => div.querySelectorAll('1')).toThrowError( - "Failed to execute 'querySelectorAll' on 'Element': '1' is not a valid selector." - ); - expect(() => div.querySelectorAll('[1')).toThrowError( - "Failed to execute 'querySelectorAll' on 'Element': '[1' is not a valid selector." - ); - expect(() => div.querySelectorAll('.1')).toThrowError( - "Failed to execute 'querySelectorAll' on 'Element': '.1' is not a valid selector." - ); - expect(() => div.querySelectorAll('#1')).toThrowError( - "Failed to execute 'querySelectorAll' on 'Element': '#1' is not a valid selector." + "Failed to execute 'querySelector' on 'HTMLElement': '#1' is not a valid selector." ); }); });