GoogleChrome / GoogleChrome/lighthouse

Prevent destructive behavior in user flows

Open
#14,336 9 comments 0 reactions 0 assignees View on GitHub
fraggle-rock P2
Dominant language
JavaScript
Stars
30.8k
Forks
9.8k
Avg merge
1d 14h
Merged PRs (30d)
20

Description

**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?

```ts
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

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

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

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

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

private async _synthesizeTouchScroll(direction: 'down' | 'up'): Promise {
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 {
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 {
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 :)

Contributor guide

Open the contributing guide

Research direction

Start with the Lighthouse user-flow entry points in the report: startTimespan(), endTimespan(), and createFlowResult(). Reproduce the supplied navigation and custom ScrollAction example, then trace how the timespan is handled around the scroll gesture. Done means the scroll sequence no longer resets to the top when wrapped in a timespan, with the behavior covered by an appropriate test.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.