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

"Non-deterministic" screenshots after viewport resize #1751

Closed
inakianduaga opened this issue Jan 9, 2018 · 8 comments
Closed

"Non-deterministic" screenshots after viewport resize #1751

inakianduaga opened this issue Jan 9, 2018 · 8 comments
Labels
chromium Issues with Puppeteer-Chromium unconfirmed

Comments

@inakianduaga
Copy link

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: 0.13.0
  • Platform / OS version: MacOS, (also Debian under docker)
  • URLs (if applicable):
  • Node.js version: 8.9.4

What steps will reproduce the problem?

  1. Render some JS for a fixed code for different viewports
 const viewports: [
    { width: 320, height: 800 },
    { width: 400, height: 800 },
    { width: 768, height: 600 },
    { width: 1024, height: 400 },
    { width: 1280, height: 400 }
  ],

  test('correctly renders home bike fragment', async () => {
    const page = await browser.newPage()
    await page.goto(`http://localhost:3000/somePageWithFixedHtmlJsCss`)

    for (const viewport of viewports) {
      await page.setViewport(viewport)
      const screenshot = await page.screenshot()
      expect(screenshot).toMatchImageSnapshot(settings.jest_image) // Jest expectation to determine if screenshot has changed compared to last run
    }
  })
  1. Compare snapshots using Jest

What is the expected result?

Snapshots shouldn't change between runs since the html / JS is fixed (so test should pass)

What happens instead?

Tests sometime fail, due to snapshots differing slightly for some viewports, assumption is that the screenshot call comes before chrome has had time to fully render the content.

Is there any hook to find out that chrome has finished rendering that I could add after the viewport resize and before the snapshot?

@JoelEinbinder
Copy link
Collaborator

It’s hacks, but you could try evaluating and awaiting a requestAnimationFrame inside the page. I’m not sure what we wait on to decide the viewport had been resized.

@inakianduaga
Copy link
Author

So you mean after awaiting for the viewport resize I add a dummy requestAnimationFrame and await for it, which would ensure after that the browser is finished rendering. Makes sense, I'll give it a shot.

And one last thing, browser rendering is deterministic right? If I wait long enough after rendering the same code should render identically right? (assuming code doesn't do stuff over time)

@dowsanjack
Copy link

@inakianduaga did requestAnimationFrame hack work for you?

@inakianduaga
Copy link
Author

inakianduaga commented Jan 27, 2018

@dowsanjack
This is what seems to be working well for us (using a 0.005 threshold for snapshot failure in comparisons).

  async function setViewport(page: puppeteer.Page, viewport: { width: number; height: number }) {
    const watchDog = page
      .mainFrame()
      .waitForFunction(`window.innerWidth === ${viewport.width} && window.innerHeight === ${viewport.height} `)

    await page.setViewport(viewport)
    await watchDog
  }

using this for changing the viewport, plus running the whole thing in a dockerized container (to prevent local macOS / CI linux differences in font rendering and what not)

FROM node:8.5.0

RUN apt-get update
RUN	apt-get install -y \
	gconf-service \
	libasound2 \
	libatk1.0-0 \
	libc6 \
	libcairo2 \
	libcups2 \
	libdbus-1-3 \
	libexpat1 \
	libfontconfig1 \
	libgcc1 \
	libgconf-2-4 \
	libgdk-pixbuf2.0-0 \
	libglib2.0-0 \
	libgtk-3-0 \
	libnspr4 \
	libpango-1.0-0 \
	libpangocairo-1.0-0 \
	libstdc++6 \
	libx11-6 \
	libx11-xcb1 \
	libxcb1 \
	libxcomposite1 \
	libxcursor1 \
	libxdamage1 \
	libxext6 \
	libxfixes3 \
	libxi6 \
	libxrandr2 \
	libxrender1 \
	libxss1 \
	libxtst6 \
	ca-certificates \
	fonts-liberation \
	libappindicator1 \
	libnss3 \
	lsb-release \
	xdg-utils \
	wget

@alixaxel
Copy link
Contributor

@JoelEinbinder Could this be the same issue I'm seeing in #1910? If so, wouldn't it then make sense to have the waitForFunction that @inakianduaga shared part of the default setViewport logic?

@ysgk
Copy link

ysgk commented Oct 26, 2018

I had the same problem. In my case, requestAnimationFrame worked perfectly.

await page.setViewport({
  width,
  height,
})

await page.evaluate(() => {
  return new Promise((resolve) => {
    window.requestAnimationFrame(resolve)
  })
})

await page.screenshot({
  path: filePath,
  fullPage: true,
})
  • MacOS
  • node: 8.12.0
  • puppeteer: 1.9.0

@aslushnikov aslushnikov added the chromium Issues with Puppeteer-Chromium label Dec 6, 2018
@stale
Copy link

stale bot commented Jun 27, 2022

We're marking this issue as unconfirmed because it has not had recent activity and we weren't able to confirm it yet. It will be closed if no further activity occurs within the next 30 days.

@stale stale bot added the unconfirmed label Jun 27, 2022
@stale
Copy link

stale bot commented Jul 27, 2022

We are closing this issue. If the issue still persists in the latest version of Puppeteer, please reopen the issue and update the description. We will try our best to accomodate it!

@stale stale bot closed this as completed Jul 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chromium Issues with Puppeteer-Chromium unconfirmed
Projects
None yet
Development

No branches or pull requests

6 participants