Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Screenshot clip vs elementHandle.screenShot #2854

Closed
benoitjchevalier opened this issue Jul 7, 2020 · 4 comments
Closed

[Question] Screenshot clip vs elementHandle.screenShot #2854

benoitjchevalier opened this issue Jul 7, 2020 · 4 comments
Assignees

Comments

@benoitjchevalier
Copy link

Hi there,

Thanks for playwright, we've built an in house visual regression testing tool and this has helped a lot!

I have a question regarding the behavior of page.screenshot() when using the clip option. Right now if the clip area is outside the viewport or bigger than the viewport then playwright will throw an error while taking the screenshot:

Error while taking screenshot for very tall boi__Should be cut off: Error: Clipped area is either empty or outside the resulting image

I see in this issue that the alternate elementHandle.screenshot is supposed to handle scrolling the element, resizing the viewport and all that good stuff, and that the clip version of page.screenshot should follow the same behavior.

My questions are:

  • should the page.screenshot clip and elementHandle.screenshot behave similarly as stated in the the issue? Right now the page one doesn't scroll or resize viewport.

It would be sweet to be able to use the clip version without caring whether an element clip area is currently in the viewport and whether the viewport is currently big enough
We can work around limitations on our side by scrolling to the element before measuring its clip area but I'd like to avoid messing with the viewport on every screenshot since performance is paramount for us in the screenshot method

I can create some repro repo to expose the difference between the two screenshot functions if needed

@dgozman
Copy link
Contributor

dgozman commented Jul 8, 2020

Thank you for the issue!

should the page.screenshot clip and elementHandle.screenshot behave similarly as stated in the the issue? Right now the page one doesn't scroll or resize viewport.

So, clip option on the screenshot is equivalent to "clip the resulting image with this rect". You can look at it as post-screenshot processing. That means clip is different from the element screenshot. Note that if you use fullPage option, the clip is relative to the full page rect, and that should include all the content that is currently in the document's body.

Something like this should work for "area screenshot":

// Calculate your clip rect. For a single element, that's usually the same as it's bounding box.
const clipRelativeToViewport = await someElementHandle.boundingBox();

// Translate clip to be relative to the page.
const clipRelativeToPage = {
  width: clipRelativeToViewport.width,
  height: clipRelativeToViewport.height,
  x: clipRelativeToViewport + await page.evaluate(() => window.scrollX),
  y: clipRelativeToViewport + await page.evaluate(() => window.scrollY),
};

// Take an area screenshot.
const areaScreenshot = await page.screenshot({ clip: clipRelativeToPage, fullPage: true });

... I'd like to avoid messing with the viewport on every screenshot since performance is paramount for us in the screenshot method

Note that element screenshot does scroll the element into view, and I think performance does not suffer that much. More generally, taking screenshot of something not visible on the screen is hard (if not impossible) across multiple browsers, so you'll have to make the area visible on the screen anyway.

@benoitjchevalier
Copy link
Author

Thanks for the answers, that makes sense. I didn't realize clip was more of a postprocess and could be used in combination with fullpage, that's actually great. I was slightly concerned it would impact performance if it was a genuine postprocess but I had a look at the code and it looks like what I need, just resize the viewport temporarily and clip to the area before taking the screenshot :)

More generally, taking screenshot of something not visible on the screen is hard (if not impossible) across multiple browsers, so you'll have to make the area visible on the screen anyway.

If using the fullpage + clip approach do you foresee any problems then? Would you recommend forcing a scroll "just in case" (either by using elementHandle.screenshot or manually scrolling before using page + clip)?

@dgozman
Copy link
Contributor

dgozman commented Jul 8, 2020

If using the fullpage + clip approach do you foresee any problems then? Would you recommend forcing a scroll "just in case" (either by using elementHandle.screenshot or manually scrolling before using page + clip)?

Doing a fullpage screenshot is usually slower than a viewport screenshot, because it requires to relayout the whole page. If scrolling solves the issue for you, I'd suggest to scroll instead of doing fullpage. If the area you'd like to capture is larger than the viewport, you'll have to do fullpage or resize the viewport to be large enough. Overall, using elementHandle.screenshot() does all of that for you, avoiding extra work when unnecessary 😄

@benoitjchevalier
Copy link
Author

Thanks, because the code dealing with this actually runs in the browser I have additional work to do to create a unique CSS selector and pass that to the node/playwright context so the elementHandle can be retrieved, but I think it might be worth it compared to dealing with conditional, cross-browser scrolling and viewport resize. I'll head in that direction.

Thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants