From dc0680119a0a596c1b54d478d3e9c4fadc576154 Mon Sep 17 00:00:00 2001 From: David Ortner Date: Tue, 12 Nov 2024 02:01:01 +0100 Subject: [PATCH] fix: [#1558] Fixes bug where psuedo selectors without an ending pranthese result in invalid selector error (#1602) --- .../src/query-selector/SelectorParser.ts | 2 +- .../happy-dom/src/xml-parser/XMLParser.ts | 2 +- .../test/query-selector/QuerySelector.test.ts | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/happy-dom/src/query-selector/SelectorParser.ts b/packages/happy-dom/src/query-selector/SelectorParser.ts index da6875b08..eb960dcd1 100644 --- a/packages/happy-dom/src/query-selector/SelectorParser.ts +++ b/packages/happy-dom/src/query-selector/SelectorParser.ts @@ -25,7 +25,7 @@ import ISelectorPseudo from './ISelectorPseudo.js'; * Group 17: Combinator. */ const SELECTOR_REGEXP = - /(\*)|([a-zA-Z0-9-]+)|#((?:[a-zA-Z0-9-_]|\\.)+)|\.((?:[a-zA-Z0-9-_]|\\.)+)|\[([a-zA-Z0-9-_]+)\]|\[([a-zA-Z0-9-_]+)\s*([~|^$*]{0,1})\s*=\s*["']{1}([^"']*)["']{1}\s*(s|i){0,1}\]|\[([a-zA-Z0-9-_]+)\s*([~|^$*]{0,1})\s*=\s*([^\]]*)\]|:([a-zA-Z-]+)\s*\(([^)]+\)?)\)|:([a-zA-Z-]+)|::([a-zA-Z-]+)|([\s,+>]*)/gm; + /(\*)|([a-zA-Z0-9-]+)|#((?:[a-zA-Z0-9-_]|\\.)+)|\.((?:[a-zA-Z0-9-_]|\\.)+)|\[([a-zA-Z0-9-_\\:]+)\]|\[([a-zA-Z0-9-_\\:]+)\s*([~|^$*]{0,1})\s*=\s*["']{1}([^"']*)["']{1}\s*(s|i){0,1}\]|\[([a-zA-Z0-9-_]+)\s*([~|^$*]{0,1})\s*=\s*([^\]]*)\]|:([a-zA-Z-]+)\s*\(([^)]+)\){0,1}|:([a-zA-Z-]+)|::([a-zA-Z-]+)|([\s,+>]*)/gm; /** * Escaped Character RegExp. diff --git a/packages/happy-dom/src/xml-parser/XMLParser.ts b/packages/happy-dom/src/xml-parser/XMLParser.ts index b5452b572..079965c02 100755 --- a/packages/happy-dom/src/xml-parser/XMLParser.ts +++ b/packages/happy-dom/src/xml-parser/XMLParser.ts @@ -42,7 +42,7 @@ const MARKUP_REGEXP = * Group 9: Attribute name when the attribute has no value (e.g. "disabled" in "
"). */ const ATTRIBUTE_REGEXP = - /\s*([a-zA-Z0-9-_:.$@?]+) *= *([a-zA-Z0-9-_:.$@?{}/]+)|\s*([a-zA-Z0-9-_:.$@?]+) *= *"([^"]*)("{0,1})|\s*([a-zA-Z0-9-_:.$@?]+) *= *'([^']*)('{0,1})|\s*([a-zA-Z0-9-_:.$@?]+)/gm; + /\s*([a-zA-Z0-9-_:.$@?\\]+) *= *([a-zA-Z0-9-_:.$@?{}/]+)|\s*([a-zA-Z0-9-_:.$@?\\]+) *= *"([^"]*)("{0,1})|\s*([a-zA-Z0-9-_:.$@?\\]+) *= *'([^']*)('{0,1})|\s*([a-zA-Z0-9-_:.$@?\\]+)/gm; enum MarkupReadStateEnum { startOrEndTag = 'startOrEndTag', diff --git a/packages/happy-dom/test/query-selector/QuerySelector.test.ts b/packages/happy-dom/test/query-selector/QuerySelector.test.ts index 0a89cce2f..2a561b406 100644 --- a/packages/happy-dom/test/query-selector/QuerySelector.test.ts +++ b/packages/happy-dom/test/query-selector/QuerySelector.test.ts @@ -847,6 +847,31 @@ describe('QuerySelector', () => { expect(elements3[1] === container.children[0].children[1].children[2]).toBe(true); }); + it('Returns all elements matching the selector without ending parenthese "button:not([type]"', () => { + const container = document.createElement('div'); + container.innerHTML = ` + + + + `; + const elements = container.querySelectorAll('button:not([type]'); + expect(elements.length).toBe(2); + expect(elements[0]).toBe(container.children[0]); + expect(elements[1]).toBe(container.children[2]); + }); + + it('Returns all elements matching the invalid selector "[q\\:shadowroot]"', () => { + const container = document.createElement('div'); + container.innerHTML = ` + + +
+ `; + const elements = container.querySelectorAll('[q\\:shadowroot]'); + expect(elements.length).toBe(1); + expect(elements[0]).toBe(container.children[0]); + }); + it('Returns all elements matching "input:not([type]):not([list])" to verify that "screen.getByRole(\'checkbox\')" works in Testing Library.', () => { const container = document.createElement('div');