Skip to content

Commit

Permalink
Merge branch 'master' into fix-form-submitter
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 authored Jan 15, 2024
2 parents 43e73a7 + 35a0b3c commit fb026d9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 6 deletions.
33 changes: 30 additions & 3 deletions packages/happy-dom/src/query-selector/QuerySelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ type IDocumentPositionAndElement = {
element: IElement;
};

/**
* Invalid Selector RegExp.
*/
const INVALID_SELECTOR_REGEXP = /^[.#\[]?\d/;

/**
* Utility for query selection in an HTML element.
*
Expand All @@ -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[] = [];

Expand Down Expand Up @@ -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
Expand All @@ -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());

Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/selection/Selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default class Selection {
*/
public get anchorOffset(): number {
if (!this.#range) {
return null;
return 0;
}
return this.#direction === SelectionDirectionEnum.forwards
? this.#range.startOffset
Expand Down
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
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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."
);
});
});
});
4 changes: 2 additions & 2 deletions packages/happy-dom/test/selection/Selection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ describe('Selection', () => {

for (const property of ['anchorOffset', 'baseOffset', 'focusOffset', 'extentOffset']) {
describe(`get ${property}()`, () => {
it('Returns null if no Range has been added.', () => {
expect(selection[property]).toBe(null);
it('Returns 0 if no Range has been added.', () => {
expect(selection[property]).toBe(0);
});

it(`Returns start offset of Range if direction is "${SelectionDirectionEnum.forwards}".`, () => {
Expand Down

0 comments on commit fb026d9

Please sign in to comment.