I have an array-like object of nodes (it is a carousel), their order is randomly generated with each page refresh, playwright finds all the elements to be visible, but some of them are outside the viewport (based on the error received). I need to make sure, that element is inside the viewport when attempting to click it, otherwise I get an error stating the element is outside.
How to determine if a randomly picked node element of an array-like object is actually within the viewport?
Playwright has added a feature to enable checking this using "expect". The usage info is below:
(method) LocatorAssertions.toBeInViewport(options?: {
ratio?: number;
timeout?: number;
}): Promise<void>
Ensures the Locator points to an element that intersects viewport, according to the intersection observer API.
Usage
const locator = page.getByRole('button');
// Make sure at least some part of element intersects viewport.
await expect(locator).toBeInViewport();
// Make sure element is fully outside of viewport.
await expect(locator).not.toBeInViewport();
// Make sure that at least half of the element intersects viewport.
await expect(locator).toBeInViewport({ ratio: 0.5 });
Playwright unfortunately doesn't have a method like isInterSectingViewport in Puppeteer yet.(likethis)
So authors of Playwright help me in Slack community(you can find it on official site).
const result = await page.$eval(selector, async element => {
const visibleRatio: number = await new Promise(resolve => {
const observer = new IntersectionObserver(entries => {
resolve(entries[0].intersectionRatio);
observer.disconnect();
});
observer.observe(element);
// Firefox doesn't call IntersectionObserver callback unless
// there are rafs.
requestAnimationFrame(() => {});
});
return visibleRatio > 0;
});
The case in which I used this method: I want know that after I’m click some element - I have scrolling to another element. Unfortunately boundingBox method doesn’t help in my case.
also You can add this functionality to my BasePage class
/**
* @returns {!Promise<boolean>}
*/
isIntersectingViewport(selector: string): Promise<boolean> {
return this.page.$eval(selector, async element => {
const visibleRatio: number = await new Promise(resolve => {
const observer = new IntersectionObserver(entries => {
resolve(entries[0].intersectionRatio);
observer.disconnect();
});
observer.observe(element);
// Firefox doesn't call IntersectionObserver callback unless
// there are rafs.
requestAnimationFrame(() => {});
});
return visibleRatio > 0;
});
}
P.S. In fact, all the code except for one line is taken from the realisation of method isInterSectingViewport in GitHub Puppeteer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With