fix: display testId as regex in trace-viewer (#23361)

Fixes https://github.com/microsoft/playwright/issues/23298
This commit is contained in:
Max Schmitt 2023-05-30 17:45:48 +02:00 committed by GitHub
parent fda57978e8
commit 9e75b95153
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 6 deletions

View File

@ -286,7 +286,7 @@ export class JavaScriptLocatorFactory implements LocatorFactory {
case 'or':
return `or(${body})`;
case 'test-id':
return `getByTestId(${this.quote(body as string)})`;
return `getByTestId(${this.toTestIdValue(body)})`;
case 'text':
return this.toCallWithExact('getByText', body, !!options.exact);
case 'alt':
@ -318,6 +318,12 @@ export class JavaScriptLocatorFactory implements LocatorFactory {
return this.quote(body);
}
private toTestIdValue(value: string | RegExp): string {
if (isRegExp(value))
return String(value);
return this.quote(value);
}
private quote(text: string) {
return escapeWithQuotes(text, '\'');
}
@ -370,7 +376,7 @@ export class PythonLocatorFactory implements LocatorFactory {
case 'or':
return `or_(${body})`;
case 'test-id':
return `get_by_test_id(${this.quote(body as string)})`;
return `get_by_test_id(${this.toTestIdValue(body)})`;
case 'text':
return this.toCallWithExact('get_by_text', body, !!options.exact);
case 'alt':
@ -409,6 +415,12 @@ export class PythonLocatorFactory implements LocatorFactory {
return `${this.quote(body)}`;
}
private toTestIdValue(value: string | RegExp) {
if (isRegExp(value))
return this.regexToString(value);
return this.quote(value);
}
private quote(text: string) {
return escapeWithQuotes(text, '\"');
}
@ -463,7 +475,7 @@ export class JavaLocatorFactory implements LocatorFactory {
case 'or':
return `or(${body})`;
case 'test-id':
return `getByTestId(${this.quote(body as string)})`;
return `getByTestId(${this.toTestIdValue(body)})`;
case 'text':
return this.toCallWithExact(clazz, 'getByText', body, !!options.exact);
case 'alt':
@ -502,6 +514,12 @@ export class JavaLocatorFactory implements LocatorFactory {
return this.quote(body);
}
private toTestIdValue(value: string | RegExp) {
if (isRegExp(value))
return this.regexToString(value);
return this.quote(value);
}
private quote(text: string) {
return escapeWithQuotes(text, '\"');
}
@ -550,7 +568,7 @@ export class CSharpLocatorFactory implements LocatorFactory {
case 'or':
return `Or(${body})`;
case 'test-id':
return `GetByTestId(${this.quote(body as string)})`;
return `GetByTestId(${this.toTestIdValue(body)})`;
case 'text':
return this.toCallWithExact('GetByText', body, !!options.exact);
case 'alt':
@ -589,6 +607,12 @@ export class CSharpLocatorFactory implements LocatorFactory {
return `HasText = ${this.quote(body)}`;
}
private toTestIdValue(value: string | RegExp) {
if (isRegExp(value))
return this.regexToString(value);
return this.quote(value);
}
private toHasNotText(body: string | RegExp) {
if (isRegExp(body))
return `HasNotTextRegex = ${this.regexToString(body)}`;

View File

@ -160,7 +160,7 @@ function transform(template: string, params: TemplateParams, testIdAttributeName
.replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1')
.replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1')
.replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1')
.replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1s]`)
.replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`)
.replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]')
.replace(/first(\(\))?/g, 'nth=0')
.replace(/last(\(\))?/g, 'nth=-1')
@ -200,7 +200,9 @@ function transform(template: string, params: TemplateParams, testIdAttributeName
const param = params[+ordinal - 1];
if (t.startsWith('internal:has=') || t.startsWith('internal:has-not='))
return param.text;
if (t.startsWith('internal:attr') || t.startsWith('internal:testid') || t.startsWith('internal:role'))
if (t.startsWith('internal:testid'))
return escapeForAttributeSelector(param.text, true);
if (t.startsWith('internal:attr') || t.startsWith('internal:role'))
return escapeForAttributeSelector(param.text, suffix === 's');
return escapeForTextSelector(param.text, suffix === 's');
});

View File

@ -61,6 +61,13 @@ it('reverse engineer locators', async ({ page }) => {
csharp: 'GetByTestId("He\\"llo")'
});
expect.soft(generate(page.getByTestId(/He"llo/))).toEqual({
javascript: 'getByTestId(/He"llo/)',
python: 'get_by_test_id(re.compile(r"He\\"llo"))',
java: 'getByTestId(Pattern.compile("He\\"llo"))',
csharp: 'GetByTestId(new Regex("He\\"llo"))'
});
expect.soft(generate(page.getByText('Hello', { exact: true }))).toEqual({
csharp: 'GetByText("Hello", new() { Exact = true })',
java: 'getByText("Hello", new Page.GetByTextOptions().setExact(true))',

View File

@ -34,6 +34,8 @@ test.beforeAll(async function recordTrace({ browser, browserName, browserType, s
await page.goto('data:text/html,<html>Hello world</html>');
await page.setContent('<button>Click</button>');
await expect(page.locator('button')).toHaveText('Click');
await expect(page.getByTestId('amazing-btn')).toBeHidden();
await expect(page.getByTestId(/amazing-btn-regex/)).toBeHidden();
await page.evaluate(({ a }) => {
console.log('Info');
console.warn('Warning');
@ -102,6 +104,8 @@ test('should open simple trace viewer', async ({ showTraceViewer }) => {
/page.gotodata:text\/html,<html>Hello world<\/html>/,
/page.setContent/,
/expect.toHaveTextlocator\('button'\)/,
/expect.toBeHiddengetByTestId\('amazing-btn'\)/,
/expect.toBeHiddengetByTestId\(\/amazing-btn-regex\/\)/,
/page.evaluate/,
/page.evaluate/,
/locator.clickgetByText\('Click'\)/,