OWASP O2 Platform Blog

Injecting FirebugLite and jQuery into a IE Automation page (JPetStore Example)

When doing IE Automation, sometimes the best way to find out what is happening at the page we’re working on is to open FireBug on it. A cool (and very powerfull) alternative is to use FirebugLite which can be embeded on any page and works on most browsers.

As you can see here http://getfirebug.com/firebuglite#Stable one way to fireup FirebugLite is to execute that bit of Javascript they show under the ‘Add the following link to your bookmarks:’ section.

When using O2’s IE Automation this can be achieved like this:

var firebugLiteScript = "(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&&F.documentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new Image;E[r]('src',I+L);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');";
ie.eval(firebugLiteScript );

And since that works, let’s add it as an Extension method to the WatiN_ExtensionMethods.cs file that is used on the IE Automation script:

public static class WatiN_IE_ExtensionMethods_FireBugLite
{
public static WatiN_IE inject_FirebugLite(this WatiN_IE ie)
{
var firebugLiteScript = "(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&&F.documentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new Image;E[r]('src',I+L);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');";
ie.eval(firebugLiteScript);
return ie;
}
}

While we are here lets also add jQuery directly (without the need to use the IE_JQuery.cs api)

ie.eval("<a href="http://code.jquery.com/jquery-1.6.2.min.js%22.uri().getHtml">http://code.jquery.com/jquery-1.6.2.min.js".uri().getHtml</a>());

or as an extension method:

public static class WatiN_IE_ExtensionMethods_JQuery
{
public static WatiN_IE inject_jQuery(this WatiN_IE ie)
{
ie.eval("<a href="http://code.jquery.com/jquery-1.6.2.min.js%22.uri().getHtml">http://code.jquery.com/jquery-1.6.2.min.js".uri().getHtml</a>());
return ie;
}
}

Puting it all together, here is a script that:

  •  opens up JPetStore
  • Injects FirebugLite
  • Injects jQuery
  • runs a jQuery command that:
    • selects an ‘a’ with the content ‘Enter the Store’
    • changes its border to 2px
    • changes it size to 20px
    • fades it out in 2000 ms
    • fades is it in 2000 ms
var topPanel = panel.clear().add_Panel();
var ie = topPanel.add_IE().silent(true);
var jPetStore = new API_JPetStore(ie);

jPetStore.homePage();
ie.inject_FirebugLite();
ie.inject_jQuery();
ie.eval("jQuery(\"a:contains('Enter the Store')\").css({'border': 'solid 10px', 'font-size' : 30 } ).fadeOut(2000).fadeIn(2000);");</pre>
 
//O2File:API_JPetStore.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is a screenshot what what this looks like:

July 13, 2011 Posted by | IE Automation, JPetStore, jQuery, Spring MVC, WatiN | Leave a comment

Using jQuery to consume an ASP.NET Ashx from JSON in two files

Here is a basic asp.net based JSON based ‘webservice’ which can be implemented with two files and requires no compilation

Javascript code (DataHandler.js):

function CallHandler() {
$.ajax({
url: "DataHandler.ashx",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: { 'page': '100AAAAAf00' },
responseType: "json",
success: OnComplete,
error: OnFail
});
return false;
}

function OnComplete(result) {
alert(JSON.stringify(result));
}
function OnFail(result) {
alert('Request Failed');
}

CallHandler();

Server side code (DataHandler.ashx):

<%@ WebHandler Language="C#" %></pre>
&nbsp;

using System.Text;
using System.Web;
using System.Web.Script.Serialization;

public class test
{
public string var1 {get;set;}
public string var2 {get;set;}
public string page {get;set;}
public test()
{
var1 = "aaaa";
var2 = "bbb";
}
}

public class GetDataHandler : IHttpHandler
{
public HttpContext context;
public HttpRequest request;
public HttpResponse response;

public void handleRequest()
{
//writeRaw("this is a message");
writeJson(new test() { page = request["page"] });
}

public bool IsReusable
{
get { return false; }
}

public void ProcessRequest (HttpContext _context)
{
context = _context;
request = _context.Request;
response = _context.Response;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;

handleRequest();

}

public void writeJson(object _object)
{
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
string jsondata = javaScriptSerializer.Serialize(_object);
writeRaw(jsondata);
}


public void writeRaw(string text)
{
context.Response.Write(text);
}
}

result

{"var1":"aaaa","var2":"bbb","page":"100AAAAAf00"}

references

based on source code samples from:

July 12, 2011 Posted by | IE Automation, jQuery | 1 Comment

Creating a jQuery DataTable using serialized JSON object

Using the same technique used in the JsTree example, here is a DataTable dynamically populated from a serialized JSON object

//based on example from http://www.datatables.net/release-datatables/examples/data_sources/js_array.html
//var topPanel = panel.clear().add_Panel(); 
var topPanel = "Poc - jQuery jsDataTable".popupWindow(900,400);

var jsDataTable =  new JsDataTable();

jsDataTable    .add_Row("Trident", "Internet Explorer 4.0", "Win 95+", 4, "X")
               .add_Row("Trident", "Internet Explorer 4.0", "Win 95+", 4, "X")
            .add_Row("Trident", "Internet Explorer 5.0", "Win 95+", 5, "C")
            .add_Row("Trident", "Internet Explorer 5.5", "Win 95+", 5.5, "A")
            .add_Row("Trident", "Internet Explorer 6.0", "Win 98+", 6, "A")
            .add_Row("Trident", "Internet Explorer 7.0", "Win XP SP2+", 7, "A")
            .add_Row("Gecko", "Firefox 1.5", "Win 98+ / OSX.2+", 1.8, "A")
            .add_Row("Gecko", "Firefox 2", "Win 98+ / OSX.2+", 1.8, "A")
            .add_Row("Gecko", "Firefox 3", "Win 2k+ / OSX.3+", 1.9, "A")
            .add_Row("Webkit", "Safari 1.2", "OSX.3", 125.5, "A")
            .add_Row("Webkit", "Safari 1.3", "OSX.3", 312.8, "A")
            .add_Row("Webkit", "Safari 2.0", "OSX.4+", 419.3, "A")
            .add_Row("Webkit", "Safari 3.0", "OSX.4+", 522.1, "A");

jsDataTable.add_Columns("Engine", "Browser", "Platform");
jsDataTable.add_Column("Version", "center");
jsDataTable.add_Column("Grade", "center");
//adding without using extension methods
/*jsDataTable.aaData.Add(new List<string> { "Trident", "Internet Explorer 4.0", "Win 95+", "4", "X" });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Engine"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Browser"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Platform"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Version" , sClass = "center" });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Grade" , sClass = "center" }); */

//return "{0}".info(jsDataTable.jsonString());

 
var ie = topPanel.add_IE();                 

ie.showMessage("loading dataTable js and css");

var jQuery = new IE_JQuery(ie);    
var cssFile = @"dataTable_demo.css".local();
var styleHtml =  "<style type=\"text/css\"> {0} </style>".format(cssFile.fileContents().fixCRLF().remove("".line()).replace("'", "\""));

var injectCSS = "$('body').append($('"  + styleHtml + "' ))";
ie.invokeEval(injectCSS);

//ie.invokeEval("<a href="http://static.jstree.com/v.1.0pre/jquery.jstree.js%22.uri().getHtml">http://static.jstree.com/v.1.0pre/jquery.jstree.js".uri().getHtml</a>());  // use to get jstree from jstree.com website
ie.invokeEval("jquery.dataTables.min.js".local().fileContents());
jQuery.element("div").html("creating local table");

ie.invokeEval("$('body').append($('<div id=\"testDataTable\"/>')); $('#testDataTable').html('test DataTable will go here');");
ie.invokeEval("$('#testDataTable').html( '<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"display\" id=\"example\"></table>' );");
//ie.invokeEval("%('#example').html('aaaaaaaaa')");
/*var dataToBuildTable =  "                        { " +    
                        "                                'aaData': [" +
                        "                                                [ 'Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X' ], " +
                        "                                                [ 'Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C' ], " +
                        "                                                [ 'Gecko', 'Firefox 3', 'Win 2k+ / OSX.3+', 1.9, 'A' ], " +
                        "                                                [ 'Webkit', 'Safari 1.2', 'OSX.3', 125.5, 'A' ]          " +
   
                        "                                          ]," +         
                        "                                'aoColumns': [" +
                        "                                                { 'sTitle': 'Engine' }, " +
                        "                                                { 'sTitle': 'Browser' }, " +
                        "                                                { 'sTitle': 'Platform' }, " +
                        "                                                { 'sTitle': 'Version', 'sClass': 'center' }, " +
                        "                                                { 'sTitle': 'Grade', 'sClass': 'center' } " +
                        "                                               ]" +
                        "                        }      ";     */
                
var dataToBuildTable = jsDataTable.jsonString();
ie.invokeEval(" $('#example').dataTable( " + dataToBuildTable +" );"  );

//O2File:JsDataTable.cs

return "done";

//O2File:IE_JQuery.cs
//O2Ref:WatiN.Core.1x.dll
//O2Ref:Microsoft.mshtml.dll

Here is the code of the JsDataTable class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.ExtensionMethods;

//O2Ref:System.Web.Extensions.dll

namespace O2.XRules.Database.APIs
{
    public class JsDataTable
    {
        public List<List<object>> aaData;
        public List<JsDataColumn> aoColumns;       
       
        public JsDataTable()
        {
             aaData = new List<List<object>>() ;
             aoColumns = new List<JsDataColumn>();
        }
       
        public class JsDataColumn
        {
            public string sTitle {get; set; }
            public string sClass {get; set; }
        }
    }
   
   
    public static class JsDataTable_ExtensionMethods
    {
        public static string jsonString(this object _object)
        {
            return new JavaScriptSerializer().Serialize(_object);
        }
       
        public static JsDataTable add_Row(this JsDataTable jsDataTable, params object[] cells)
        {
            return jsDataTable.add_Row(cells.toList());
        }
       
        public static JsDataTable add_Row(this JsDataTable jsDataTable, List<object> cells)
        {
            jsDataTable.aaData.Add(cells);
            return jsDataTable;
        }
               
        public static JsDataTable add_Column(this JsDataTable jsDataTable, string title)
        {
            return jsDataTable.add_Column(title, null);
        }
       
        public static JsDataTable add_Column(this JsDataTable jsDataTable, string title, string _class)
        {
            jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = title, sClass = _class });
            return jsDataTable;
        }
       
        public static JsDataTable add_Columns(this JsDataTable jsDataTable, params string[] titles)
        {
            foreach(var title in titles)
                jsDataTable.add_Column(title);
            return jsDataTable;
        }
    }
}

June 21, 2011 Posted by | IE Automation, jQuery, WatiN | Leave a comment

Creating a jQuery jsTree using serialized JSON object

Based on the code samples from http://mohyuddin.blogspot.com/2009/05/binding-jstree-programmatically-with.html this O2 Platform script shows how to create a jsTree (jQuery plugin) using as a data source a serialized JSON object (this is perfect for use on a web service)

//var topPanel = panel.clear().add_Panel(); 
var topPanel = "Poc - jQuery jsTree".popupWindow(600,200);
 
var ie = topPanel.add_IE();                </pre>
&nbsp;

ie.showMessage("loading jstree js");

var jQuery = new IE_JQuery(ie);  

var cssFile = @"jquery.jstree.style.css".local();
var styleHtml =  "<style type=\"text/css\"> {0} </style>".format(cssFile.fileContents().remove("".line()));
var injectCSS = "$('body').append($('"  + styleHtml + "' ))";
ie.invokeEval(injectCSS);

//ie.invokeEval("<a href="http://static.jstree.com/v.1.0pre/jquery.jstree.js%22.uri().getHtml">http://static.jstree.com/v.1.0pre/jquery.jstree.js".uri().getHtml</a>());  // use to get jstree from jstree.com website
ie.invokeEval("jquery.jstree.js".local().fileContents());
jQuery.element("div").html("creating local tree");
ie.invokeEval("$('body').append($('<div id=\"testJsTree\"/>')); $('#testJsTree').html('test JsTree will go here');");

var jsTree = new JsTree();
jsTree.add_Node("node 1");
jsTree.add_Node("node 2") 
      .add_Node("child 1")
      .add_Nodes("sub child 1", "sub child 2");
jsTree.add_Nodes("node 3", "node 4");
 
ie.invokeEval("treeData = " + jsTree.jsonString());                                  // this creates a string for the serialized jsTree object
//ie.invokeEval("treeData = { 'data' : ['firstnode' ,'2ndNode', '3rdNode' ]  }");    // this creates a tree it manually
ie.invokeEval("jQuery('#testJsTree').jstree({ 'json_data' : treeData ,  'plugins' : [  'themes', 'json_data' , 'dnd']} );");

jQuery.element("div").html("tree created");

return "ok";
//O2File:JsTreeNode.cs
//O2File:IE_JQuery.cs
//O2Ref:WatiN.Core.1x.dll
//O2Ref:Microsoft.mshtml.dll

Here is the code of the JsTree class (in the JsTreeNode.cs file):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
//O2Ref:System.Web.Extensions.dll

namespace O2.XRules.Database.APIs
{
    public class JsTree
    {
        public List<JsTreeNode> data;
       
        public JsTree()
        {
            data = new List<JsTreeNode>();
        }
    }
   
    public class JsTreeNode
    {
        public Attributes attributes { get; set; }      
        public Data data  { get; set; }          
        public string state { get; set; }              
        public List<JsTreeNode> children { get; set; }          
       
        public JsTreeNode()
        {
            children = new  List<JsTreeNode>();
            data = new Data();
            attributes = new Attributes();
        }   
        public  JsTreeNode(string title) : this()
        {
            data.title = title;
        }
       
    }
    public class Attributes
    {
        public string id { get; set; }  
        public string rel { get; set; }          
        public string mdata { get; set; }      
    }
   
    public class Data
    {
        public string title { get; set; }      
        public string icon { get; set; }      
    }
   
    public static class JsTree_ExtensionMethods
    {
        public static string jsonString(this object _object)
        {
            return new JavaScriptSerializer().Serialize(_object);
        }
       
        public static JsTreeNode add_Node(this JsTree jsTree, string title)
        {
            var newJsTreeNode = new JsTreeNode(title);
            jsTree.data.Add(newJsTreeNode);
            return newJsTreeNode;
        }
       
        public static List<JsTreeNode> add_Nodes(this JsTree jsTree, params string[] titles)
        {
            var newJsTreeNodes = new List<JsTreeNode>();
            foreach(var title in titles)
                newJsTreeNodes.Add(jsTree.add_Node(title));
            return newJsTreeNodes;
        }
       
        public static JsTreeNode add_Node(this JsTreeNode jsTreeNode, string title)
        {
            var newJsTreeNode = new JsTreeNode(title);
            jsTreeNode.children.Add(newJsTreeNode);
            return newJsTreeNode;
        }
       
        public static List<JsTreeNode> add_Nodes(this JsTreeNode jsTreeNode, params string[] titles)
        {
            var newJsTreeNodes = new List<JsTreeNode>();
            foreach(var title in titles)
                newJsTreeNodes.Add(jsTreeNode.add_Node(title));
            return newJsTreeNodes;
        }
    }
}

Based on the original code sample, here is a working version of its test script:


List<JsTreeNode> nodesList = new List<JsTreeNode>();
for (int i = 1; i < 10; i++)
{
    JsTreeNode node = new JsTreeNode();
    node.attributes = new Attributes();
    node.attributes.id = "rootnod" + i;
    node.attributes.rel = "root" + i;
    node.data = new Data();
    node.data.title = "Root node:" + i;
    node.state = "close";

    node.children = new List<JsTreeNode>();

    for (int j = 1; j < 4; j++)
    {
        JsTreeNode cnode = new JsTreeNode();
        cnode.attributes = new Attributes();
        cnode.attributes.id = "childnod1" + j;
        node.attributes.rel = "folder";
        cnode.data = new Data();
        cnode.data.title = "child node: " + j;
        cnode.attributes.mdata = "{draggable : true,max_children : 1,max_depth : 1 }";
        node.children.Add(cnode);

    }
    node.attributes.mdata = "{draggable : false,max_children : 1, max_depth :1}";
    nodesList.Add(node);
}
var jsTree = new JsTree();
jsTree.data= nodesList; 
var jsonData = new JavaScriptSerializer().Serialize(jsTree);       

return jsonData;   

June 21, 2011 Posted by | IE Automation, jQuery, WatiN | 3 Comments

Invoking jQuery from O2

jQuery is an amazing  javascript API and since O2 has a two-way communcations with the hosted IE object, there is a new O2 API that allows the managed (ie. in O2) manipulation of jQuery.

Here is an exampe of this api in action:

var topPanel = "PoC - jQuery IE Automation example".popupWindow(600,700);
var ie = topPanel.add_IE().silent(true);

ie.open(<a href="http://jquery.bassistance.de/autocomplete/demo/">http://jquery.bassistance.de/autocomplete/demo/</a>);
var jQuery = new IE_JQuery(ie);
jQuery.id("suggest1")            // getting reference to html element with id 'suggest1'
      .border(12)               // seeting the border value to 12
      .value("London")            // setting the 'value' attribute to 'London'
      .keydown();     
         
jQuery.wait(200)                  // wait 200 ms to give time for the '.ac_over:first' to exist
      .element(".ac_over:first")  // get reference to '.ac_over:first' element
      .parent()                      // invoke the jQuery 'parent' method
      .click();                      // invoke the jQuery 'click' method     
     
jQuery.wait(1000).id("suggest1").border(2);      // wait 1s before removing the border</pre>
return "ok";

//O2File:IE_JQuery.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is a longer version of the above script (the following code samples are not ‘standalone *.h2 scripts and will need to be executed inside the ‘Quick Development Environment’ or ‘IE Automation’ scripts (since they need the ‘panel’ variable):

panel.clear();
var ie = panel.add_IE().silent(true);

ie.open("http://jquery.bassistance.de/autocomplete/demo/");

var jQuery = new IE_JQuery(ie);
jQuery.id("suggest1")            // getting reference to html element with id 'suggest1'
      .border(12)               // seeting the border value to 12
      .value("London")            // setting the 'value' attribute to 'London'
      .keydown();     
         
jQuery.wait(200)                  // wait 200 ms to give time for the '.ac_over:first' to exist
      .element(".ac_over:first")  // get reference to '.ac_over:first' element
      .parent()                      // invoke the jQuery 'parent' method
      .click();                      // invoke the jQuery 'click' method     
     
jQuery.wait(1000).id("suggest1").border(2);      // wait 1s before removing the border

return "ok";

     
// here is a more verbose version of the above script
ie.wait(1000);

jQuery.element("#suggest1").border(12);              
jQuery.id("suggest1").attr("value","Lond").keydown();   
ie.wait(200);
jQuery.element(".ac_over:first").parent().click();
// here is a version using much more raw jQuery manipulations and experiements
ie.invokeEval("jQuery(\"#suggest1\").attr('value','mode 1')");
ie.wait(1000);
jQuery.invokeJQuery("'#suggest1').attr('value','mode 2'");
ie.wait(1000);
jQuery.element("#suggest1").invokeJQuery("attr","'value' , 'mode 3' ");
ie.wait(1000);
jQuery.element("#suggest1").attr("value","L");
ie.wait(1000);
jQuery.id("suggest1").invokeJQuery("trigger", "'keydown'");
ie.wait(1000);
jQuery.element(".ac_over:first").invokeJQuery("parent","").invokeJQuery("click","");
return "done";
//O2File:IE_JQuery.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

 
Here is the Script provided by an Daniel (an O2 user) which inspired the creation of this script:

panel.clear();
var ie = panel.add_IE().silent(true);</pre>
ie.open("http://jquery.bassistance.de/autocomplete/demo/");
//ie.invokeEval(incJquery);
ie.field("suggest1").value("London"); //entering value inside first autocomplete control
ie.invokeEval("$('#suggest1').trigger('keydown')"); //triggering keyboard event
ie.wait(100);
ie.invokeEval("$('.ac_over:first').parent().click()"); //choosing first value from autocomplete
return ie.fields();
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

 
this is how Daniel was injecting jQuery into the page (note that the IE_JQuery.cs api also does this)

var incJquery = "var script = document.createElement('script');";
incJquery += "script.src = 'http://code.jquery.com/jquery-latest.pack.js';";
incJquery += "script.type = 'text/javascript';";
incJquery += "document.body.insertBefore( script, document.body.firstChild );";
ie.invokeEval(incJquery);

June 8, 2011 Posted by | IE Automation, jQuery, WatiN | Leave a comment

Trigger an Keypress event in IE

Using O2’s IE Automation (which is a wrapper on top of WatiN), if you need to trigger an Javascript event, there are a couple ways this can be done:
(this text was originally written to answer a question posted on O2’s mailing list)

June 6, 2011 Posted by | IE Automation, jQuery, WatiN | Leave a comment