Skip to content

Commit

Permalink
fix(locator parser): allow escaped quotes in the digest function (#29012
Browse files Browse the repository at this point in the history
)

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.
  • Loading branch information
dgozman authored Jan 17, 2024
1 parent 9b657b5 commit d023829
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 5 deletions.
11 changes: 7 additions & 4 deletions packages/playwright-core/src/utils/isomorphic/locatorParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
9 changes: 8 additions & 1 deletion tests/library/locator-generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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);
Expand Down

0 comments on commit d023829

Please sign in to comment.