diff --git a/packages/happy-dom/src/query-selector/SelectorItem.ts b/packages/happy-dom/src/query-selector/SelectorItem.ts index a5aa0ead4..dc0b2389b 100644 --- a/packages/happy-dom/src/query-selector/SelectorItem.ts +++ b/packages/happy-dom/src/query-selector/SelectorItem.ts @@ -7,6 +7,7 @@ const ATTRIBUTE_NAME_REGEXP = /[^a-zA-Z0-9-_$]/; const PSUEDO_REGEXP = /:([a-zA-Z-]+)\(([0-9n+-]+|odd|even)\)|:not\(([^)]+)\)|:([a-zA-Z-]+)/g; const CLASS_REGEXP = /\.([a-zA-Z0-9-_$]+)/g; const TAG_NAME_REGEXP = /^[a-zA-Z0-9-]+/; +const ID_REGEXP = /#[A-Za-z][-A-Za-z0-9_]*/g; /** * Selector item. @@ -31,16 +32,22 @@ export default class SelectorItem { const baseSelector = selector.replace(new RegExp(PSUEDO_REGEXP, 'g'), ''); this.isAll = baseSelector === '*'; - this.isID = !this.isAll ? selector.startsWith('#') : false; - this.isAttribute = !this.isAll && !this.isID && baseSelector.includes('['); + this.isID = !this.isAll ? selector.indexOf('#') !== -1 : false; + this.isAttribute = !this.isAll && baseSelector.includes('['); // If baseSelector !== selector then some psuedo selector was replaced above - this.isPseudo = !this.isAll && !this.isID && baseSelector !== selector; - this.isClass = !this.isAll && !this.isID && new RegExp(CLASS_REGEXP, 'g').test(baseSelector); - this.tagName = !this.isAll && !this.isID ? baseSelector.match(TAG_NAME_REGEXP) : null; + this.isPseudo = !this.isAll && baseSelector !== selector; + this.isClass = !this.isAll && new RegExp(CLASS_REGEXP, 'g').test(baseSelector); + this.tagName = !this.isAll ? baseSelector.match(TAG_NAME_REGEXP) : null; this.tagName = this.tagName ? this.tagName[0].toUpperCase() : null; this.isTagName = this.tagName !== null; this.selector = selector; - this.id = !this.isAll && this.isID ? baseSelector.replace('#', '') : null; + this.id = null; + if (!this.isAll && this.isID) { + const idMatches = baseSelector.match(ID_REGEXP); + if (idMatches) { + this.id = idMatches[0].replace('#', ''); + } + } } /** @@ -59,7 +66,9 @@ export default class SelectorItem { // ID Match if (this.isID) { - return this.id === element.id; + if (this.id !== element.id) { + return false; + } } // Tag name match diff --git a/packages/happy-dom/test/query-selector/QuerySelector.test.ts b/packages/happy-dom/test/query-selector/QuerySelector.test.ts index f95192bff..305ea6925 100644 --- a/packages/happy-dom/test/query-selector/QuerySelector.test.ts +++ b/packages/happy-dom/test/query-selector/QuerySelector.test.ts @@ -560,6 +560,16 @@ describe('QuerySelector', () => { expect(div1.querySelector('span.spanClass')).toBe(span); }); + it('Returns div with a specific id and tag name matching "div#divId".', () => { + const div1 = document.createElement('div'); + const div2 = document.createElement('div'); + const div3 = document.createElement('div'); + div3.id = 'divId'; + div1.appendChild(div2); + div2.appendChild(div3); + expect(div1.querySelector('div#divId')).toBe(div3); + }); + it('Returns span with a specific class name and tag name matching "custom-element.class1".', () => { const div = document.createElement('div'); const customElement1 = document.createElement('custom-element');