Friday 19 April 2013

Finding a html link with no ID in the middle of a web page using WatiN (via IE objects and jQuery)

When coding web automation scripts,  a common problem is that the target HTML element that we want to access doesn't have any id or attribute that we can use to map it.

This posts shows a number of examples on how to to find those HTML elements using O2 Platform’s WatiN/IE extension methods.

Lets start with this html code sample (see end of post for the actual code)

image

If you execute it on a O2 Platform’s C# REPL GUI you should get something like this:

image

Note: our objective is to trigger the onClick event on the main link, which should pop up an alert:

image

Example 1) CLICK THE LINK: Using list of links

The first way to click on the lists is to get a list of links:

image

find the one we want ( ie.links()[1]) , ie.links().value(1) or ie.links().item(1) would also work, with the last two returning null if the index provided is took big)

image

(note how you get a lot of details about the current element in the Output window)

Once we have the link we want we can just. click() it :)

image

Tip: if you are doing a demo you might want to add a .flash() to highlight the element before clicking on it:

image

and use .disableFlashing() during development (so you don’t have to wait for it):

image

Example 2) CLICK THE LINK: Using innerHTML

Another way to find the link is to use the .innerHtml() value:

image

which can be used on a foreach loop:

image

to find and click it:

image

if you wanted to store the link in a strongly type variable, use the .getFullName() method to find the type:

image

And then use a variable to hold its value before you click it:

image

We can refactor this code by moving the WatiN.Core reference into an using statement (which can be anywhere on the script, but are usually included at the end)

image

and replacing the foreach with a lambda method:

image

and in this case we don’t even need the foundLink variable:

image

or use a smaller text to search for the link:

image

Example 3) CLICK THE LINK: Via an Image

Another way to find a link is to search for something that we know is inside it (like an image)

image

get its parent:

image

cast it into a Link object and click it:

image

Tip: you can use an element/image attributes to find the image/element you want:

image


Example 4) CLICK THE LINK: Using jQuery

If you are a jQuery fan, then you can also use it to click on the link.

Start by adding jQuery (if not there)

image

And here is how to use jQuery to find the link:

image

And how to click on the link (using a jQuery selector):

image

Tip: Inject FireBug Lite to make your life easier writing the scripts:

image

which will allow to you try out your jQuery scripts:

image

That's it, let me know if this helps and if you have other ways to find those annoying HTML elements with no id attribute :)

Code samples used on this post

here are some of the code samples used to create the screenshots shown above:

Loading test HTML in Web Browser:
var ie = panel.clear().add_IE().silent(false); 
//original HTML that would be found in the middle of a big web page
var targetHtml = @"<A TABINDEX=""1""
                    onKeyDown=""KeyEnter(this)"" 
                    onClick=""javascript:alert('I was clicked')""
                    STYLE=""cursor:hand;"" 
                    onMouseOut=""SetImage('TaskList','');""
                    onMouseDown=""SetImage('TaskList','pressed');"" 
                    TARGET=""main"">
                  <IMG NAME=""TaskList"" SRC=""images/TaskList.jpg"" ALT=""Show Your Task List"" BORDER=""0""/></A>";

//adding a couple links before and after to make the sample a bit more realistic
var codeSample = "<a href=''>a link before</a><br/>{0} <br/><a href=''>a link after</a><br/>".format(targetHtml);

//load the html into the current IE object (you could also save the text as an HTML page and open that)
ie.set_Html(codeSample);

return ie.IE.Html;


Clicking using innerHtml via foreach loop:
var ie = panel.clear().add_IE().silent(false); 
//original HTML that would be found in the middle of a big web page
var targetHtml = @"<A TABINDEX=""1""
                    onKeyDown=""KeyEnter(this)"" 
                    onClick=""javascript:alert('I was clicked')""
                    STYLE=""cursor:hand;"" 
                    onMouseOut=""SetImage('TaskList','');""
                    onMouseDown=""SetImage('TaskList','pressed');"" 
                    TARGET=""main"">
                  <IMG NAME=""TaskList"" SRC=""images/TaskList.jpg"" ALT=""Show Your Task List"" BORDER=""0""/></A>";

//adding a couple links before and after to make the sample a bit more realistic
var codeSample = "<a href=''>a link before</a><br/>{0} <br/><a href=''>a link after</a><br/>".format(targetHtml);

//load the html into the current IE object (you could also save the text as an HTML page and open that)

ie.set_Html(codeSample);

var innerHtmlToFind = "<IMG border=0 name=TaskList alt=\"Show Your Task List\" src=\"images/TaskList.jpg\">";

WatiN.Core.Link foundLink = null;

foreach(var link in ie.links())
    if (link.innerHtml() == innerHtmlToFind)
    {
        foundLink = link;
        break;
    }
if (foundLink.notNull())
    foundLink.click();    
    
return foundLink;

//return ie.links().second().innerHtml();


//O2File:WatiN_IE_ExtensionMethods.cs 
//O2Ref:WatiN.Core.1x.dll


Clicking using innerHtml via Lambda method:
var ie = panel.clear().add_IE().silent(false); 
//original HTML that would be found in the middle of a big web page
var targetHtml = @"<A TABINDEX=""1""
                    onKeyDown=""KeyEnter(this)"" 
                    onClick=""javascript:alert('I was clicked')""
                    STYLE=""cursor:hand;"" 
                    onMouseOut=""SetImage('TaskList','');""
                    onMouseDown=""SetImage('TaskList','pressed');"" 
                    TARGET=""main"">
                  <IMG NAME=""TaskList"" SRC=""images/TaskList.jpg"" ALT=""Show Your Task List"" BORDER=""0""/></A>";

//adding a couple links before and after to make the sample a bit more realistic
var codeSample = "<a href=''>a link before</a><br/>{0} <br/><a href=''>a link after</a><br/>".format(targetHtml);

//load the html into the current IE object (you could also save the text as an HTML page and open that)

ie.set_Html(codeSample);

var innerHtmlToFind = "name=TaskList alt=\"Show Your Task List\" src=\"images/TaskList.jpg\">";


return ie.links()
            .where((link)=> link.innerHtml() == innerHtmlToFind)
         .first()
         .click();


//using WatiN.Core
//O2File:WatiN_IE_ExtensionMethods.cs 
//O2Ref:WatiN.Core.1x.dll


Click using an Image’s parent:
var ie = panel.clear().add_IE().silent(false); 
//original HTML that would be found in the middle of a big web page
var targetHtml = @"<A TABINDEX=""1""
                    onKeyDown=""KeyEnter(this)"" 
                    onClick=""javascript:alert('I was clicked')""
                    STYLE=""cursor:hand;"" 
                    onMouseOut=""SetImage('TaskList','');""
                    onMouseDown=""SetImage('TaskList','pressed');"" 
                    TARGET=""main"">
                  <IMG NAME=""TaskList"" SRC=""images/TaskList.jpg"" ALT=""Show Your Task List"" BORDER=""0""/></A>";

//adding a couple links before and after to make the sample a bit more realistic
var codeSample = "<a href=''>a link before</a><br/>{0} <br/><a href=''>a link after</a><br/>".format(targetHtml);

//load the html into the current IE object (you could also save the text as an HTML page and open that)

ie.set_Html(codeSample);

var link = (Link)ie.images().first().Parent;
link.click();
return "link clicked";

//using WatiN.Core
//O2File:WatiN_IE_ExtensionMethods.cs 
//O2Ref:WatiN.Core.1x.dll


Click using jQuery
var ie = panel.clear().add_IE().silent(false); 
//original HTML that would be found in the middle of a big web page
var targetHtml = @"<A TABINDEX=""1""
                    onKeyDown=""KeyEnter(this)"" 
                    onClick=""javascript:alert('I was clicked')""
                    STYLE=""cursor:hand;"" 
                    onMouseOut=""SetImage('TaskList','');""
                    onMouseDown=""SetImage('TaskList','pressed');"" 
                    TARGET=""main"">
                  <IMG NAME=""TaskList"" SRC=""images/TaskList.jpg"" ALT=""Show Your Task List"" BORDER=""0""/></A>";

//adding a couple links before and after to make the sample a bit more realistic
var codeSample = "<a href=''>a link before</a><br/>{0} <br/><a href=''>a link after</a><br/>".format(targetHtml);

//load the html into the current IE object (you could also save the text as an HTML page and open that)

ie.set_Html(codeSample);

ie.inject_jQuery();

ie.eval("$('a').eq(1).click();");

//using WatiN.Core
//O2File:WatiN_IE_ExtensionMethods.cs 
//O2Ref:WatiN.Core.1x.dll