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

[BUG] chromium and webkit screenshot ignoring screenshot: clip: height option property #1030

Closed
aesyondu opened this issue Feb 15, 2020 · 6 comments · Fixed by #1156
Closed
Assignees

Comments

@aesyondu
Copy link
Contributor

aesyondu commented Feb 15, 2020

Context:

  • Playwright Version: 0.11.1
  • Operating System: Mac OS X 10.14.6
  • Extra: node@11.15.0 npm@6.7.0

Code Snippet
Full repo:
https://github.com/aesyondu/javascript-questions/tree/tmp/playwright-sample

Specific commit:
aesyondu/javascript-questions@4d9b189

index.js

const path = require("path")
const { firefox } = require("playwright-firefox");
const { chromium } = require("playwright-chromium");
const { webkit } = require("playwright-webkit");

(async () => {
    const browser = await firefox.launch({ headless: false })
    // const browser = await chromium.launch({ headless: false })
    // const browser = await webkit.launch({ headless: false })
    const context = await browser.newContext()
    context.setDefaultTimeout(9999999)
    const page = await context.newPage()

    await page.goto(`file:${path.join(__dirname, "index.html")}`) // 2. firefox not resolving page.goto file:
    console.log("FIREFOX not outputting this")

    const question = await page.$("h6[id^='1']")
    const {x: xStart, y: yStart, width: widthStart} = await question.boundingBox()

    const limit = await page.$("h6[id^='2']")
    const {x: xEnd, y: yEnd} = await limit.boundingBox()

    const heightCalc = yEnd - yStart
    const heightCalc2 = (yEnd - yStart) * 2
    console.log(yStart, yEnd, heightCalc)
    await page.screenshot({
        clip: {
            x: xStart,
            y: yStart,
            width: widthStart,
            height: 1000, // 2. chromium and webkit not using the height here
        },
        // path: "./chromium.png",
        path: "./webkit.png",
    })
    console.log("FINISH")
    await browser.close()
})()

Describe the bug
Using screenshot: clip: height, the height is ignored, and is capped at 177px. However, if I change it to height: 10, it becomes 10px.

Couldn't test with firefox due to the page.goto: file bug. It's already reported.

@aesyondu aesyondu changed the title [BUG] chromium and webkit screenshot ignoring height [BUG] chromium and webkit screenshot ignoring screenshot: clip: height Feb 15, 2020
@aesyondu aesyondu changed the title [BUG] chromium and webkit screenshot ignoring screenshot: clip: height [BUG] chromium and webkit screenshot ignoring screenshot: clip: height option property Feb 15, 2020
@aesyondu
Copy link
Contributor Author

aesyondu commented Feb 15, 2020

I'm expecting that I shouldn't need to manually scroll to the element just to screenshot it.

However, I tried scrollIntoViewIfNeeded but it didn't really change the output, presumably because the element is already ratio == 1. I tried manual browser eval and it did change the output. But after I commented out my code, chromium output permanently changed and I couldn't replicate the initial result (now has 221px height), but webkit stayed the same. Now I don't know what's going on. Maybe I'm just using these properties wrong?

    const question = await page.$("h6[id^='1']")
    // await question.scrollIntoViewIfNeeded() // NOT WORKING since already ratio == 1, ARGHH!
    const {x: xStart, y: yStart, width: widthStart} = await question.boundingBox()

    const limit = await page.$("h6[id^='2']")
    const {x: xEnd, y: yEnd} = await limit.boundingBox()

    // await page.$eval("h6[id^='1']", (node, y) => {
    //     window.scrollTo(0, y)
    // }, yStart)

Commit ref:
aesyondu/javascript-questions@65d443b

@aesyondu
Copy link
Contributor Author

aesyondu commented Feb 15, 2020

I now tried changing the page viewport height, it changed the output of webkit significantly, but chromium output stayed the same:

    const page = await context.newPage({
        viewport: {
            height: 2000,
        }
    })

Commit ref:
aesyondu/javascript-questions@58e471d

@pavelfeldman
Copy link
Member

pavelfeldman commented Feb 15, 2020

It is a little tricky to repro this w/o the source page While I am trying to repro locally, did you consider using

const limit = await page.$("h6[id^='2']");
await limit.screenshot({path:...});

@pavelfeldman
Copy link
Member

Ah, I think I understand what you are doing - you need a whole section. Let me see if we can help you here.

@pavelfeldman
Copy link
Member

pavelfeldman commented Feb 15, 2020

Ok, poked at it. Thank you for a nice repo with the script.

  • The problem with the height is that we screenshot the intersection of the provided clip and the viewport. In your case, height was falling off the viewport and hence was ignored
  • The problem with the scrollIntoViewIfNeeded is that it centers the element and you can't center both start of the topic and the end of the topic - something goes behind the viewport
  • Another problem is that Chromium will not capture beyond the 13-th topic (4K pixels).

We will hunt all three problems to make sure it works as expected.

For now,elementHandle.screenshot is your best friend since we scroll, resize the viewport and do everything it takes to capture it. Action item for ourselves here is to make clip work the same way instead of intersecting with the viewport.

Following worked for me on 0.11.1 on Firefox and WebKit. Chromium made first 14 snippets. I guess you can delete them dynamically to capture all in Chromium as well.

const path = require("path")
const { chromium, webkit, firefox } = require("playwright");

(async () => {
    const browserType = webkit;
    const browser = await browserType.launch()

    // I'm using deviceScaleFactor = 2 to make images render in high dpi
    const page = await browser.newPage({ viewport:
        { width: 800, height: 600, deviceScaleFactor: 2 }
    })

    // Playwright does not yet support file:// in Firefox
    // I had to serve this on localhost for Firefox to work 
    await page.goto(`http://localhost:5000/index.html`)

    const count = await page.evaluate(() => document.querySelectorAll("h6").length)
    for (let i = 0; i < count; ++i) {
        const topic = await page.evaluateHandle(index =>
            document.querySelectorAll("h6").item(index), i)
        console.log(`Capturing ${await topic.evaluate(e => e.innerText)}`)

        // Create a transparent box, we will be screenshotting it.
        const box = await topic.evaluateHandle(question => {
            let limit = question
            while (limit && limit.nextElementSibling && limit.nodeName !== "DETAILS")
                limit = limit.nextElementSibling
            const questionRect = question.getBoundingClientRect()
            const limitRect = limit.getBoundingClientRect()

            const box = document.createElement("div")
            const y = document.documentElement.scrollTop + questionRect.y - 5;
            const height = limitRect.y - questionRect.y;
            box.style = `pointer-events: none; position: absolute; left: 0; right: 0; top: ${y}px; height: ${height}px;`
            document.body.appendChild(box)
            return box;
        }, topic)
        await box.screenshot({ path: `./${browserType.name()}_${i + 1}.png` })
        await box.evaluate(e => e.remove())
    }

    console.log("FINISH")
    await browser.close()
})()

@aesyondu
Copy link
Contributor Author

Very nice, didn't think about the elementHandle.screenshot. Thanks!

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

Successfully merging a pull request may close this issue.

3 participants