The topic of catching java script errors with webdriver has been discussed time and again. This was also a hot topic during the days of Selenium RC. There have been quite a few approaches to catch java script errors with WebDriver, like -
- Adding extra script to web page and using JavascriptExecutor to retrieve them. I won’t recommend this approach as it requires application code to be changed to be able to test it
- And of late, there has been a beta feature available in WebDriver APIs which lets you capture browser console log. Using this you can capture browser level logs. I like this approach as it does not require application code to be modified or adding extra extension to a browser. I experimented this approach with FF 47.0.1, Chrome 50 and Selenium 2.53.1 and worked like a charm.
Let’s consider blog - https://rationaleemotions.wordpress.com/ which has a 404 error and it is visible on console. (By the very useful blog, you may like to follow it if not already :)) -
Browser console is also the place where javascript error would logged. Let’s catch and print this error on Chrome. Here is a sample code to do this -
package com.seleniumtests.tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.testng.annotations.Test;
public class JavaScriptErrorTest {
WebDriver webDriver;
LogEntries logEntries;
public static void logConsoleEntries (LogEntries logEntries) {
for (LogEntry logEntry : logEntries) {
System.out.println(String.valueOf(" Time Stamp: " + logEntry.getTimestamp()));
System.out.println(String.valueOf(" Log Level: " + logEntry.getLevel()));
System.out.println(String.valueOf(" Log Message: " + logEntry.getMessage()));
}
}
@Test
public void catchJavaScriptError() throws Exception {
String url = "https://rationaleemotions.wordpress.com/";
System.setProperty("webdriver.chrome.driver",
"chromedriver");
webDriver = new ChromeDriver();
webDriver.get(url);
logEntries = webDriver.manage().logs().get(LogType.BROWSER);
logConsoleEntries(logEntries);
webDriver.quit();
}
}
And following message is printed -
Time Stamp: 1468249126412 Log Level: SEVERE Log Message: https://s0.wp.com/wp-content/themes/pub/themorningafter/inc/style-wpcom.css?ver=4.5.3-20160628 0:0 Failed to load resource: the server responded with a status of 404 ()
You can build your assert statement around log.
Let’s see an example of javascript error now and this time with Firefox browser. We will consider website - http://www.softwaretestingtricks.com/ for testing and it seems to have quite a few java scripts errors. Lets update our test to use Firefox driver -
@Test
public void catchJavaScriptError() throws Exception {
String url = "http://www.softwaretestingtricks.com/";
webDriver = new FirefoxDriver();
webDriver.get(url);
logEntries = webDriver.manage().logs().get(LogType.BROWSER);
logConsoleEntries(logEntries);
webDriver.quit();
}
This would print lots of logs and one log would be a js error -
Time Stamp: 1468310250086 Log Level: SEVERE Log Message: TypeError: $(...).flexslider is not a function
If you want to restrict the amount of logs then you can restrict the logs to a given level when instantiating your driver -
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
LoggingPreferences loggingPreferences = new LoggingPreferences();
loggingPreferences.enable(LogType.BROWSER, Level.SEVERE);
desiredCapabilities.setCapability(CapabilityType.LOGGING_PREFS, loggingPreferences);
webDriver = new FirefoxDriver(desiredCapabilities);
And now you would only have sever errors printed. I am reluctant to use this method of restricting amount of logs as I see different results in chrome and firefox. For example logging SEVERE errors reported following on chrome -
Time Stamp: 1468311387330 Log Level: SEVERE Log Message: http://reportage.wp-theme.pro/wp-content/themes/reportage/images/social/facebook.png 0:0 Failed to load resource: net::ERR_NAME_NOT_RESOLVED Time Stamp: 1468311387331 Log Level: SEVERE Log Message: http://reportage.wp-theme.pro/wp-content/themes/reportage/images/social/twitter.png 0:0 Failed to load resource: net::ERR_NAME_NOT_RESOLVED Time Stamp: 1468311387331 Log Level: SEVERE Log Message: http://reportage.wp-theme.pro/wp-content/themes/reportage/images/social/vimeo.png 0:0 Failed to load resource: net::ERR_NAME_NOT_RESOLVED Time Stamp: 1468311387331 Log Level: SEVERE Log Message: http://reportage.wp-theme.pro/wp-content/themes/reportage/images/social/linkedin.png 0:0 Failed to load resource: net::ERR_NAME_NOT_RESOLVED Time Stamp: 1468311387331 Log Level: SEVERE Log Message: http://reportage.wp-theme.pro/wp-content/themes/reportage/images/social/googleplus.png 0:0 Failed to load resource: net::ERR_NAME_NOT_RESOLVED Time Stamp: 1468311387584 Log Level: SEVERE Log Message: javascript 1:187 Uncaught TypeError: Cannot read property 'title' of undefined Time Stamp: 1468311387859 Log Level: SEVERE Log Message: javascript 1:4571 Uncaught TypeError: Cannot read property '0' of undefined
And following on firefox -
Time Stamp: 1468311872314 Log Level: SEVERE Log Message: TypeError: entry is undefined Time Stamp: 1468311872464 Log Level: SEVERE Log Message: TypeError: json.feed.entry is undefined Time Stamp: 1468311873221 Log Level: SEVERE Log Message: TypeError: json.feed.entry is undefined Time Stamp: 1468311873969 Log Level: SEVERE Log Message: SyntaxError: missing ) after argument list Time Stamp: 1468311876268 Log Level: SEVERE Log Message: TypeError: $(...).flexslider is not a function
Hence I prefer to not restrict the amount the log, print all the log and parse log for possible errors.
Form the above example, it is clear that we can capture logs for both Firefox and Chrome browser. But beware that this function is yet beta (at the time of writing this post) and you may encounter unexpected errors.
But collecting browser logs for javascript errors on each event would result in lots of extra code and corresponding checks. What if we could automate javascript error check which takes place on each test method? I can think of listener doing this for us. What do you think?