WatiN and INamingContainer adventures

I decided to add a simple WatiN acceptance test today to validate our login page.  When a user enters invalid credentials, the page should show an error message.

To test this, I need to set the text of the username and password, and click the Login button.  Since I didn’t want just any textbox, but specifically the username and the password, I like to use the element ID’s to find them.

We’re using the ASP.NET Login control to provide the login interface, which has the textboxes, the button, and the error message in one package.  When I want to get the ID, this is what it winds up being:


Well that’s no fun.  The INamingContainer interface puts out some crazy HTML element IDs to guarantee uniqueness.  Luckily I can use regular expressions to search for elements ending in “UserName”, and that works for the button, too.

However, the error message does not have an ID around it, so I have to dig into the login control manually to fish it out:

Table loginControl = browser.Table(new Regex("._ctlLogin$"));
TableCell errorCell =

Since I don’t have access to the innards of the HTML in the Login control, this is what I have to resort to.

I’m really looking forward to MVC framework, where I can take back control over the HTML generated.  At least WatiN will be easier.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASPdotNET, Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • You can use the LayoutTemplate section of the Login control to specify your own HTML, and therefore control IDs. See:



  • Interresting problem to solve, The next version of InCisif.net (2.1) will support this problem during recording and run time and produce clear code like this one:

    Page.Control(AspNetId(“butCreateAccount”)).Click(); // ASP.NET ID:ctl00$ContentPlaceHolder1$butCreateAccount

    Page.Control(AspNetId(“FirstName”)).Text = “Joe”; // ASP.NET ID:ctl00$ContentPlaceHolder1$FirstName
    Page.Control(AspNetId(“LastName”)).Text = “Doe”; // ASP.NET ID:ctl00$ContentPlaceHolder1$LastName

    Page.Control(AspNetId(“butOK”)).Click(); // ASP.NET ID:ctl00$ContentPlaceHolder1$butOK

    The function AspNetId can be override and the default implementation look like this:

    public virtual string AspNetId(string id){

    string t = string.Format(@”re:(.*\${0}$)|(.*_{0}$)”, id);
    if(Page.Control(t)!=null)return t;

    return id;

    Frederic Torres
    Web Testing with C# or VB.NET