diff --git a/packages/happy-dom/src/query-selector/QuerySelector.ts b/packages/happy-dom/src/query-selector/QuerySelector.ts index b0c702022..7bf78ad8c 100644 --- a/packages/happy-dom/src/query-selector/QuerySelector.ts +++ b/packages/happy-dom/src/query-selector/QuerySelector.ts @@ -106,7 +106,14 @@ export default class QuerySelector { const selector = new SelectorItem(selectorParts[0]); const result = selector.match(currentNode); - if ((targetNode === currentNode || !currentNode.parentElement) && !result.matches) { + if (result.matches && selectorParts.length === 1) { + return { + priorityWeight: priorityWeight + result.priorityWeight, + matches: true + }; + } + + if (!currentNode.parentElement || (targetNode === currentNode && !result.matches)) { return { priorityWeight: 0, matches: false }; } diff --git a/packages/happy-dom/test/nodes/element/Element.test.ts b/packages/happy-dom/test/nodes/element/Element.test.ts index 0d6b551a7..f35e87e1d 100644 --- a/packages/happy-dom/test/nodes/element/Element.test.ts +++ b/packages/happy-dom/test/nodes/element/Element.test.ts @@ -713,6 +713,19 @@ describe('Element', () => { expect(element.matches('.nonexistent-class div.active')).toBe(false); }); + it('Checks if a detached element matches with a descendant combinator', () => { + const parentElement = document.createElement('div'); + parentElement.setAttribute('role', 'status'); + + const element = document.createElement('div'); + element.className = 'active'; + parentElement.appendChild(element); + + expect(element.matches('div[role="status"] div.active')).toBe(true); + expect(element.matches('div[role="article"] div.active')).toBe(false); + expect(parentElement.matches('.nonexistent-class div[role="status"]')).toBe(false); + }); + it('Checks if the element matches with a child combinator', () => { const grandparentElement = document.createElement('div'); grandparentElement.setAttribute('role', 'alert'); @@ -727,6 +740,7 @@ describe('Element', () => { expect(element.matches('div[role="status"] > div.active')).toBe(true); expect(element.matches('div[role="alert"] > div.active')).toBe(false); + expect(grandparentElement.matches('div > div[role="alert"]')).toBe(false); }); });