Let's say you have the code:
WebDriver driver; @Before public void setUp() { driver = new FirefoxDriver(); }
and you want to change it so the test cases will generate a screen capture file when an exception is thrown. Here is the first change:
WebDriver driver; @Before public void setUp() { WebDriverEventListener eventListener = new MyEventListener(); driver = new EventFiringWebDriver(new FirefoxDriver()).register(eventListener); }
The second change is to create the MyEventListener class. The MyEventListener class will be:
public class MyEventListener implements WebDriverEventListener { // All the methods of the WebDriverEventListener need to // be implemented here. You can leave most of them blank. // For example... public void afterChangeValueOf(WebElement arg0, WebDriver arg1) { // does nothing } // ... public void onException(Throwable arg0, WebDriver arg1) { String filename = generateRandomFilename(arg0); createScreenCaptureJPEG(filename); } }
The MyEventListener class will have 15 methods, including the two examples I have given here. The main method that you must implement if you want screen captures whenever an exception is thrown would be the onException method.
The biggest trick for this method is generating a unique filename for each exception. First thought is that the filename could be in the format "YYYY-MM-DD-HH-MM-SS.jpg". Unless you get two exception in one minute this will work okay. Unfortunately, it will be hard to figure out what the exception was unless you kept some sort of log in the code execution. You'll also have to waste time figuring out which exception goes with which date/time.
Personally, I'd use the format "YYYY-MM-DD-HH-MM-SS-message-from-the-throwable-argument.jpg". Selenium tends to throw multiple line exception messages. So you could take the first line of the message, change characters which are illegal for your file system and change them to underscores. You could also have something to set the location of the screen capture files and prepend that to the filename.
Here is the code I came up with in 2 minutes:
private String generateRandomFilename(Throwable arg0) { Calendar c = Calendar.getInstance(); String filename = arg0.getMessage(); int i = filename.indexOf('\n'); filename = filename.substring(0, i).replaceAll("\\s", "_").replaceAll(":", "") + ".jpg"; filename = "" + c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH) + "-" + c.get(Calendar.DAY_OF_MONTH) + "-" + c.get(Calendar.HOUR_OF_DAY) + "-" + c.get(Calendar.MINUTE) + "-" + c.get(Calendar.SECOND) + "-" + filename; return filename; }
The final part is the code to actually generate the file. This is standard Robot stuff. Here is the code I whipped together a few projects back:
private void createScreenCaptureJPEG(String filename) { try { BufferedImage img = getScreenAsBufferedImage(); File output = new File(filename); ImageIO.write(img, "jpg", output); } catch (IOException e) { e.printStackTrace(); } } private BufferedImage getScreenAsBufferedImage() { BufferedImage img = null; try { Robot r; r = new Robot(); Toolkit t = Toolkit.getDefaultToolkit(); Rectangle rect = new Rectangle(t.getScreenSize()); img = r.createScreenCapture(rect); } catch (AWTException e) { e.printStackTrace(); } return img; }
And that is it. Whenever an exception is thrown a file will be generate.
Nice Article! thanks.
ReplyDeletevery nice article. It was very helpful to me.
ReplyDeleteSimps
Nice article. But I have one comment and one question.
ReplyDeleteFirst the comment:
- You can use AbstractWebDriverEventListener instead of WebDriverEventListener so you must must not override all the methods you do not use.
The Question:
I see you are using HtmlUnitDriver. But I never get any visible output from this driver. So how do you make HtmlUnitDriver rendering html in a GUI?
Thanks for the comments Ralph. I am not sure why I used HtmlUnitDriver in my example. It does not display a GUI and therefore shouldn't be used for this example. I have changed it to FirefoxDriver.
ReplyDeleteGreat article! Thank you for sharing!
ReplyDeleteI have tried this but this method is not working for me :(
ReplyDeletePlease guide/help.
"onException" methid is not at all being called.
ReplyDeletewhat should i do for this.
Please help me, please.
onException function will be called automatically when exception occur.
ReplyDeleteMake some exception using some selenium functions like VerifyXXXXX,AssertXXXXX, etc,.
If you wonder how to use those functions, refer the description of each functions in selenium package.
Great post, thanks a lot
ReplyDeleteCan you please help me how i can implement this with the Remote web driver.
ReplyDeleteTo webuser,
ReplyDeleteThis article uses Robot to capture the local screen image. If you want to capture the image of a remote computer it is not possible with Selenium 2. If you look at the EventFiringWebDriver class you will see it implements the interface TakesScreenshot. This seems to implement that EventFiringWebDriver has the getScreenshotAs() method. HOWEVER, if you look at the code you will see the EventFiringWebDriver.getScreenshotAs() methods checks to see if the underlying WebDriver supports it. If it does not it throws an exception. FirefoxDriver supports TakesScreenshot but RemoteWebDriver does not.
Bottom line, you can only do this with FirefoxDriver. Maybe you should file a feature request with the Selenium team to have them add TakesScreenshot to RemoteWebDriver, if RemoteWebDriver is using Firefox.
Nice Article! thanks.
ReplyDeleteI have one use case in same please clarify for that.
I want to take screen sort for each and every event (means click on button or tab or link). Than i want to capture the page.
I want to capture my application from login to logout.
Please give me some solution.
Thanks,
Ajay
Ajay, have a look at http://darrellgrainger.blogspot.ca/2012/07/creating-screen-capture-on-every-action.html
ReplyDeletewhere are the screenshots stored in the machine?
ReplyDeleteWhere are the screenshots stored on the machine? or they are within the project workspace?
ReplyDeleteThe createScreenCaptureJPEG() takes as input the full path to the file. If I use:
ReplyDeletecreateScreenCaptureJPEG("filename.jpg");
it will save the file in the current directory, whatever that may be. If I use:
createScreenCaptureJPEG("C:\\foo\\bar\\filename.jpg");
then the file will be saved in C:\foo\bar. For convenience I have provided a method called generateRandomFilename(). You can modify this method to include a specific directory where screenshots are stored. In other words, the point of the article was not a full solution. You still need to create code to determine where the screenshot files will be saved.
Hello Darrell,
ReplyDeleteIn one of your reply you said that screen capture is implemented only with FirefoxDriver and for all other drivers it will throw an exception.
Is it still the same case, or is it being implemented with the other drivers.
I am getting NUlLL exception when I call 'GetScreenshot' on instance of 'EventFiringWebDriver'.
Can I get any document about the same on Selenium site?
Thanks,
Naresh
I determine a lot from the source code. The documentation can always be out of date but the source code must be what the tool is currently doing. You can go to http://code.google.com/p/selenium/source/checkout to browser the source code. This page also has instructions on checking out the source code.
ReplyDeleteIf I look at the Java bindings:
trunk/java/client/src/org/openqa/selenium/chrome/ChromeDriver.java
trunk/java/client/src/org/openqa/selenium/firefox/FirefoxDriver.java
trunk/java/client/src/org/openqa/selenium/ie/InternetExplorerDriver.java
trunk/java/client/src/org/openqa/selenium/iphone/IPhoneDriver.java
trunk/java/client/src/org/openqa/selenium/safari/SafariDriver.java
all now have "implements TakesScreenshot". So all the drivers now support taking a screen shot.
Hello Darrel, is it implemented by RemoteWebDriver? I was looking into latest .Net bindings and I found it is not yet implemented by SafariDriver and RemoteWebDriver. Is it same with RemoteWebDriver in Java also?
ReplyDeleteThanks,
Naresg
The bindings for RemoteWebDriver in Java does not have "implements TakesScreenshot". So it does not support taking a screen capture.
ReplyDeleteDarrell, just wanted to say thank you for your blog! It's awesome!
ReplyDeleteVery useful and interesting.
You're doing great job!
Kyryll, Kiev, Ukraine.
This really work...Just a small changes in the code to extract the substring of complete message would help to reduce the filename :-)
ReplyDeleteThanks Darrell!
This comment has been removed by a blog administrator.
ReplyDeleteI noticed you state this is for exceptions. Will this also generate a screenshot for failed assertions?
ReplyDeleteHey Cameron. It will not work if you throw an assertion. Frameworks like junit or TestNG will throw AssertionError which are different from Exception. This will only work for whenever a runtime exception is thrown.
ReplyDeleteIf you are explicitly throwing an assert you could write your work assert which checks the assert condition and if false does a screen capture then throws an assert.
This code is more for when runtime exceptions occur. These are things you cannot anticipate and therefore need a general catchall structure.
Thanks Darrell. Also, there are screenshots being taken when there are not any exceptions being thrown. I am getting an "unable to find element" error, but there is not a NoSuchElementException, nor is the script failing. Any thoughts? I posted in this question in another forum hoping you might respond.
ReplyDeletehttp://www.seleniumtests.com/p/selenium-2-forum.html
Cameron, have a look at http://darrellgrainger.blogspot.com/2012/07/creating-screen-capture-on-every-action.html. It talks about the other methods you can implement from the WebDriverEventListener. Experiment and see if one of the other methods might be able to help you. Generally, I find driver.findElement returns a NoSuchElementException and this code works. Must be something else to your code which is capturing the exception or doing something else.
ReplyDeleteRather than have a conversation here you should post a general message on https://groups.google.com/forum/#!forum/webdriver. I monitor it and will see anything you post there.
i m getting java.io.FileNotFoundException: D:\newJunoWorkspace\UCTest\ScreenShots\22_Nov_2013__12_59_51PM_192.168.110.101.png (The system cannot find the path specified) error once the Assertion fails and Image is getting Captured only when browser dies.
ReplyDeletewhat is the error i m getting ?
FileNotFoundException usually has nothing to do with Selenium. If you try saving the file to a directory which does not exist, if code is running as System or LocalSystem and these users do not have permission to write to the directory it will fail. Basically, look into reasons a FileNotFoundException occurs (not Selenium specific) and investigate if any of these reasons are why you code is failing. If you still have trouble, post to https://groups.google.com/forum/#!forum/webdriver for more help.
ReplyDelete