6

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.

pinoyyid
  • 21,499
  • 14
  • 64
  • 115
  • I don't think you can take a full screenshot by resizing the chrome browser off the screen size limits. Screenshot function i believe is a OS bounded restriction, where you cannot manually take the complete screenshot of the page yourself. Only option is to scroll the page manually everytime and take multiple screenshots and then use an external software to join them(which is a tedious task). Thanks – giri-sh Jan 05 '16 at 10:49
  • I doubt it's the screenshot that is OS bounded. It's the window resize. As the test runs I can see that the browser window has grown, but only as far as the screen top/bottom. I can manually resize a normal chrome window beyond my screen size, but something in selenium/chromedriver seems to not like doing the same. – pinoyyid Jan 05 '16 at 11:18
  • I meant that whenever you take a screenshot manually, the max area you could cover is what you can see in your computer screen size. So when its not possible to take a screenshot manually by enlarging the browser window(off screen size limits), how will selenium be able to do it as it internally calls the same screenshot function that runs when you do it manually. – giri-sh Jan 05 '16 at 11:21
  • My problem is that when I resize the chrome browser to height 5000, it only resizes to the screen height. How do I get the window to a height of 5000? – pinoyyid Jan 05 '16 at 15:16
  • maybe you can run a virtual monitor with your desired resolution? – Dude Jan 07 '16 at 12:24
  • @Dude sounds interesting. Can you elaborate? – pinoyyid Jan 07 '16 at 12:26
  • Have you tried this one? Capable to take any size screenshot. https://www.npmjs.com/package/snappit-mocha-protractor – Linh Pham Jan 07 '16 at 13:07
  • @pinoyyid thanks for the feedback. I was hoping the scroll/take screenshot/montage option would work for you. It worked for me (not ideally but I've got a decent concatenated image from top to bottom). – alecxe Jan 11 '16 at 01:43
  • @alecxe that was my least favourite option as it added more moving parts to an already complex script. eg. I upload the images to github so I can use their image diff tools. Thx for the comprehensive answer. – pinoyyid Jan 11 '16 at 03:17

1 Answers1

8

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.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • "Scroll, take screenshot, append" - it's not working when there's an element with position set to fix. It breaks the screenshot. How to cope with fixed position element? – cezarypiatek May 08 '16 at 19:49
  • @Uriel do you have a specific URL you can share? I'd also create a separate question so that more people can help. Thanks. – alecxe May 08 '16 at 19:52
  • for example this (https://msdn.microsoft.com/en-us/library/windows/hardware/ff551063(v=vs.85).aspx) page has menu on the left side which has position set to fixed. @alecxe please try to take a screenshot using scroll&append approach and check if you get what you expected – cezarypiatek May 08 '16 at 19:58