Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
723 views
in Technique[技术] by (71.8m points)

selenium - How can I screenshot the full height of a mobile form factor?

When testing mobile form factors, Chrome screenshots just the visible window. I'm fine with that being the standard and expected behaviour. However, I additionally want to capture the full scrolled height of the page so I can inspect the rendering of the entire page.

I thought the simplest solution was to set the chrome window height to be a sufficiently large value, and job done. However, the Chrome window height seems bound by my physical screen height, ie. I set it to 5,000 with browser.manage().window().setSize(375,5000);, but it only resizes to a height of 1,200.

I already know [According to the WebDriver specification][1], the [takeScreenshot() function][2] is not supposed to capture the entire page, but should make a screenshot of the visible area only.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OP EDIT: I went with the final option below which I've labelled "Working solution!!"

Below are the different grouped by type strategies to solve the problem.


Scroll, take screenshot, append

Quoting the author of the screenshot system at the CrossBrowserTesting.com:

As the author of the screenshot system for CrossBrowserTesting.com, I can tell you that the only way we've been able to get full page screenshots consistently and reliably across browsers is to scroll, capture, and append images.

Here is a sample working implementation of scrolling and taking visible area screenshots using cnn.com as an example target. Using scrollHeight, clientHeight and scrollTop to determine where we are on a vertical scroll position and how much more to scroll down. Since we are dealing with promises in a loop, we have to make a recursive function with a "we are at the bottom" base condition:

var fs = require('fs'),
    Utils = {
        screenShotDirectory: '',

        writeScreenShot: function (data, filename) {
            var stream = fs.createWriteStream(this.screenShotDirectory + filename);

            stream.write(new Buffer(data, 'base64'));
            stream.end();
        },

        getSizes: function () {
            return browser.executeScript("return {scrollHeight: document.body.scrollHeight, clientHeight: document.body.clientHeight, scrollTop: document.body.scrollTop};");
        },

        scrollToBottom: function (height, index) {
            var self = this;

            self.getSizes().then(function (data) {
                // continue only if we are not at the bottom of the page
                if (data.scrollTop + data.clientHeight < data.scrollHeight) {
                    browser.executeScript("window.scrollTo(0, arguments[0]);", height).then(function () {
                        browser.takeScreenshot().then(function (png) {
                            self.writeScreenShot(png, "test" + index + ".png");
                        });
                    });
                    self.scrollToBottom(height + data.clientHeight, index + 1);
                }
            });
        }
    };

describe("Scrolling and saving screenshots", function () {
    beforeEach(function () {
        browser.ignoreSynchronization = true;
        browser.get("http://www.cnn.com/");
    });

    it("should capture an entire page", function () {
        Utils.getSizes().then(function (data) {
            Utils.scrollToBottom(data.clientHeight * 2, 1);
        });
    });
});

It would produce multiple test<index>.png images that you can then glue together.

To concatenate images in a "single column image", you may, for instance, use the GraphicsMagick Image Processing System through the gm nodejs module. The .montage() method with the concatenate option in the 1x mode would be helpful. Sample code:

var gm = require('gm');

Utils.getSizes().then(function (data) {
    var index = Utils.scrollToBottom(data.clientHeight * 2, 1);

    var op = gm();
    for (var i = 1; i <= index; i++) {
        op = op.in("test" + i + ".png");
    }

    op = op.montage().mode("concatenate").tile("1x");
    
    op.write('output.png', function (err) {
        if (err) console.log(err);
    });
});

Change the Browser

In Chrome, you would always get only the visible area on the resulting screenshot, here is the relevant chromedriver issue with a lot of information about the issue and multiple workarounds:

Somewhat surprisingly, it should though work in Firefox - switch to it if possible:

Chrome screenshots that take up the entire screen are not like Firefox's. Firefox will capture the entire screen, even parts of it that are not currently viewable. Chrome will not!


Tweak the Screen Size

Another option would be to use services like BrowserStack or SauceLabs to start your tests on a specific platform in a specific browser and, using a specific large enough resolution. Protractor supports Sauce Labs and BrowserStack out-of-the-box.

Example configuration for BrowserStack:

exports.config: {
  browserstackUser: "user",
  browserstackKey: "key",

  capabilities: {
    'browserstack.local': true,
    'browserstack.debug': true,
 
    browserName: "Chrome",
    os: "Windows",
    os_version: "8",
    resolution: "2048x1536"
  },
}

Then, maximize the browser window (inside onPrepare(), for instance):

browser.driver.manage().window().maximize();

And make a screenshot.


Working solution!!!

Another option could be to run tests in a Virtual Display. I you would follow this blogpost and use Xvfb, when you will run the Xvfb server, you may specify the resolution:

/usr/bin/Xvfb :99 -ac -screen 0 2048x6000x24 &

Also see related information on this topic here:


You may also use the docker-selenium solution which allows to configure the screen size.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...