fix(locator parser): allow escaped quotes in the digest function (#29012)

This supports mixed quotes locators in JavaScript where we are not sure
what quote is the correct one, so we normalize to unescaped single quote
when comparing with the original.

Drive-by: we were allowing single quotes in Python, Java and .NET, but
these are actually not allowed.

Regressed in #27718.
Fixes #28630.
This commit is contained in:
Dmitry Gozman 2024-01-16 16:06:02 -08:00 committed by GitHub
parent 9b657b54fb
commit d023829dd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 15 additions and 5 deletions

View File

@ -220,14 +220,17 @@ export function locatorOrSelectorAsSelector(language: Language, locator: string,
try {
const { selector, preferredQuote } = parseLocator(locator, testIdAttributeName);
const locators = asLocators(language, selector, undefined, undefined, preferredQuote);
const digest = digestForComparison(locator);
if (locators.some(candidate => digestForComparison(candidate) === digest))
const digest = digestForComparison(language, locator);
if (locators.some(candidate => digestForComparison(language, candidate) === digest))
return selector;
} catch (e) {
}
return '';
}
function digestForComparison(locator: string) {
return locator.replace(/\s/g, '').replace(/["`]/g, '\'');
function digestForComparison(language: Language, locator: string) {
locator = locator.replace(/\s/g, '');
if (language === 'javascript')
locator = locator.replace(/\\?["`]/g, '\'');
return locator;
}

View File

@ -539,6 +539,13 @@ it('parseLocator quotes', async () => {
expect.soft(parseLocator('java', `locator('text="bar"')`, '')).toBe(``);
expect.soft(parseLocator('csharp', `Locator("text='bar'")`, '')).toBe(`text='bar'`);
expect.soft(parseLocator('csharp', `Locator('text="bar"')`, '')).toBe(``);
const mixedQuotes = `
locator("[id*=freetext-field]")
.locator('input:below(:text("Assigned Number:"))')
.locator("visible=true")
`;
expect.soft(parseLocator('javascript', mixedQuotes, '')).toBe(`[id*=freetext-field] >> input:below(:text("Assigned Number:")) >> visible=true`);
});
it('parseLocator css', async () => {
@ -563,7 +570,7 @@ it('parse locators strictly', () => {
// Quotes
expect.soft(parseLocator('javascript', `locator("div").filter({ hasText: "Goodbye world" }).locator("span")`)).toBe(selector);
expect.soft(parseLocator('python', `locator('div').filter(has_text='Goodbye world').locator('span')`)).toBe(selector);
expect.soft(parseLocator('python', `locator('div').filter(has_text='Goodbye world').locator('span')`)).not.toBe(selector);
// Whitespace
expect.soft(parseLocator('csharp', `Locator("div") . Filter (new ( ) { HasText = "Goodbye world" }).Locator( "span" )`)).toBe(selector);