Scroll to load more content
Let actions scroll for you, reveal a known element, or drive infinite scroll and wait for new items.
Most of the time you do not scroll on purpose. A locator action scrolls its target into view before it acts, so clicking or asserting an item that starts off-screen already works. You scroll explicitly only to trigger loading, such as an infinite feed.
Let the action scroll for you
click(), check(), fill(), and the other actions bring their element into view first. An item below the fold needs no separate scroll step.
$page->goto('https://app.example.test/feed');
// The button is off-screen; the click scrolls to it first.
$page->getByRole('button', ['name' => 'Load older posts'])->click();
Do not add a manual scroll before an action. The action handles it, and the element is re-resolved once it is actionable.
When scrolling is itself the behavior you need to verify, call scrollIntoViewIfNeeded() explicitly:
$footer = $page->getByRole('contentinfo');
$footer->scrollIntoViewIfNeeded();
expect($footer)->toBeVisible();
Trigger infinite scroll with the mouse wheel
When new content loads because the viewport reaches the bottom, drive that with the mouse wheel. wheel() takes a horizontal and a vertical delta, both in pixels.
$page->mouse()->wheel(0, 4000);
Each call scrolls by the delta. Repeat it to keep loading pages of content until you have enough.
Wait for the new items, not the clock
After scrolling, wait for the count of items to grow. toHaveCount() polls until the list reaches the expected size, so the test proceeds as soon as the new items render.
$posts = $page->getByRole('article');
$page->mouse()->wheel(0, 4000);
expect($posts)->toHaveCount(20);
A locator matches every element, so getByRole('article') counts all posts. The assertion replaces a fixed wait: it succeeds the moment the twentieth post exists.
Load several pages in a loop
To reach a known size, scroll and assert in a loop until the target count holds.
$posts = $page->getByRole('article');
while (($before = $posts->count()) < 60) {
$page->mouse()->wheel(0, 4000);
expect($posts)->toHaveCount(min($before + 20, 60));
}
This loop assumes the product appends batches of 20. count() records the size before each scroll; toHaveCount() waits for the next known batch. If the product uses variable batch sizes, wait for a page marker or another product signal instead of guessing a count.
Pitfalls
- Do not use a fixed wait after scrolling.
sleep(2)waits for the clock;toHaveCount()waits for the items. - Use
scrollIntoViewIfNeeded()to reveal one known element. Use the mouse wheel when scrolling itself triggers the next batch. wheel()scrolls by a delta, not to a position. Repeat it to keep going.
Expected result
The feed contains the new items, and the count assertion proves they rendered. If the product shows an end-of-list marker, assert that marker when no more content should load.