Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: capricorn86/happy-dom
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v13.1.2
Choose a base ref
...
head repository: capricorn86/happy-dom
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v13.1.3
Choose a head ref
  • 5 commits
  • 2 files changed
  • 2 contributors

Commits on Nov 29, 2023

  1. Copy the full SHA
    00e63aa View commit details
  2. #0@patch: Format code.

    btea committed Nov 29, 2023
    Copy the full SHA
    cf5abd7 View commit details

Commits on Jan 15, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    85ea7d7 View commit details
  2. #1170@patch: Throws an error when providing an invalid selector to qu…

    …erySelector() and querySelectorAll().
    capricorn86 committed Jan 15, 2024
    Copy the full SHA
    61b3137 View commit details
  3. Merge pull request #1170 from btea/task/0-match-section-invalid-selector

    #0@patch: Matches a partially invalid selector and throws an error.
    capricorn86 authored Jan 15, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    35a0b3c View commit details
Showing with 62 additions and 3 deletions.
  1. +30 −3 packages/happy-dom/src/query-selector/QuerySelector.ts
  2. +32 −0 packages/happy-dom/test/query-selector/QuerySelector.test.ts
33 changes: 30 additions & 3 deletions packages/happy-dom/src/query-selector/QuerySelector.ts
Original file line number Diff line number Diff line change
@@ -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,14 +40,20 @@ export default class QuerySelector {
): INodeList<IElement> {
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.`
);
}

if (selector === null || selector === undefined) {
return new NodeList<IElement>();
}

if (INVALID_SELECTOR_REGEXP.test(selector)) {
throw new Error(
`Failed to execute 'querySelectorAll' on '${node.constructor.name}': '${selector}' is not a valid selector.`
);
}

const groups = SelectorParser.getSelectorGroups(selector);
let matches: IDocumentPositionAndElement[] = [];

@@ -79,17 +90,23 @@ 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.`
);
}

if (selector === null || selector === undefined) {
return null;
}

if (INVALID_SELECTOR_REGEXP.test(selector)) {
throw new Error(
`Failed to execute 'querySelector' on '${node.constructor.name}': '${selector}' is not a valid selector.`
);
}

for (const items of SelectorParser.getSelectorGroups(selector)) {
const match =
node[PropertySymbol.nodeType] === NodeTypeEnum.elementNode
@@ -112,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());

32 changes: 32 additions & 0 deletions packages/happy-dom/test/query-selector/QuerySelector.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
@@ -1126,5 +1142,21 @@ describe('QuerySelector', () => {
expect(element === div.children[0]).toBe(true);
expect(element2 === div.children[0]).toBe(true);
});

it('Throws an error when providing an invalid selector', () => {
const div = document.createElement('div');
expect(() => div.querySelector('1')).toThrowError(
"Failed to execute 'querySelector' on 'HTMLElement': '1' is not a valid selector."
);
expect(() => div.querySelector('[1')).toThrowError(
"Failed to execute 'querySelector' on 'HTMLElement': '[1' is not a valid selector."
);
expect(() => div.querySelector('.1')).toThrowError(
"Failed to execute 'querySelector' on 'HTMLElement': '.1' is not a valid selector."
);
expect(() => div.querySelector('#1')).toThrowError(
"Failed to execute 'querySelector' on 'HTMLElement': '#1' is not a valid selector."
);
});
});
});