puppeteer: Behavior of setViewport() inconsistent in Headful

Environment:

  • Puppeteer: 1.0.0
  • Platform / OS: Ubuntu 16.04 LTS (1920x1080@1x)
  • Node.js: 8.9.3
  • Chromium: 65.0.3312.0 (Developer Build) (64-bit)

What steps will reproduce the problem?

Running the following code several times.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: [
      '--start-maximized',
    ],
    headless: false,
  });

  const page = await browser.newPage();

  /**
   * This should make Chromium infer current screen resolution (only in headless = false).
   */
  await page.setViewport({
    width: 0,
    height: 0,
  });

  await page.goto('http://matanich.com/test/viewport-width', {
    waitUntil: [
      'domcontentloaded',
      'load',
    ],
  });

  let result = await page.evaluate(
    () => {
      return window.innerWidth;
    }
  );

  console.log(`Detected window.innerWidth to be ${result}.`);

  await browser.close();
})();

What is the expected result?

I should get the save window.innerWidth all the time.

What happens instead?

Seems that sometimes setViewport() fails silently and fallbacks to the default viewport size of 800x600.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 800.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 800.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 1
  • Comments: 19 (10 by maintainers)

Most upvoted comments

I was struggling with a similar issue (trying to resize the viewport in headless), but thanks to aslushnikov’s answer on another thread I was able to use this workaround function for both headful and headless modes:

async function setWindowSize(page, width, height) {
  if(headless) {
    const session = await page.target().createCDPSession();
    const {windowId} = await session.send('Browser.getWindowForTarget');
    await session.send('Browser.setWindowBounds', {windowId, bounds: {width: width, height: height}});
    await session.detach();
  } else {
    await page.setViewport({width: width, height: height});
  }
}

Apologies that it isn’t the most idiomatic async Javascript code…

I would use Browser.setWindowBounds() everywhere, but unfortunately it has inconsistent behavior in headful. It doesn’t seem to account for the dimensions of UI elements like the address bar and navigation controls. Which would make sense since those probably don’t exist in headless mode.

Maybe someone can put together a workaround that measures the width/height differences between the two methods upon the first call in headful, then accounts for those differences during subsequent calls. That way Browser.setWindowBounds() could be used everywhere until the Puppeteer devs get time to fix this.

Note that the width also seems to be inconsistent, but that could be due to css rules in my project. Also the sizes are different between headless and headful, so to avoid a bunch of false positives, you’ll need to run your tests completely in one mode or the other for now. In my case that’s fine, since I was just trying to make window resizing work headless.

If any of the devs read this, please please remove all runtime differences due to implementation details between headful and headless. We shouldn’t have to worry about the window bounds not working just because we’re running headless. I realize that this is probably a goal of yours, and that you probably have your hands tied by the Chrome devs not realizing the we still need to resize windows during development:

https://bugs.chromium.org/p/chromium/issues/detail?id=2091

I can’t reproduce this as of puppeteer v1.7.0. @alixaxel is this still relevant to you?

P.S. There’s now a defaultViewport: null option that you can pass to puppeteer.launch to disable viewport overrides.

@alixaxel Thanks very much. I mean I can create a page demo that show 100% viewport.

my english is poor 😶🙃🙂

@aizuyan You don’t need to delete it, can just pass appMode: true to Browser options:

https://github.com/GoogleChrome/puppeteer/blob/f2b6016354670ed8300285e0ae25894e3bc5c8e9/lib/Launcher.js#L68-L69

However, I have no idea what this option is for, it’s not documented anywhere.


BTW, care to clarify what you mean by “that be ok”?

Also experimented adding a await page.waitFor(500); after setViewport() and goto().

Same results. 😕