Taking full size screenshots using Selenium 3 with the Firefox geckodriver

Since Selenium3 switched from FirefoxDriver to geckodriver, which is now mandatory as of Firefox 47, the screenshot command now only takes a picture of the viewport.  As far as I’ve been able to tell, the only solution anyone has come up with is using something like aShot to scroll down the page and stitch a string of images together.  As it turns out though, the geckodriver system is intentionally crippled to comply with the JsonWire protocol which specifies that it should take a picture of the viewport.  Firefox itself still has the same capabilities that it did before.  To work around this, you can build a custom geckodriver.

First you need a dev environment that will build geckodriver, so use a Dockerfile containing:

FROM selenium/standalone-firefox:3.8.1
USER root
RUN apt-get update && apt-get install -y build-essential file curl
RUN apt-get install -y less python
ENV SHELL=/bin/bash
RUN apt-get install -y less python
RUN apt-get install -y autoconf2.13 build-essential ccache python-dev python-pip python-setuptools unzip uuid zip
RUN apt-get install -y libasound2-dev libcurl4-openssl-dev libdbus-1-dev libdbus-glib-1-dev libgconf2-dev libgtk-3-dev libgtk2.0-dev libiw-dev libnotify-dev libpulse-dev libx11-xcb-dev libxt-dev mesa-com
RUN pip install mercurial
ENV SSL_VERSION=1.0.2n


RUN curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \
 tar -xzf openssl-$SSL_VERSION.tar.gz && \
 cd openssl-$SSL_VERSION && ./config && make depend && make install && \
 cd .. && rm -rf openssl-$SSL_VERSION*

ENV OPENSSL_LIB_DIR=/usr/local/ssl/lib \
 OPENSSL_INCLUDE_DIR=/usr/local/ssl/include \
 OPENSSL_STATIC=1

# install toolchain
RUN curl https://sh.rustup.rs -sSf | \
 sh -s -- --default-toolchain stable -y
ENV PATH=/root/.cargo/bin:$PATH
USER seluser

Then you want to run that docker image with a local volume mapped, because the firefox source is huge.

docker run -u root -it -v /home/somewhere/firefox-src:/src geckodriver bash

then follow the instructions at https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_build/Linux_and_MacOS_build_preparation

Choose regular desktop firefox, when bootstrap.py asks you, not artifact.

wget https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py
python bootstrap.py
hg clone https://hg.mozilla.org/mozilla-central

Then hand apply this simple patch, which may need some changes depending on what they do with the code:

diff -r 4db166f0442d testing/geckodriver/src/marionette.rs
--- a/testing/geckodriver/src/marionette.rs Thu Jan 11 00:01:16 2018 +0200
+++ b/testing/geckodriver/src/marionette.rs Thu Jan 11 03:04:49 2018 +0000
@@ -1147,14 +1147,14 @@
 let mut data = BTreeMap::new();
 data.insert("id".to_string(), Json::Null);
 data.insert("highlights".to_string(), Json::Array(vec![]));
- data.insert("full".to_string(), Json::Boolean(false));
+ data.insert("full".to_string(), Json::Boolean(true));
 (Some("takeScreenshot"), Some(Ok(data)))
 },
 TakeElementScreenshot(ref e) => {
 let mut data = BTreeMap::new();
 data.insert("id".to_string(), e.id.to_json());
 data.insert("highlights".to_string(), Json::Array(vec![]));
- data.insert("full".to_string(), Json::Boolean(false));
+ data.insert("full".to_string(), Json::Boolean(true));
 (Some("takeScreenshot"), Some(Ok(data)))
 },
 Extension(ref extension) => {

put this in a file called ‘mozconfig’ to tell mach to build geckodriver, as it’s not done by default.

ac_add_options –enable-geckodriver

cd mozilla-central
echo "ac_add_options --enable-geckodriver" > mozconfig
./mach build

This results in the binary being located in ./obj-x86_64-pc-linux-gnu/dist/bin/geckodriver.  If you want to use the official selenium docker image, you’ll need to copy that over top of  /usr/bin/geckodriver — otherwise, just replace it whereever it is on your system.