From 8de42e63aec43bfad303bfac77e58c20e7d1de3d Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Mon, 19 Sep 2022 16:04:26 +0200 Subject: [PATCH] fix: ensure the right order of waitForSelector and scrollIntoView --- .../LighthouseStringifyExtension.test.ts.js | 16 +-- .../PuppeteerStringifyExtension.test.ts.js | 40 ++---- __snapshots__/lighthouse-e2e.test.ts.js | 24 ++-- __snapshots__/stringify.test.ts.js | 128 ++++++++++++------ __snapshots__/stringifyStep.test.ts.js | 2 +- src/PuppeteerRunnerExtension.ts | 22 ++- src/PuppeteerStringifyExtension.ts | 12 +- 7 files changed, 152 insertions(+), 92 deletions(-) diff --git a/__snapshots__/LighthouseStringifyExtension.test.ts.js b/__snapshots__/LighthouseStringifyExtension.test.ts.js index 721a813d..60fb6b53 100644 --- a/__snapshots__/LighthouseStringifyExtension.test.ts.js +++ b/__snapshots__/LighthouseStringifyExtension.test.ts.js @@ -28,8 +28,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later await lhFlow.startTimespan(); { const targetPage = page; + await scrollIntoViewIfNeeded([["#button"]], targetPage, timeout); const element = await waitForSelectors([["#button"]], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 61, @@ -42,7 +42,7 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later fs.writeFileSync(__dirname + '/flow.report.html', lhFlowReport) await -`; +` exports['LighthouseStringifyExtension handles ending navigation 1'] = ` const fs = require('fs'); @@ -74,8 +74,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later await lhFlow.startTimespan(); { const targetPage = page; + await scrollIntoViewIfNeeded([["#button"]], targetPage, timeout); const element = await waitForSelectors([["#button"]], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 61, @@ -97,11 +97,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later fs.writeFileSync(__dirname + '/flow.report.html', lhFlowReport) await -`; +` -exports[ - 'LighthouseStringifyExtension handles multiple sequential navigations 1' -] = ` +exports['LighthouseStringifyExtension handles multiple sequential navigations 1'] = ` const fs = require('fs'); const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -133,8 +131,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); + await scrollIntoViewIfNeeded([["#link"]], targetPage, timeout); const element = await waitForSelectors([["#link"]], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 61, @@ -148,4 +146,4 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later fs.writeFileSync(__dirname + '/flow.report.html', lhFlowReport) await -`; +` diff --git a/__snapshots__/PuppeteerStringifyExtension.test.ts.js b/__snapshots__/PuppeteerStringifyExtension.test.ts.js index f04b5403..cd533131 100644 --- a/__snapshots__/PuppeteerStringifyExtension.test.ts.js +++ b/__snapshots__/PuppeteerStringifyExtension.test.ts.js @@ -1,10 +1,8 @@ -exports[ - 'PuppeteerStringifyExtension should print the correct script for a click step 1' -] = ` +exports['PuppeteerStringifyExtension should print the correct script for a click step 1'] = ` { const targetPage = page; + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -13,17 +11,15 @@ exports[ }); } -`; +` -exports[ - 'PuppeteerStringifyExtension should print the correct script for asserted events 1' -] = ` +exports['PuppeteerStringifyExtension should print the correct script for asserted events 1'] = ` { const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -33,15 +29,13 @@ exports[ await Promise.all(promises); } -`; +` -exports[ - 'PuppeteerStringifyExtension should print the correct script with a chain selector 1' -] = ` +exports['PuppeteerStringifyExtension should print the correct script with a chain selector 1'] = ` { const targetPage = page; + await scrollIntoViewIfNeeded([["aria/Test","aria/Test2"]], targetPage, timeout); const element = await waitForSelectors([["aria/Test","aria/Test2"]], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -50,15 +44,13 @@ exports[ }); } -`; +` -exports[ - 'PuppeteerStringifyExtension should print the correct script for a change step 1' -] = ` +exports['PuppeteerStringifyExtension should print the correct script for a change step 1'] = ` { const targetPage = page; + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); const type = await element.evaluate(el => el.type); if (["select-one"].includes(type)) { await element.select("Hello World"); @@ -74,15 +66,13 @@ exports[ } } -`; +` -exports[ - 'PuppeteerStringifyExtension should print the correct script for a change step for non-text inputs 1' -] = ` +exports['PuppeteerStringifyExtension should print the correct script for a change step for non-text inputs 1'] = ` { const targetPage = page; + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); const type = await element.evaluate(el => el.type); if (["select-one"].includes(type)) { await element.select("#333333"); @@ -98,4 +88,4 @@ exports[ } } -`; +` diff --git a/__snapshots__/lighthouse-e2e.test.ts.js b/__snapshots__/lighthouse-e2e.test.ts.js index 417787a2..3ce1e9d4 100644 --- a/__snapshots__/lighthouse-e2e.test.ts.js +++ b/__snapshots__/lighthouse-e2e.test.ts.js @@ -1,6 +1,4 @@ -exports[ - 'Lighthouse user flow run via stringify produces a valid desktop flow report 1' -] = ` +exports['Lighthouse user flow run via stringify produces a valid desktop flow report 1'] = ` const fs = require('fs'); const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -27,8 +25,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later await lhFlow.startTimespan(); { const targetPage = page; + await scrollIntoViewIfNeeded(["#test"], targetPage, timeout); const element = await waitForSelectors(["#test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ button: 'left', offset: { @@ -39,8 +37,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later } { const targetPage = page; + await scrollIntoViewIfNeeded(["#test"], targetPage, timeout); const element = await waitForSelectors(["#test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ button: 'middle', offset: { @@ -55,8 +53,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); + await scrollIntoViewIfNeeded(["a[href=\\"main2.html\\"]"], targetPage, timeout); const element = await waitForSelectors(["a[href=\\"main2.html\\"]"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -69,8 +67,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later await lhFlow.startTimespan(); { const targetPage = page; + await scrollIntoViewIfNeeded(["#test"], targetPage, timeout); const element = await waitForSelectors(["#test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ button: 'left', offset: { @@ -81,8 +79,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later } { const targetPage = page; + await scrollIntoViewIfNeeded(["#test"], targetPage, timeout); const element = await waitForSelectors(["#test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ button: 'left', offset: { @@ -108,7 +106,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -245,4 +249,4 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` diff --git a/__snapshots__/stringify.test.ts.js b/__snapshots__/stringify.test.ts.js index 7944464b..7acd77ed 100644 --- a/__snapshots__/stringify.test.ts.js +++ b/__snapshots__/stringify.test.ts.js @@ -25,7 +25,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -162,11 +168,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` -exports[ - 'stringify should print the correct script for a emulateNetworkCondition step 1' -] = ` +exports['stringify should print the correct script for a emulateNetworkCondition step 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later (async () => { @@ -198,7 +202,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -335,11 +345,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` -exports[ - 'stringify should print the correct script if the target is not the main page 1' -] = ` +exports['stringify should print the correct script if the target is not the main page 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later (async () => { @@ -352,8 +360,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later const target = await browser.waitForTarget(t => t.url() === "https://localhost/test", { timeout }); const targetPage = await target.page(); targetPage.setDefaultTimeout(timeout); + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -375,7 +383,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -512,7 +526,7 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` exports['stringify should use step and flow timeouts 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -528,8 +542,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later const target = await browser.waitForTarget(t => t.url() === "https://localhost/test", { timeout }); const targetPage = await target.page(); targetPage.setDefaultTimeout(timeout); + await scrollIntoViewIfNeeded(["aria/Test"], targetPage, timeout); const element = await waitForSelectors(["aria/Test"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -551,7 +565,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -688,11 +708,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` -exports[ - 'stringify should print the correct script if the step is within an iframe 1' -] = ` +exports['stringify should print the correct script if the step is within an iframe 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later (async () => { @@ -706,8 +724,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later let frame = targetPage.mainFrame(); frame = frame.childFrames()[1]; frame = frame.childFrames()[1]; + await scrollIntoViewIfNeeded(["aria/Test"], frame, timeout); const element = await waitForSelectors(["aria/Test"], frame, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.click({ offset: { x: 1, @@ -729,7 +747,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -866,7 +890,7 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` exports['stringify should print the correct script for a keydown step 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -895,7 +919,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -1032,7 +1062,7 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` exports['stringify should print the correct script for a keyup step 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -1061,7 +1091,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -1198,7 +1234,7 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` exports['stringify should print the correct script for scroll events 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later @@ -1211,8 +1247,8 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later { const targetPage = page; + await scrollIntoViewIfNeeded(["body > div:nth-child(1)"], targetPage, timeout); const element = await waitForSelectors(["body > div:nth-child(1)"], targetPage, { timeout, visible: true }); - await scrollIntoViewIfNeeded(element, timeout); await element.evaluate((el, x, y) => { el.scrollTop = y; el.scrollLeft = x; }, 0, 40); } { @@ -1233,7 +1269,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -1370,11 +1412,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` -exports[ - 'stringify should print the correct script for waitForElement steps 1' -] = ` +exports['stringify should print the correct script for waitForElement steps 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later (async () => { @@ -1401,7 +1441,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -1538,11 +1584,9 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` -exports[ - 'stringify should print the correct script for waitForExpression steps 1' -] = ` +exports['stringify should print the correct script for waitForExpression steps 1'] = ` const puppeteer = require('puppeteer'); // v13.0.0 or later (async () => { @@ -1569,7 +1613,13 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } - async function scrollIntoViewIfNeeded(element, timeout) { + async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) { @@ -1706,4 +1756,4 @@ const puppeteer = require('puppeteer'); // v13.0.0 or later process.exit(1); }); -`; +` diff --git a/__snapshots__/stringifyStep.test.ts.js b/__snapshots__/stringifyStep.test.ts.js index e05eede8..7119b293 100644 --- a/__snapshots__/stringifyStep.test.ts.js +++ b/__snapshots__/stringifyStep.test.ts.js @@ -4,4 +4,4 @@ exports['stringifyStep should stringify a single step 1'] = ` await targetPage.goto("https://localhost/"); } -`; +` diff --git a/src/PuppeteerRunnerExtension.ts b/src/PuppeteerRunnerExtension.ts index 3efff5e1..e583d359 100644 --- a/src/PuppeteerRunnerExtension.ts +++ b/src/PuppeteerRunnerExtension.ts @@ -111,6 +111,7 @@ export class PuppeteerRunnerExtension extends RunnerExtension { switch (step.type) { case 'doubleClick': { + await scrollIntoViewIfNeeded(step.selectors, localFrame, timeout); const element = await waitForSelectors(step.selectors, localFrame, { timeout, visible: waitForVisible, @@ -118,7 +119,6 @@ export class PuppeteerRunnerExtension extends RunnerExtension { if (!element) { throw new Error('Could not find element: ' + step.selectors[0]); } - await scrollIntoViewIfNeeded(element, timeout); startWaitingForEvents(); await element.click({ clickCount: 2, @@ -133,6 +133,7 @@ export class PuppeteerRunnerExtension extends RunnerExtension { break; case 'click': { + await scrollIntoViewIfNeeded(step.selectors, localFrame, timeout); const element = await waitForSelectors(step.selectors, localFrame, { timeout, visible: waitForVisible, @@ -140,7 +141,6 @@ export class PuppeteerRunnerExtension extends RunnerExtension { if (!element) { throw new Error('Could not find element: ' + step.selectors[0]); } - await scrollIntoViewIfNeeded(element, timeout); startWaitingForEvents(); await element.click({ delay: step.duration, @@ -155,6 +155,7 @@ export class PuppeteerRunnerExtension extends RunnerExtension { break; case 'hover': { + await scrollIntoViewIfNeeded(step.selectors, localFrame, timeout); const element = await waitForSelectors(step.selectors, localFrame, { timeout, visible: waitForVisible, @@ -162,7 +163,6 @@ export class PuppeteerRunnerExtension extends RunnerExtension { if (!element) { throw new Error('Could not find element: ' + step.selectors[0]); } - await scrollIntoViewIfNeeded(element, timeout); startWaitingForEvents(); await element.hover(); await element.dispose(); @@ -198,11 +198,14 @@ export class PuppeteerRunnerExtension extends RunnerExtension { break; case 'change': { + await scrollIntoViewIfNeeded(step.selectors, localFrame, timeout); const element = (await waitForSelectors(step.selectors, localFrame, { timeout, visible: waitForVisible, })) as ElementHandle; - await scrollIntoViewIfNeeded(element, timeout); + if (!element) { + throw new Error('Could not find element: ' + step.selectors[0]); + } const inputType = await element.evaluate( /* c8 ignore start */ (el) => el.type @@ -228,11 +231,11 @@ export class PuppeteerRunnerExtension extends RunnerExtension { } case 'scroll': { if ('selectors' in step) { + await scrollIntoViewIfNeeded(step.selectors, localFrame, timeout); const element = await waitForSelectors(step.selectors, localFrame, { timeout, visible: waitForVisible, }); - await scrollIntoViewIfNeeded(element, timeout); startWaitingForEvents(); await element.evaluate( (e, x, y) => { @@ -461,9 +464,16 @@ const asSVGElementHandle = async ( }; async function scrollIntoViewIfNeeded( - element: ElementHandle, + selectors: Selector[], + frame: Frame, timeout: number ): Promise { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const svgHandle = await asSVGElementHandle(element); const intersectionTarget = svgHandle diff --git a/src/PuppeteerStringifyExtension.ts b/src/PuppeteerStringifyExtension.ts index 1aa37935..2c6a988e 100644 --- a/src/PuppeteerStringifyExtension.ts +++ b/src/PuppeteerStringifyExtension.ts @@ -133,12 +133,14 @@ export class PuppeteerStringifyExtension extends StringifyExtension { } #appendWaitForSelector(out: LineWriter, step: StepWithSelectors): void { + out.appendLine(`await scrollIntoViewIfNeeded(${JSON.stringify( + step.selectors + )}, ${step.frame ? 'frame' : 'targetPage'}, timeout);`); out.appendLine( `const element = await waitForSelectors(${JSON.stringify( step.selectors )}, ${step.frame ? 'frame' : 'targetPage'}, { timeout, visible: true });` ); - out.appendLine('await scrollIntoViewIfNeeded(element, timeout);'); } #appendClickStep(out: LineWriter, step: ClickStep): void { @@ -329,7 +331,13 @@ const helpers = `async function waitForSelectors(selectors, frame, options) { throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } -async function scrollIntoViewIfNeeded(element, timeout) { +async function scrollIntoViewIfNeeded(selectors, frame, timeout) { + const element = await waitForSelectors(selectors, frame, { visible: false, timeout }); + if (!element) { + throw new Error( + 'The element could not be found.' + ); + } await waitForConnected(element, timeout); const isInViewport = await element.isIntersectingViewport({threshold: 0}); if (isInViewport) {