Skip to content

Commit 99a0ac6

Browse files
committed
chore: remove _react selector
When querying with `_react`, suggest an alternative locator instead.
1 parent 0778fcf commit 99a0ac6

File tree

5 files changed

+204
-132
lines changed

5 files changed

+204
-132
lines changed

packages/injected/src/injectedScript.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ export class InjectedScript {
275275
const result = this.querySelectorAll(selector, root);
276276
if (strict && result.length > 1)
277277
throw this.strictModeViolationError(selector, result);
278+
this.checkDeprecatedSelectorUsage(selector, result);
278279
return result[0];
279280
}
280281

@@ -1228,28 +1229,44 @@ export class InjectedScript {
12281229
return oneLine(`<${element.nodeName.toLowerCase()}${attrText}>${trimStringWithEllipsis(text, 50)}</${element.nodeName.toLowerCase()}>`);
12291230
}
12301231

1231-
strictModeViolationError(selector: ParsedSelector, matches: Element[]): Error {
1232+
private _generateSelectors(elements: Element[]) {
12321233
this._evaluator.begin();
12331234
beginAriaCaches();
12341235
beginDOMCaches();
12351236
try {
12361237
// Firefox is slow to access DOM bindings in the utility world, making it very expensive to generate a lot of selectors.
12371238
const maxElements = this._isUtilityWorld && this._browserName === 'firefox' ? 2 : 10;
1238-
const infos = matches.slice(0, maxElements).map(m => ({
1239+
const infos = elements.slice(0, maxElements).map(m => ({
12391240
preview: this.previewNode(m),
12401241
selector: this.generateSelectorSimple(m),
12411242
}));
1242-
const lines = infos.map((info, i) => `\n ${i + 1}) ${info.preview} aka ${asLocator(this._sdkLanguage, info.selector)}`);
1243-
if (infos.length < matches.length)
1244-
lines.push('\n ...');
1245-
return this.createStacklessError(`strict mode violation: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} elements:${lines.join('')}\n`);
1243+
return infos.map((info, i) => `${i + 1}) ${info.preview} aka ${asLocator(this._sdkLanguage, info.selector)}`);
12461244
} finally {
12471245
endDOMCaches();
12481246
endAriaCaches();
12491247
this._evaluator.end();
12501248
}
12511249
}
12521250

1251+
strictModeViolationError(selector: ParsedSelector, matches: Element[]): Error {
1252+
const lines = this._generateSelectors(matches).map(line => `\n ` + line);
1253+
if (lines.length < matches.length)
1254+
lines.push('\n ...');
1255+
return this.createStacklessError(`strict mode violation: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} elements:${lines.join('')}\n`);
1256+
}
1257+
1258+
checkDeprecatedSelectorUsage(selector: ParsedSelector, matches: Element[]) {
1259+
if (!matches.length)
1260+
return;
1261+
const deperecated = selector.parts.find(part => part.name === '_react' || part.name === '_vue');
1262+
if (!deperecated)
1263+
return;
1264+
const lines = this._generateSelectors(matches).map(line => `\n ` + line);
1265+
if (lines.length < matches.length)
1266+
lines.push('\n ...');
1267+
throw this.createStacklessError(`"${deperecated.name}" selector is not supported: ${asLocator(this._sdkLanguage, stringifySelector(selector))} resolved to ${matches.length} element${matches.length === 1 ? '' : 's'}:${lines.join('')}\n`);
1268+
}
1269+
12531270
createStacklessError(message: string): Error {
12541271
if (this._browserName === 'firefox') {
12551272
const error = new Error('Error: ' + message);

packages/playwright-core/src/server/frameSelectors.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ export class FrameSelectors {
7171
if (!resolved)
7272
throw new Error(`Failed to find frame for selector "${selector}"`);
7373
return await resolved.injected.evaluateHandle((injected, { info, scope }) => {
74-
return injected.querySelectorAll(info.parsed, scope || document);
74+
const elements = injected.querySelectorAll(info.parsed, scope || document);
75+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
76+
return elements;
7577
}, { info: resolved.info, scope: resolved.scope });
7678
}
7779

@@ -82,7 +84,9 @@ export class FrameSelectors {
8284
throw new Error(`Failed to find frame for selector "${selector}"`);
8385
await options.__testHookBeforeQuery?.();
8486
return await resolved.injected.evaluate((injected, { info }) => {
85-
return injected.querySelectorAll(info.parsed, document).length;
87+
const elements = injected.querySelectorAll(info.parsed, document);
88+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
89+
return elements.length;
8690
}, { info: resolved.info });
8791
}
8892

@@ -92,7 +96,9 @@ export class FrameSelectors {
9296
if (!resolved)
9397
return [];
9498
const arrayHandle = await resolved.injected.evaluateHandle((injected, { info, scope }) => {
95-
return injected.querySelectorAll(info.parsed, scope || document);
99+
const elements = injected.querySelectorAll(info.parsed, scope || document);
100+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
101+
return elements;
96102
}, { info: resolved.info, scope: resolved.scope });
97103

98104
const properties = await arrayHandle.getProperties();

packages/playwright-core/src/server/frames.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ export class Frame extends SdkObject {
785785
} else if (element) {
786786
log = ` locator resolved to ${visible ? 'visible' : 'hidden'} ${injected.previewNode(element)}`;
787787
}
788+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
788789
return { log, element, visible, attached: !!element };
789790
}, { info: resolved.info, root: resolved.frame === this ? scope : undefined }));
790791
const { log, visible, attached } = await progress.race(result.evaluate(r => ({ log: r.log, visible: r.visible, attached: r.attached })));
@@ -1115,6 +1116,7 @@ export class Frame extends SdkObject {
11151116
} else if (element) {
11161117
log = ` locator resolved to ${injected.previewNode(element)}`;
11171118
}
1119+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
11181120
return { log, success: !!element, element };
11191121
}, { info: resolved.info, callId: progress.metadata.id }));
11201122
const { log, success } = await progress.race(result.evaluate(r => ({ log: r.log, success: r.success })));
@@ -1444,6 +1446,8 @@ export class Frame extends SdkObject {
14441446
throw injected.strictModeViolationError(info!.parsed, elements);
14451447
else if (elements.length)
14461448
log = ` locator resolved to ${injected.previewNode(elements[0])}`;
1449+
if (info)
1450+
injected.checkDeprecatedSelectorUsage(info.parsed, elements);
14471451
return { log, ...await injected.expect(elements[0], options, elements) };
14481452
}, { info, options, callId: progress.metadata.id }));
14491453

0 commit comments

Comments
 (0)