Sunday, December 28, 2008

Can Selenium detect if the page has JavaScript errors?

We usually have common requirement for Selenium: Check JS error in step.

Use case like:
1. beginJsErrorChecker
2. open | http://containJSError.jsp
3. open | http://noissueJS.jsp
4. endJsErrorChecker
It can report url2 has jserror in Selenium:
[error] JsErrorChecker:[JavaScript Error: "foo is not defined" {file: "http://containJSError.jsp" line: 9}]
It's hard to provide a generic solution for all browsers but my team implements above scenario for Selenium IDE only by Firefox chrome Error Console XPCOM APIs.

user-extensions.js like:
 
if (browserVersion.isChrome) {
  var theConsoleListener = {
     stepIdx:0, //beginJsErrorChecker command index
     observe:function( aMessage ){//async!
        dump("Log : " + aMessage.message);
        //Error, Warning, Message too noise. We only report "[JavaScript Error:..."
        if(aMessage.message != null && aMessage.message.indexOf("[JavaScript Error:") == 0){ 
          LOG.error("JsErrorChecker:" + aMessage.message);
                  
          //throw new SeleniumError("Catch JS Error: " + aMessage.message);
          //can't throw exception here: pollution to target JSError
          //so we manually markFailed
          
          //IDE only
          var olddebugIndex = testCase.debugContext.debugIndex;
          testCase.debugContext.debugIndex = this.stepIdx;//set actual index
                  
          testCase.debugContext.failed = true;
          testCase.debugContext.currentCommand().result = 'failed';
          editor.view.rowUpdated(testCase.debugContext.debugIndex);
                  
          testCase.debugContext.debugIndex = olddebugIndex;//recover
        } 
   },
   QueryInterface: function (iid) {
        if (!iid.equals(Components.interfaces.nsIConsoleListener) &&
              !iid.equals(Components.interfaces.nsISupports)) {
            throw Components.results.NS_ERROR_NO_INTERFACE;
            }
        return this;
   }
  }; 
}
 
Selenium.prototype.doBeginJsErrorChecker = function(){
  try {
    if (browserVersion.isChrome) {// firefox 
          theConsoleListener.stepIdx=testCase.debugContext.debugIndex;//set current step idx for async call
          var aConsoleService = Components.classes["@mozilla.org/consoleservice;1"]
                          .getService(Components.interfaces.nsIConsoleService);
          aConsoleService.registerListener(theConsoleListener);
          aConsoleService.reset();
    }else{
      throw new SeleniumError("TODO: Non-FF browser...");
    }
    } catch (e) {
    throw new SeleniumError("Threw an exception: " + e.message);
    }
};

Selenium.prototype.doEndJsErrorChecker = function(){
  try {
    if (browserVersion.isChrome) {// firefox  
          var aConsoleService = Components.classes["@mozilla.org/consoleservice;1"]
                          .getService(Components.interfaces.nsIConsoleService);
          aConsoleService.unregisterListener(theConsoleListener);
          aConsoleService.reset();
    }else{
      throw new SeleniumError("TODO: Non-FF browser...");
    }
    } catch (e) {
    throw new SeleniumError("Threw an exception: " + e.message);
    }
};
I just add a Selenim listener to Firefox Error Console to make jserror checker work for Selenium-IDE.
Because it is async mode to check JSError, we treat beginJsErrorChecker failed if any step contains JSError in begin...end block.
We also filter all Warning and Message in Error Console, treat Error only as failed here.

I pasted solution on http://clearspace.openqa.org/message/52135
http://jira.openqa.org/browse/SEL-613

3 comments:

  1. Hey, that's really awesome! Did you find a way how to port it to Selenium 2 (web driver)?

    ReplyDelete
  2. Great Job!
    I really appreciate your fantastic post. Thanks for sharing such a nice tip. Good information and will be useful for us.
    More info:- Mozilla Firefox Support

    ReplyDelete