diff --git a/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts b/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts index 04f3040547d16..355d0cec5fa0d 100644 --- a/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts +++ b/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts @@ -36,7 +36,7 @@ export interface LocatorFactory { } export function asLocator(lang: Language, selector: string, isFrameLocator: boolean = false): string { - return asLocators(lang, selector, isFrameLocator)[0]; + return asLocators(lang, selector, isFrameLocator, 1)[0]; } export function asLocators(lang: Language, selector: string, isFrameLocator: boolean = false, maxOutputSize = 20, preferredQuote?: Quote): string[] { @@ -220,7 +220,7 @@ function combineTokens(factory: LocatorFactory, tokens: string[][], maxOutputSiz const visit = (index: number) => { if (index === tokens.length) { result.push(factory.chainLocators(currentTokens)); - return currentTokens.length < maxOutputSize; + return result.length < maxOutputSize; } for (const taken of tokens[index]) { currentTokens[index] = taken; diff --git a/tests/library/locator-generator.spec.ts b/tests/library/locator-generator.spec.ts index cceff133d4eb4..417e096e29a55 100644 --- a/tests/library/locator-generator.spec.ts +++ b/tests/library/locator-generator.spec.ts @@ -615,3 +615,27 @@ it('parseLocator frames', async () => { expect.soft(parseLocator('java', `locator("iframe").contentFrame().getByText("foo")`, '')).toBe(`iframe >> internal:control=enter-frame >> internal:text=\"foo\"i`); expect.soft(parseLocator('java', `frameLocator("iframe").getByText("foo")`, '')).toBe(`iframe >> internal:control=enter-frame >> internal:text=\"foo\"i`); }); + +it('should not oom in locator parser', async ({ page }) => { + const l = page.locator.bind(page); + const locator = page.locator('text=L1').or(l('text=L2').or(l('text=L3').or(l('text=L4')).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L5').or(l('text=L6'))).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L7') + .or(l('text=L8'))))).or(l('text=L9').or(l('text=L10').or(l('text=L11')).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L12').or(l('text=L13'))).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L14').or(l('text=L15'))))).or(l('text=L16').or(l('text=L17').or(l('text=L18')).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L19').or(l('text=L20'))).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L21').or(l('text=L22'))))).or(l('text=L23').or(l('text=L24').or(l('text=L25')).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L26').or(l('text=L27'))).or(l('#f0') + .contentFrame().locator('#f0_mid_0') + .contentFrame().locator('text=L28').or(l('text=L29'))))); + const error = await locator.count().catch(e => e); + expect(error.message).toContain('Frame locators are not allowed inside composite locators'); +});