Taking Remote Screenshots With Selenium And The Robot Framework

1 Comment

.Screenshot are incredibely helpful when doing user interface tests, to get fast feedback why a test has failed. Selenium provides several great opportunities to do exactly that. But, there are many problems related to that at the moment, from which some will discussed, even solved in the following post.

Update (2010-02-15): This post refers to SeleniumLibrary version 2.2. In the meantime, the proposals made to be included for remote screenshots have been included in version 2.3. (Release Notes). Thanks to the Robot Framework Team!

Our preferred way to integrate Selenium into our automated acceptance tests is the Robot Framework. This enables us to drive tests through all layers of the application, from the database up to the UI. Since it’s automated, this happens daily (or better nightly) or even on every commit. And this is where the first problem occurs. Our CI-Server (Hudson) runs on Linux … but without an XServer. Thus, the selenium server cannot run on the same machine, from with the acceptance tests are triggered. Another reason to run the selenium server on a different host is, that it’s quite difficult to run the Internet Explorer on Linux. A browser that still in wide use, especially in corporate networks, despite the numerous security warnings and rendering issues.

Many screenshot methods that are offered by the selenium server, take the file to save the screenshot to as an argument. This makes it difficult to access that screenshots (scp, fileshares, …). You’ll waste precious time just to access the file, while the analysis and debugging should be as easy as possible. But there’s also two methods in Selenium, that return the Screenshot as String base64 encoded PNG). This looks like a promising path 🙂

java.lang.String captureEntirePageScreenshotToString(java.lang.String kwargs)
java.lang.String captureScreenshotToString()

However, the existing SeleniumLibrary for the Robot Framework does not expose those methods as keyword. So we have to help ourselves, until it will be officially supported (Issue 89). So please download the latest Source-Distribution of the Robot SeleniumLibrary 2.2.2, and edit the file __init__.py. Please excuse my first, amateurish python coding trials:

import base64 
    def _absnorm(self, path):
        return os.path.normpath(os.path.abspath(path.replace('/', os.sep)))
    def _write_to_file(self, path, content, mode):
        path = self._absnorm(path)
        parent = os.path.dirname(path)
        if not os.path.exists(parent):
        f = open(path, mode+'b')
        return path
    def capture_remote_screenshot(self, path=None):
        """Captures a screenshot and returns it as a string
        Given path must be relative to Robot Framework output directory,
        otherwise the embedded image is not shown in the log file. If path is
        not given, file with name similar to 'selenium-image-x.png' is created
        directly under the output directory.
        # configure path
        if path and os.path.isabs(path):
            raise RuntimeError("Given path must be relative to Robot outpudir")
        if not path:
            path = self._namegen.next()
        outdir = NAMESPACES.current.variables['${outputdir}']
        fullpath = os.path.join(outdir, path)
        if not os.path.exists(os.path.split(fullpath)[0]):
        # retrieve remote screenshot
        self._info("Retrieving Screenshot")
        screenshot = self._selenium.capture_entire_page_screenshot_to_string("background=#CCFFDD")
        # save screenshot
        self._info("Saving screenshot to file '%s'" % fullpath)
        self._write_to_file(fullpath, screenshot, 'w')
<td colspan="3"><a href="http://blog.codecentric.de/en/2010/02/taking-remote-screenshots-with-selenium-and-the-robot-framework/">'
                   '<img src="http://blog.codecentric.de/en/2010/02/taking-remote-screenshots-with-selenium-and-the-robot-framework/" width="700px"></a></td>
' % (path, path))

The functions _absnorm and _write_to_file I borrowed from the OperatingSystem Robot Library (and also slightly modified them). To install the modified Selenium Library, just execute “setup.py install”.

How can the new keyword be used in a Robot Testcase? I find it most helpful to get a browser screenshot after a failing test, to debug the problem quickly. You can use the testcase teardown for that, which invokes the keyword when the test failed:


Test CaseActionArguments
TestSelenium PASSOpen Browserhttp://www.google.de${BROWSER}
[Teardown]Selenium Teardown
TestSelenium FAILOpen Browserhttp://www.google.de${BROWSER}
[Teardown]Selenium Teardown
SeleniumTeardownRun Keyword If Test FailedTake Screenshot
Close Browser
Take ScreenshotRun Keyword If‘${BROWSER}’ != ‘*iexplore’ and ‘${BROWSER}’ != *’ie’ and ‘${BROWSER}’ != ‘*internetexplorer’ and ‘${BROWSER}’ != ‘*iehta’Capture Remote Screenshot

Now, in every teardown it is checked if the test failed. If this is the case, the keyword “Take Screenshot” will be called. This checks for the correct browser, and only if its not the Internet Explorer, it calls the new Keyword “Capture Remote Screenshot”, which embeds the screenshot in the robot logfile:

In order to get screenshots working with internet explorer, a few hacks were necessary. At first I had to realize, that I have to call the correct selenium method, otherwise the screenshot is completely black (not only for IE, but for all Browsers). If you use the method selenium.capture_screenshot_to_string(), you screenshot will be black. It uses Java to take a screenshot from the entire screen (not only the browser content). This works with all browsers, unless the selenium server runs in the background. We are running the selenium server on a remote desktop, and in order to get non-black screenshots you have to say logged in. An alternative setup was using VNC, but this seemed also unpractical to us (via stackoverflow):

What we do is launch everything from under the context of a VNC session. On Windows, configure VNC to launch a session upon startup. Then make sure the user auto-logs in. Then place a .bat file in Program Files->Startup that launches Selenium RC. It’s kind of a pain, but it’s the most reliable way I’ve found for ensuring that Selenium RC starts in an environment that supports screenshots, launching IE, interacting with native events, etc.

The last alternative is, to not capture the entire screen, but only the browser content. This has the advantage, that you will see the complete website, even if it is larger than the screen. This method uses javascript to get hold of the rendered browser content. Problem: Works perfectly with Firefox, but not at all with Internet Explorer. Not yet. This can be fixed — so I thought. The following turned out to be a dead end. If somebody knows how to fix it, I’d be very interested to hear about it.

WIN: Screenshots with IE

This is the only working method, that I could figure out to take Screenshots with the internet explorer. Run the selenium server in “singleWindow” mode. In order to do that, execute:

java -jar selenium-server.jar -singleWindow

Additionally, selenium has to use the browser profile “*iexploreproxy”, that’s why the testcase above filters for all other IE-profiles.

Note: Eventually, you still have to install the latest SnapsIE library (see below). I have not tested, if the above works when I deinstall it again.

Achtung (2010-02-15): SnapsIE 0.2 indeed has to be installed to make screenshots work with IE.

FAIL: Screenshots with IE

This did not work at all. As I said, if you know why, let me know:

  1. Download and install SnapsIE 0.2
  2. Unpack selenium-server-1.0.1.jar and
    • Replace core\lib\snapsie.js with the version from SnapsIE 0.2
    • Edit the file core\scripts\selenium-api.js according to the proposal by Elf in the Selenium-Forum. I extended the changes a little, so here’s the complete new method::
Selenium.prototype.doCaptureEntirePageScreenshot = function(filename, kwargs) {
     * Saves the entire contents of the current window canvas to a PNG file.
     * Contrast this with the captureScreenshot command, which captures the
     * contents of the OS viewport (i.e. whatever is currently being displayed
     * on the monitor), and is implemented in the RC only. Currently this only
     * works in Firefox when running in chrome mode, and in IE non-HTA using
     * the EXPERIMENTAL "Snapsie" utility. The Firefox implementation is mostly
     * borrowed from the Screengrab! Firefox extension. Please see
     * http://www.screengrab.org and http://snapsie.sourceforge.net/ for
     * details.
     * @param filename  the path to the file to persist the screenshot as. No
     *                  filename extension will be appended by default.
     *                  Directories will not be created if they do not exist,  
     *                  and an exception will be thrown, possibly by native
     *                  code.
     * @param kwargs    a kwargs string that modifies the way the screenshot
     *                  is captured. Example: "background=#CCFFDD" .
     *                  Currently valid options:
     *                  <dl>
     *                   <dt>background</dt>
     *                     <dd>the background CSS for the HTML document. This
     *                     may be useful to set for capturing screenshots of
     *                     less-than-ideal layouts, for example where absolute
     *                     positioning causes the calculation of the canvas
     *                     dimension to fail and a black background is exposed
     *                     (possibly obscuring black text).</dd>
     *                  </dl>
    if (! browserVersion.isChrome &&
        ! (browserVersion.isIE && ! browserVersion.isHTA)) {
        throw new SeleniumError('captureEntirePageScreenshot is only '
            + 'implemented for Firefox ("firefox" or "chrome", NOT '
            + '"firefoxproxy") and IE non-HTA ("iexploreproxy", NOT "iexplore" '
            + 'or "iehta"). The current browser isn\'t one of them!');
    // do or do not ... there is no try
    if (browserVersion.isIE) {
        // targeting snapsIE >= 0.2
        function getFailureMessage(exceptionMessage) {
            var msg = 'Snapsie failed: ';
            if (exceptionMessage) {
                if (exceptionMessage ==
                    "Automation server can't create object") {
                    msg += 'Is it installed? Does it have permission to run '
                        + 'as an add-on? See http://snapsie.sourceforge.net/';
                else {
                    msg += exceptionMessage;
            else {
                msg += 'Undocumented error';
            return msg;
        if (typeof(runOptions) != 'undefined' &&
            runOptions.isMultiWindowMode() == false) {
            // framed mode
            try {
                Snapsie.saveSnapshot(filename, 'selenium_myiframe');
            catch (e) {
                throw new SeleniumError(getFailureMessage(e.message));
        else {
            // multi-window mode
            if (!this.snapsieSrc) {
                // XXX - cache snapsie, and capture the screenshot as a
                // callback. Definitely a hack, because we may be late taking
                // the first screenshot, but saves us from polluting other code
                // for now. I wish there were an easier way to get at the
                // contents of a referenced script!
                if (/.hta/.exec(snapsieUrl))
                    snapsieUrl = "http://localhost:4444/selenium-server/Core/lib/snapsie.js";
                var self = this;
                new Ajax.Request(snapsieUrl, {
                    method: 'get'
                    , onSuccess: function(transport) {
                        self.snapsieSrc = transport.responseText;
                        self.doCaptureEntirePageScreenshot(filename, kwargs);
            // it's going into a string, so escape the backslashes
            filename = filename.replace(/\\/g, '\\\\');
            // this is sort of hackish. We insert a script into the document,
            // and remove it before anyone notices.
            var doc = selenium.browserbot.getDocument();
            var script = doc.createElement('script'); 
            var scriptContent = this.snapsieSrc
				+ 'try {'
                + '    Snapsie.saveSnapshot("' + filename + '");'
                + '}'
                + 'catch (e) {'
                + '    document.getElementById("takeScreenshot").failure ='
                + '        e.message;'
                + '}';
            script.id = 'takeScreenshot';
            script.language = 'javascript';
            script.text = scriptContent;
            if (script.failure) {
                throw new SeleniumError(getFailureMessage(script.failure));


  • Hi

    I do use

    java -jar selenium-server-standalone-2.11.0.jar -port 4445 -timeout:30 -userExtension “D:\projects\tests\selenium server\user-extension.js” -htmlSuite “http://www.google.com” “d:\mytest.html”

    and added your above function in the user-extension.js i am calling above but I get

    Unknown command: ‘captureScreenshot’

    is like the file is not readed !

    any hint please ?


Your email address will not be published. Required fields are marked *