Capturing screenshots from remote Selenium RC
Posted: October 16th, 2009 | Author: Dave | Filed under: Examples | Tags: debug, failure, remote, screenshot | 14 Comments »Despite the name, the Selenium RC (Remote Control) server is often run on the same machine as the testing framework, which makes saving screenshots to disk quite easy. If however you are running Selenium RC on a separate machine, or are using Selenium Grid it can become more difficult as the screenshots are also saved on the remote machines.
To solve this you can use the captureScreenshotToString and captureEntirePageScreenshotToString commands, which return a Base64 encoded String of the screenshot, which you can then decode and save to disk on your testrunner machine.
The following demonstrates the latter command (entire screenshot) in Java. I have added this to a TestNG afterInvocation listener for failed tests so that I have a screenshot of the page that resulted in the failure, which can be very valuable for diagnosing issues.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public void afterInvocation(IInvokedMethod method, ITestResult result) { if (!result.isSuccess()) { String imageName = "screenshot.png"; String imagePath = outputDirectory + separator + imageName; try { String base64Screenshot = session().captureEntirePageScreenshotToString(""); byte[] decodedScreenshot = Base64.decodeBase64(base64Screenshot.getBytes()); FileOutputStream fos = new FileOutputStream(new File(imagePath)); fos.write(decodedScreenshot); fos.close(); Reporter.log("<a href=\"file:///" + imagePath + "\">Screenshot</a>"); } catch (Exception e) { e.printStackTrace(); } } } |
Notes:
- This example uses
org.apache.commons.codec.binary.Base64 - In this example,
outputDirectoryis set in aonStartlistener from theITestContextparameter’sgetOutputDirectorymethod - In reality you’d want to construct
imageNamefrom the test method name so that it is unique for each test - The
captureEntireScreenshot*commands have limited browser support. Currently I only capture these screenshots if the browser is Firefox
Where are you getting reference to the Selenium object? I’m assuming you’ve encapsulated it in the session() call but how does that work? Thanks!
Nevermind… you can do something like this:
SeleniumTest test = (SeleniumTest) result.getTestClass().getInstances(false)[0];
My implementation uses Selenium Grid, so it’s necessary to have a thread safe implementation of the Selenium object. If you’re not using Grid, you could use a static Selenium object. Once I’ve made some refinements to the thread safe implementation I intend to write a post explaining it.
Hi,
can you show me please an example when you use this method in your code to get a screenshot, in the test or after Startsession or when?
Thank you.
The example method actually overrides an afterInvocation method from a TestListenerAdapter that implements TestNG’s IInvokedMethodListener interface – as documented here: http://testng.org/javadoc/org/testng/IInvokedMethodListener.html
For debugging purposes I have since split this out to a separate method so that I can capture screenshots ad-hoc, and may at some point implement a solution that captures screenshots after every verification failure.
You could also have this method run in a method annotated with AfterMethod.
Hi ,
Is there any way to record the test execution as SWF file instead of capturing screenshot?
Hi,
I tried to use the above example, but I have a problem writing to the html output (output.html):
String html= “Screenshot“;
Reporter.log(html);
My output.html contains character entities like <
<a href="file:///C:\temp\2010-12-02_13-30-53.png">Screenshot</a>
Because of that I see the html code in my browser literally:
Screenshot
How can this be solved?
Hi Ben, thanks for commenting!
It looks like TestNG is escaping the less-than and greater-than characters. I’ve not seen this before but maybe it’s been introduced in a recent version… My best suggestion would be to ask on the testng-users Google Group at http://groups.google.com/group/testng-users/
Cheers,
Dave
HI, I am very new for Selenium and thanks the blog which help’s for new learners like me. So i have small doubt i used your method in my class to capture screen shot, but i faced an issue @ session(). can i know from where session method is calling. can u please share the method for me.
Thanks,
Pradeep
Hi Pradeep, thanks for commenting. See the earlier comments regarding session(). It simply returns a Selenium object. I was pasting from my framework, which used multi-threading to run several instances of Selenium in parallel.
Hi;
by any chance, do you know how to overcome the ‘sleep mode’ issue when the RC has no display (virtual machine)?
Whenever the RC is not active (someone remotely connected to it) or is logged, the capture method returns a black image which has the size of the display settings (800*600 for example).
I’m using GRID and have several RCs on different OS; it seems possible to use Xvfb for unix machines but had not the chance do try this out yet.
Thanks
Hi Dave,
Can you post some sample code for implementing Selenium as thread safe (my test cases runs in grid ) and how to use selenium object in listener to take screen shot.
Hi Pascal,
I’m not familiar with the problem. Have you tried using Selenium 2.0? The grid support for 2.0 is progressing well so hopefully this will soon be a viable option for you if it solves your screen capture issues.
Thanks,
Dave
The code at https://github.com/nirvdrum/selenium-grid/blob/master/tools/src/main/com/thoughtworks/selenium/grid/tools/ThreadSafeSeleniumSessionStorage.java shows using a thread safe Selenium. This post contains details of using a TestNG listener to capture a screenshot.