Skip to content

Commit

Permalink
fix: [#1507] Fixes selector validation, so that it converts values to…
Browse files Browse the repository at this point in the history
… string (#1522)

* chore: [#1507] Fixes selector validation, so that it converts values to string

* fix: [#1507] Fixes selector validation, so that it converts values to string

* chore: [#1507] Attempt to fix shaky unit tests
  • Loading branch information
capricorn86 authored Aug 31, 2024
1 parent 9bde659 commit d0c8ab5
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 66 deletions.
111 changes: 58 additions & 53 deletions packages/happy-dom/src/query-selector/QuerySelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import ISVGElementTagNameMap from '../config/ISVGElementTagNameMap.js';
import ICachedQuerySelectorAllItem from '../nodes/node/ICachedQuerySelectorAllResult.js';
import ICachedQuerySelectorItem from '../nodes/node/ICachedQuerySelectorResult.js';
import ICachedMatchesItem from '../nodes/node/ICachedMatchesResult.js';
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum.js';

type DocumentPositionAndElement = {
documentPosition: string;
Expand Down Expand Up @@ -78,27 +77,32 @@ export default class QuerySelector {
node: Element | Document | DocumentFragment,
selector: string
): NodeList<Element> {
if (selector === null || selector === undefined) {
return new NodeList<Element>(PropertySymbol.illegalConstructor, []);
}

const window = node[PropertySymbol.window];

if (<string>selector === '') {
throw new window.Error(
throw new window.DOMException(
`Failed to execute 'querySelectorAll' on '${node.constructor.name}': The provided selector is empty.`
);
}

if (typeof selector !== 'string' && typeof selector !== 'boolean') {
if (typeof selector === 'function') {
throw new window.DOMException(
`Failed to execute 'querySelectorAll' on '${node.constructor.name}': '${selector}' is not a valid selector.`,
'SyntaxError'
`Failed to execute 'querySelectorAll' on '${node.constructor.name}': '${selector}' is not a valid selector.`
);
}

if (typeof selector === 'symbol') {
throw new window.TypeError(`Cannot convert a Symbol value to a string`);
}

selector = String(selector);

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

const cache = node[PropertySymbol.cache].querySelectorAll;
const cachedResult = cache.get(selector);

Expand All @@ -109,12 +113,6 @@ export default class QuerySelector {
}
}

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

const groups = SelectorParser.getSelectorGroups(selector);
const items: Element[] = [];
const nodeList = new NodeList<Element>(PropertySymbol.illegalConstructor, items);
Expand Down Expand Up @@ -199,27 +197,38 @@ export default class QuerySelector {
node: Element | Document | DocumentFragment,
selector: string
): Element | null {
if (selector === null || selector === undefined) {
return null;
}

const window = node[PropertySymbol.window];

if (selector === '') {
throw new window.Error(
throw new window.DOMException(
`Failed to execute 'querySelector' on '${node.constructor.name}': The provided selector is empty.`
);
}

if (typeof selector !== 'string' && typeof selector !== 'boolean') {
if (typeof selector === 'function' || typeof selector === 'symbol') {
throw new window.DOMException(
`Failed to execute 'querySelector' on '${node.constructor.name}': '${selector}' is not a valid selector.`,
'SyntaxError'
`Failed to execute 'querySelector' on '${node.constructor.name}': '${selector}' is not a valid selector.`
);
}

if (typeof selector === 'function') {
throw new window.DOMException(
`Failed to execute 'querySelector' on '${node.constructor.name}': '${selector}' is not a valid selector.`
);
}

if (typeof selector === 'symbol') {
throw new window.TypeError(`Cannot convert a Symbol value to a string`);
}

selector = String(selector);

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

const cachedResult = node[PropertySymbol.cache].querySelector.get(selector);

if (cachedResult?.result) {
Expand All @@ -229,12 +238,6 @@ export default class QuerySelector {
}
}

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

const cachedItem: ICachedQuerySelectorItem = {
result: <WeakRef<Element | null>>{
deref: () => null
Expand Down Expand Up @@ -277,55 +280,57 @@ export default class QuerySelector {
selector: string,
options?: { ignoreErrors?: boolean }
): ISelectorMatch | null {
if (!selector) {
return null;
}
const ignoreErrors = options?.ignoreErrors;
const window = element[PropertySymbol.window];

if (selector === null || selector === undefined) {
if (selector === '*') {
return {
priorityWeight: 0
priorityWeight: 1
};
}

const window = element[PropertySymbol.window];

if (<string>selector === '') {
throw new window.Error(
if (ignoreErrors) {
return null;
}
throw new window.DOMException(
`Failed to execute 'matches' on '${element.constructor.name}': The provided selector is empty.`
);
}

if (typeof selector !== 'string' && typeof selector !== 'boolean') {
if (typeof selector === 'function') {
if (ignoreErrors) {
return null;
}
throw new window.DOMException(
`Failed to execute 'matches' on '${element.constructor.name}': '${selector}' is not a valid selector.`,
DOMExceptionNameEnum.syntaxError
`Failed to execute 'matches' on '${element.constructor.name}': '${selector}' is not a valid selector.`
);
}

selector = String(selector);

if (selector === '*') {
return {
priorityWeight: 1
};
if (typeof selector === 'symbol') {
if (ignoreErrors) {
return null;
}
throw new window.TypeError(`Cannot convert a Symbol value to a string`);
}

const ignoreErrors = options?.ignoreErrors;
const cachedResult = element[PropertySymbol.cache].matches.get(selector);

if (cachedResult?.result) {
return cachedResult.result.match;
}
selector = String(selector);

if (INVALID_SELECTOR_REGEXP.test(selector)) {
if (ignoreErrors) {
return null;
}
throw new window.Error(
throw new window.DOMException(
`Failed to execute 'matches' on '${element.constructor.name}': '${selector}' is not a valid selector.`
);
}

const cachedResult = element[PropertySymbol.cache].matches.get(selector);

if (cachedResult?.result) {
return cachedResult.result.match;
}

const cachedItem: ICachedMatchesItem = {
result: { match: null }
};
Expand Down
12 changes: 6 additions & 6 deletions packages/happy-dom/test/fetch/Request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -555,7 +555,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -589,7 +589,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -622,7 +622,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -663,7 +663,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -795,7 +795,7 @@ describe('Request', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down
14 changes: 7 additions & 7 deletions packages/happy-dom/test/fetch/Response.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -190,7 +190,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -233,7 +233,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -273,7 +273,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -315,7 +315,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down Expand Up @@ -455,7 +455,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});

Expand Down Expand Up @@ -484,7 +484,7 @@ describe('Response', () => {
setTimeout(() => {
expect(isAsyncComplete).toBe(true);
resolve(null);
}, 30);
}, 50);
});
});
});
Expand Down
Loading

0 comments on commit d0c8ab5

Please sign in to comment.