Skip to content

Prevent destructive behavior in user flows #14336

@ChristopherPHolder

Description

@ChristopherPHolder

Summary

So I followed this example (more or less) https://web.dev/lighthouse-user-flows/#looking-for-feedback

What I am trying to do is navigate to a page, scroll to the bottom, and scroll back to the top.
However, if I put the scroll to the bottom in a timespan at the end it resets to the top of the page.
How do I avoid this?

    const url = new URL(targetUrl);
    const browser = await launch({headless: false});
    const page = await browser.newPage();
    const flow = await new UserFlow(page);

    const scrollAction = new ScrollAction(page);

    await flow.navigate(url.href, { stepName: "Cold Initial Navigation" });
    
     await flow.startTimespan({ stepName: 'Scroll To Bottom Of Page' } );
     await scrollAction.swipeToPageBottom();
     await flow.endTimespan();
     
     await flow.startTimespan({ stepName: 'Scroll To Top Of Page' });
     await scrollAction!.swipeToPageTop();
     await flow.endTimespan();
     
     const report = await flow.createFlowResult();
     await browser.close();

and the scroll action

import { CDPSession, Page, Protocol } from "puppeteer";

export class ScrollAction {
 private session?: CDPSession;
 constructor(private page: Page) {}

 async swipeToPageBottom(): Promise<void> {
   await this.page.waitForSelector("body");
   await this._synthesizeTouchScroll('down');
 }

 async swipeToPageTop(): Promise<void> {
   await this.page.waitForSelector("body");
   await this._synthesizeTouchScroll('up');
 }

 private async _synthesizeTouchScroll(direction: 'down' | 'up'): Promise<void> {
   const scrollParams = await this._getScrollParams(direction);
   if (!this.session) {
     this.session = await this.page.target().createCDPSession();
   }
   // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-synthesizeScrollGesture
   await this.session.send('Input.synthesizeScrollGesture', scrollParams);
 }

 private async _getScrollParams(direction: 'down' | 'up'): Promise<Protocol.Input.SynthesizeScrollGestureRequest> {
   const innerHeight = await this._getInnerContentHeight();
   const x = 200;
   const y = direction === 'up' ? 200 : 600;
   const scrollDistance = 1500;
   const speed = 800;
   const repeatDelayMs = 250;
   const yDistance = direction === 'up' ? scrollDistance : scrollDistance * (-1);
   const repeatCount = Math.ceil(innerHeight/scrollDistance) -1;
   const gestureSourceType = 'touch';
   return {x, y, yDistance, speed, repeatCount, repeatDelayMs, gestureSourceType};
 }

 private async _getInnerContentHeight(): Promise<number> {
   const innerContentHandle = await this.page.$("body");
   const innerContentBox = await innerContentHandle!.boundingBox(); 
   return innerContentBox!.height;
 }
}

Now what is interesting is that if I remove the timestamp it works fine.
If I don't, its scrolls to the bottom and then appears at the top and tries to scroll from there.

What am I doing wrong or is it a config that I am missing?
Thanks so much in advance :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions