Skip to content

Commit

Permalink
Merge pull request #943 from btea/task/939-selector-parse-pseudo-element
Browse files Browse the repository at this point in the history
#939@patch: Correct parsing of pseudo elements by selectors.
  • Loading branch information
capricorn86 committed Jul 10, 2023
2 parents 508e43f + 2b2cac4 commit 53c8c01
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 3 deletions.
8 changes: 8 additions & 0 deletions packages/happy-dom/src/query-selector/SelectorItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default class SelectorItem {
public classNames: string[] | null;
public attributes: ISelectorAttribute[] | null;
public pseudos: ISelectorPseudo[] | null;
public isPseudoElement: boolean;
public combinator: SelectorCombinatorEnum;

/**
Expand All @@ -28,20 +29,23 @@ export default class SelectorItem {
* @param [options.classNames] Class names.
* @param [options.attributes] Attributes.
* @param [options.pseudos] Pseudos.
* @param [options.isPseudoElement] Is pseudo element.
*/
constructor(options?: {
tagName?: string;
id?: string;
classNames?: string[];
attributes?: ISelectorAttribute[];
pseudos?: ISelectorPseudo[];
isPseudoElement?: boolean;
combinator?: SelectorCombinatorEnum;
}) {
this.tagName = options?.tagName || null;
this.id = options?.id || null;
this.classNames = options?.classNames || null;
this.attributes = options?.attributes || null;
this.pseudos = options?.pseudos || null;
this.isPseudoElement = options?.isPseudoElement || false;
this.combinator = options?.combinator || SelectorCombinatorEnum.descendant;
}

Expand All @@ -54,6 +58,10 @@ export default class SelectorItem {
public match(element: IElement): ISelectorMatch | null {
let priorityWeight = 0;

if (this.isPseudoElement) {
return null;
}

// Tag name match
if (this.tagName) {
if (this.tagName !== '*' && this.tagName !== element.tagName) {
Expand Down
9 changes: 6 additions & 3 deletions packages/happy-dom/src/query-selector/SelectorParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import ISelectorPseudo from './ISelectorPseudo.js';
* Group 13: Pseudo name when arguments (e.g. "nth-child")
* Group 14: Arguments of pseudo (e.g. "2n + 1")
* Group 15: Pseudo name when no arguments (e.g. "empty")
* Group 16: Combinator.
* Group 16: Pseudo element (e.g. "::after", "::-webkit-inner-spin-button").
* 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-_]+) *([~|^$*]{0,1}) *= *["']{1}([^"']*)["']{1} *(s|i){0,1}\]|\[([a-zA-Z0-9-_]+) *([~|^$*]{0,1}) *= *([^\]]*)\]|:([a-zA-Z-]+) *\(([^)]+)\)|:([a-zA-Z-]+)|([ ,+>]*)/g;
/(\*)|([a-zA-Z0-9-]+)|#((?:[a-zA-Z0-9-_]|\\.)+)|\.((?:[a-zA-Z0-9-_]|\\.)+)|\[([a-zA-Z0-9-_]+)\]|\[([a-zA-Z0-9-_]+) *([~|^$*]{0,1}) *= *["']{1}([^"']*)["']{1} *(s|i){0,1}\]|\[([a-zA-Z0-9-_]+) *([~|^$*]{0,1}) *= *([^\]]*)\]|:([a-zA-Z-]+) *\(([^)]+)\)|:([a-zA-Z-]+)|::([a-zA-Z-]+)|([ ,+>]*)/g;

/**
* Escaped Character RegExp.
Expand Down Expand Up @@ -151,7 +152,9 @@ export default class SelectorParser {
currentSelectorItem.pseudos = currentSelectorItem.pseudos || [];
currentSelectorItem.pseudos.push(this.getPseudo(match[15]));
} else if (match[16]) {
switch (match[16].trim()) {
currentSelectorItem.isPseudoElement = true;
} else if (match[17]) {
switch (match[17].trim()) {
case ',':
currentSelectorItem = new SelectorItem({
combinator: SelectorCombinatorEnum.descendant
Expand Down
14 changes: 14 additions & 0 deletions packages/happy-dom/test/query-selector/QuerySelector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,14 @@ describe('QuerySelector', () => {
)
).toEqual(['b.n4', 'span.n5', 'div.n6']);
});

it('Returns empty node list when match pseudo element "::-webkit-inner-spin-button".', () => {
const container = document.createElement('div');
container.innerHTML = QuerySelectorNthChildHTML;
const elements = container.querySelectorAll('::-webkit-inner-spin-button');

expect(elements.length).toBe(0);
});
});

describe('querySelector', () => {
Expand Down Expand Up @@ -1087,5 +1095,11 @@ describe('QuerySelector', () => {

expect(div.querySelector('input:not([list])[type="search"]')).toBeNull();
});

it('Returns null by pseudo element selector of ::-webkit-inner-spin-button', () => {
const div = document.createElement('div');
expect(div.querySelector('::-webkit-inner-spin-button')).toBeNull();
expect(document.querySelector('::-webkit-inner-spin-button')).toBeNull();
});
});
});

0 comments on commit 53c8c01

Please sign in to comment.