Saturday, December 20, 2008

Automate HttpFox(HttpWatch) test case for http traffic manipulation in Selenium

Selenium can verify and store values by DOM on current page easily. However, it's hard for Selenium to do manipulation on http traffic like POST Data, http headers, Query String and Content sniffer.

I know many QA did http traffic testing manually by 2 famous software:
1) HTTPWatch: commercial. support both IE and Foxfox.
2) HTTPFox: free, opensource. a Firefox extension.

One day, a guy came to my cube and raised a question: Can I stop my tons of manual functional testing with HttpFox, but use Selenium to automate them? Is it possible that we create a bundle of Selenium APIs to manuplate Http Traffic Sniffer operations?

Yes, we should add this important feature to Selenium. I finished a beta version to support HttpFox APIs in Selenium:
1) merge httpfox.xpi into Selenium-IDE.xpi
2) leverage XPCOM in httpfoxservice.js HTTPFox provided
3) create Selenium APIs and print http traffic info to Selenium LOG:
startHttpFox4Sel
stopHttpFox4Sel
clearHttpFox4Sel
verifyTextInHttpFoxURLs(Not)Present | textpattern
verifyTextInHttpFoxContent(Not)Present | urlpattern | textpattern
storeContentInHttpFoxByURL | urlpattern | varname
verifyParamInHttpFoxQueryString(Not)Present | urlpattern | param1=value1,param2=value2 list
storeParamInHttpFoxQueryString | param@urlpattern | varname
verifyParamInHttpFoxPostData(Not)Present | urlpattern | param1=value1,param2=value2 list
storeParamInHttpFoxPostData | param@urlpattern | varname
...

Source draft:
Selenium.prototype.doStartHttpFox4Sel = function() {
    try {
     if(browserVersion.isChrome){
      HttpFox.cmd_hf_clear();
         HttpFox.cmd_hf_startWatching(); 
        }
    } catch (e) {
     throw new SeleniumError("Threw an exception: " + e.message);
    }
}; 

Selenium.prototype.doStopHttpFox4Sel = function() {
    try {
        if(browserVersion.isChrome){ 
         HttpFox.cmd_hf_stopWatching();
         HttpFox.cmd_hf_clear();
        }
    } catch (e) {
     throw new SeleniumError("Threw an exception: " + e.message);
    }
}; 

Selenium.prototype.doClearHttpFox4Sel = function() {
    try {
        if(browserVersion.isChrome){  
         HttpFox.cmd_hf_clear();
        }
    } catch (e) {
     throw new SeleniumError("Threw an exception: " + e.message);
    }
}; 
       
Selenium.prototype.isTextInHttpFoxURLsPresent = function(pattern) {
   try {
     if(browserVersion.isChrome){  
   for (var i = 0; i < HttpFox.HttpFoxService.Requests.length; i++){ 
        var request = HttpFox.HttpFoxService.Requests[i];
        //1.Time:
        var time = formatTimeDifference(request.StartTimestamp, request.EndTimestamp) ;
        //2.Sent:
        var sent = "";
        if (request.IsSending){
          sent = humanizeSize(request.getBytesSent(), 6) + "/" + humanizeSize(request.getBytesSentTotal(), 6);
        }
        else {
         sent = humanizeSize(request.getBytesSentTotal(), 6); 
        } 
        //3.Received:     
         var received = "";
         if (request.IsSending){
          received = "*";
       }
       if (!request.IsFinished){
          // show loading body progress
         received = humanizeSize(request.getBytesLoaded(), 6) + "/" + humanizeSize(request.getBytesLoadedTotal(), 6);
       }else{
         received = humanizeSize(request.getBytesLoaded(), 6); 
       }
       if (request.IsFromCache || request.ResponseStatus == 304){
         received = "(" + received + ")";
       } 
        //4.Method:
       var method = request.RequestMethod; 
        //5.Result: 
        var result = "";
       if (request.IsAborted){
         result =  "(Aborted)";
       }else if (request.isError()){
          result = "(Error)";
       }else if (request.IsFromCache && (request.ResponseStatus != 304)) {
          result =  "(Cache)";
       }else if (!request.HasReceivedResponseHeaders && !request.IsFinal){
          result = "*";
       }else{
           result =  request.ResponseStatus;
       } 
        //6.Type:
              var type = "";
              if (request.hasErrorCode()){
               if (request.ContentType){
               type =  request.ContentType + " (" + request.Status.toString(16) + ")";//we omit nsResultErrors translate
              }else{
               type =  request.Status.toString(16);
              }
             }else if (!request.HasReceivedResponseHeaders && !request.IsFromCache && !request.IsFinal){
               type =  "*";
             }else if (request.isRedirect()){
              if (request.ResponseHeaders && request.ResponseHeaders["Location"]){
               type =  "Redirect to: " + request.ResponseHeaders["Location"]; 
              }else{
               type =  "Redirect (cached)";
              }
             }else{
              type = request.ContentType;     
             }  
       //7.URL
       var urlstring = request.Url ;
       //TODO: LOG.info(http sniffer info);
       //TODO: verify as you like by PatternMatcher
   } //end for
    }//end chrome
    } catch (e) {
     throw new SeleniumError("Threw an exception: " + e.message);
    }
}; 

Now, QA can automate HttpFox steps in Selenium. They don't need to do http traffic testing manually all days.

6 comments:

  1. which version of selenium supports httpfox and can u pls briefly explain the process of adding XPCOM objects

    ReplyDelete
  2. Can you get a good how to .. about getting Xpi flies merging and all.

    ReplyDelete
  3. captureNetworkTraffic() API in DefaultSelenium captures http request/response headers and you can access them in html/xml/plain format.

    Here is sample code:

    Selenium s = new DefaultSelenium(...);
    s.start("captureNetworkTraffic=true");
    s.open("http://www.google.com");
    String xml = s.captureNetworkTraffic("xml"); // html, plain
    s.stop();

    ReplyDelete
    Replies
    1. Hi Ivan,
      Could you please send me the steps as i am asked to test the cache contaol max header using selenium and also i would need to configure it so if caching time changes, my test should be easily able to manipulate.

      Delete