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

elementHandle.screenshot() produces blank screenshots for elements outside of viewport #2423

Open
darkcody opened this Issue Apr 20, 2018 · 8 comments

Comments

Projects
None yet
6 participants
@darkcody

darkcody commented Apr 20, 2018

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: 1.3.0
  • Platform / OS version: OS X 10.12.6
  • URLs (if applicable): N/A (Test script uses https://github.com but I've noticed the issue on other pages)
  • Node.js version: 8.1.4

What steps will reproduce the problem?
Using elementHandle.screenshot in the following test script, capturing an element outside of the viewport results in a blank / empty screenshot.

Please include code that reproduces the issue.

import puppeteer from 'puppeteer';

const VIEWPORT = {width: 1200, height: 900};
const URL = 'https://github.com/';
const TESTELEMENT = '.footer';

(async () => {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();
  await page.setViewport(VIEWPORT);
  await page.goto(URL, { waitUntil: 'networkidle0' });


  // Full page screenshot.
  await page.screenshot({
    path: 'tmp/testPage.png',
    fullPage: true
  });

  // Screenshot using element handle.
  const element = await page.$(TESTELEMENT);
  await page.waitFor(1000);
  await element.screenshot({
    path: 'tmp/testElement.png',
  });

  // Screenshot using the element's bounding box.
  const elementBounds = await element.boundingBox();
  await page.screenshot({
    path: 'tmp/testClip.png',
    clip: elementBounds,
  });

  await browser.close();
})()

What is the expected result?

The screenshot taken using the element handle should capture the footer for the url provided. The screenshot that supplies the element's bounding box should also capture the footer.

What happens instead?

The full page screenshot is fine, but the other two are blank (white). If I adjust the script and increase the viewport height to something really large, like 9999px, the footer is within the initial viewport and the problematic screenshot come out fine.

@VesterDe

This comment has been minimized.

VesterDe commented Apr 20, 2018

I'm having a similar issue with Puppeteer, but for me out-of-viewport elements otherwise work, but seem to fail if the distance (x/y) and/or size(w/h) of the element contain decimals.

A minimal script that replicates this can be found here. Run that through https://try-puppeteer.appspot.com/ and it will log the bounding rectangles for both selectors.

@darkcody

This comment has been minimized.

darkcody commented Apr 20, 2018

@VesterDe, I can confirm the element I attempted to capture also has a vertical offset containing decimals.

The issue also seems to begin with puppeteer v1.2. Both my test script and @VesterDe's script produce the expected results with version 1.1.1

@darkcody darkcody changed the title from elementHandle.screenshot() produces blank screenshots for elements outside of viewport to elementHandle.screenshot() produces blank screenshots for elements outside of viewport when the element's bounding box contains decimal values Apr 20, 2018

@darkcody darkcody changed the title from elementHandle.screenshot() produces blank screenshots for elements outside of viewport when the element's bounding box contains decimal values to elementHandle.screenshot() produces blank screenshots for elements outside of viewport Apr 20, 2018

@bclinkinbeard

This comment has been minimized.

bclinkinbeard commented Apr 21, 2018

I'm seeing some weird coordinates issues with elementHandle.screenshot() in 1.3 as well. I have a script that captures the code blocks from all of my blog pages and for one specific page the coordinates are all off.

One of many working pages: https://benclinkinbeard.com/d3tips/utility-methods-with-d3-array/
The only problem page: https://benclinkinbeard.com/d3tips/a-reusable-function-for-creating-charts-with-axes/
Relevant code from a set of utils I'm using:

async function initPuppeteer(options = { args: ['--no-sandbox'] }) {
  const browser = await puppeteer.launch(options)
  const page = await browser.newPage()
  return { browser, page }
}

async function getScreenshotBuffer(page, selector) {
  let buffers = []

  if (!selector) {
    buffers = [await page.screenshot()]
  } else {
    const targets = await page.$$(selector)
    const promises = targets.map(elHandle => elHandle.screenshot())
    buffers = await Promise.all(promises)
  }

  return buffers
}

async function getBuffersFromURL(
  url,
  width = 2000,
  height = 800,
  selector = 'div.highlight',
) {
  const { browser, page } = await initPuppeteer()
  page.setViewport({ width, height, deviceScaleFactor: 2 })
  await goToURL(page, url)
  const buffers = await getScreenshotBuffer(page, selector)
  await browser.close()
  return buffers
}

Instead of getting that very simple first code block I get this:

image

@bclinkinbeard

This comment has been minimized.

bclinkinbeard commented Apr 22, 2018

I'm also seeing weirdness that is not just coordinate offsets. It's hard to tell in the GitHub UI but there is a big white bar at the top of the below image where the opening tag should be.

d3-day-3-building-a-real-bar-chart_01

@bclinkinbeard

This comment has been minimized.

bclinkinbeard commented Apr 22, 2018

Related to #2263, #2357, and/or #2166 ?

@bclinkinbeard

This comment has been minimized.

bclinkinbeard commented Apr 22, 2018

I solved my problem. Several concurrent calls to elementHandle.screenshot() is apparently not feasible, which makes sense when you slow it down and see how it works. I made the following change to grab screenshots serially instead of in parallel.

const handles = await page.$$(selector)

// no more of this
// const promises = [targets[0]].map(elHandle => elHandle.screenshot())
// buffers = await Promise.all(promises)

// this instead
while (handles.length) {
  const handle = handles.shift()
  const buffer = await handle.screenshot()
  buffers.push(buffer)
}
@delesseps

This comment has been minimized.

delesseps commented Apr 30, 2018

Experiencing same issue scrolling to capture elements outside the viewport, in my case floating tooltips.

I've noticed it only happens in headless mode, changing config to headless: false seems to resolve if that helps identifying the problem/finding a solution.

@seraphinmiranda

This comment has been minimized.

seraphinmiranda commented Aug 16, 2018

I also had the same issue one hour ago ^^
I solved the problem by changing to a higher viewport.

@aslushnikov aslushnikov added the chromium label Dec 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment