microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
63.84k stars 3.46k forks source link

[Bug]: Element screenshot causes flickering/shaking #29487

Closed jeff-an closed 1 month ago

jeff-an commented 4 months ago

Version

1.40.1

Steps to reproduce

  1. clone this repo: https://github.com/jeff-an/playwright-bug-report
  2. npm install && npx playwright install
  3. node main.js

Expected behavior

The screen does NOT flicker black when the screenshot is taken

Actual behavior

It happens very quickly, but when the screenshot is taken, it looks like the rest of the viewport minus the element being captured flickers black. it also looks like the element being screenshotted, which is an iframe in this case, expands a little before returning to its original size. this happens for maybe ~0.25 seconds but is very jarring.

Additional context

Could be a recurrence of https://github.com/microsoft/playwright/issues/2576. The almost exact same symptoms was reported in https://github.com/microsoft/playwright/issues/6920, which ended up closed since it didn't have a repro. Maybe the fixes applied as a result of 2576 need to be applied to element-specific screenshots as well?

The actual type of the element doesn't seem to matter; I can repro with as well.

Setting viewport: null, reducedMotion: reduce, or devicePixelRatio: 2 (or any other value) does not seem to help.

Environment

System:
    OS: macOS 14.0
    CPU: (8) arm64 Apple M1 Pro
    Memory: 125.95 MB / 16.00 GB
  Binaries:
    Node: 20.9.0 - ~/.nvm/versions/node/v20.9.0/bin/node
    npm: 10.1.0 - ~/.nvm/versions/node/v20.9.0/bin/npm
    pnpm: 8.7.6 - ~/Library/pnpm/pnpm
  IDEs:
    VSCode: 1.86.1 - /Applications/Visual Studio Code.app/Contents/Resources/app/bin/code
  Languages:
    Bash: 3.2.57 - /bin/bash
mxschmitt commented 4 months ago

I was able to reproduce the flickering/shaking between during the Page.captureScreenshot CDP call.

jeff-an commented 4 months ago

if I wanted to attempt to contribute a fix here, do you guys have any pointers in terms of where to start? i.e. do you have a general sense of why this is happening? thanks!

dgozman commented 3 months ago

@jeff-an This is how screenshots in Chromium work. If you are capturing a specific area of the page, which is the case for the element screenshot, Chromium translates that area to the top-left for a single frame, and then takes the screenshot.

In some circumstances it is theoretically possible to avoid this by clipping the viewport screenshot, given that element has integer absolute coordinates and fits the viewport, but that's extra complexity that neither Chromium nor Playwright would like to have.

I don't think this is going to be fixed in the near future. Apart from aesthetics, this does not seem to have any impact on the automatic testing. In fact, you should probably run your tests in the headless mode and not see the page at all. What's your usecase for this?

jeff-an commented 3 months ago

We're building a managed testing service on top of playwright, and we need headful mode to render some UI that helps the engineer see what step they are currently executing and allow them to interact with the app manually, similar to the idea behind Playwright codegen. We take screenshots of relevant elements on the page for debugging purposes and to support features like visual diffing, but the flicker is quite jarring for the user to see.

dgozman commented 3 months ago

@jeff-an I see, thanks! As a workaround, I'd recommend to call page.screenshot() and then clip it to your liking, for example by calling locator.boundingBox() to determine the clip rect. I'll leave this issue open for prioritization, but I do not expect this to be our focus in the near future.

jeff-an commented 3 months ago

Appreciate the tip @dgozman! Do you know if locator.boundingBox() has issues with different deviceScaleFactors? A while back we did some prototyping with clicking elements with CDP using the bounding box rectangles, and the rectangles were wrong if the user was running on a high pixel density monitor like Retina. We concluded that the true device pixel ratio on the user's system could not be accurately determined by our software before initializing the playwright browser.

dgozman commented 3 months ago

@jeff-an boundingBox() should return css pixels independent of deviceScaleFactor. So if you get a device-resolution screenshot on the high-dpi display, you'll need to scale the bounding box accordingly.

jeff-an commented 1 month ago

Sorry for the late response! I was able to get this working with the scale option set to css as well as the sharp library.