Wednesday, July 01, 2009

Determining Html Element Visibility with WatiN

I recently started using WatiN to write automated Web application tests for the first time. WatiN is a great and rapidly maturing tool with lots of developer support, and I highly recommend it based on my experiences so far. But after writing several tests of dynamic screen elements I realized the tests weren't verifying everything I thought they were verifying.

When you use WatiN "Find" syntax to search for elements and screen text there's no obvious distinction made between hidden and visible elements. The screens I was testing use ASP.NET validation controls to perform client-side validation and include other dynamic elements such as the AJAX.NET ModalPopupExtender. I wanted to verify that these elements were visible and hidden at the appropriate times, and the simplest way of accomplishing this with WatiN was not immediately obvious.

After digging around in the API a bit I came up with a method that's simple, robust and seems to perform reasonably well. As demonstrated in the sample tests below, you can simply walk up the element hierarchy checking whether an element or any of its parents are styled with "display: none".

   1: using System.Text.RegularExpressions;
   2: using NUnit.Framework;
   3: using WatiN.Core;
   4:  
   5: [TestFixture]
   6: public class WatinTest
   7: {
   8:     [Test]
   9:     public void PopupDisplayed()
  10:     {
  11:         var ie = new IE();
  12:         ie.GoTo("http://www.example.com");
  13:  
  14:         Div popup = ie.Div(Find.ById(new Regex("pnlPopup$")));
  15:         Assert.IsTrue(IsDisplayed(popup));
  16:     }
  17:  
  18:     [Test]
  19:     public void ValidatorDisplayed()
  20:     {
  21:         var ie = new IE();
  22:         ie.GoTo("http://www.example.com");
  23:  
  24:         Span validator = ie.Span(Find.ByText("Required field"));
  25:         Assert.IsTrue(IsDisplayed(validator));
  26:     }
  27:  
  28:     public bool IsDisplayed(Element element)
  29:     {
  30:         if (string.Equals(element.Style.Display, "none"))
  31:         {
  32:             return false;
  33:         }
  34:         if (element.Parent != null)
  35:         {
  36:             return IsDisplayed(element.Parent);
  37:         }
  38:         return true;
  39:     }
  40: }

The first test case (PopupDisplayed) searches for the div element representing a modal popup panel by the element id. It uses a regular expression since the ASP.NET control ids for nested controls are unwieldy and variable. In this test we are checking whether the div itself is displayed, but this method would also work for any control contained by the div (such as a submit or text input element).

The second test (ValidatorDisplayed) searches for the span element representing a RequiredFieldValidator by the validation text contained in the span.

Some caveats apply when using this method:

  • It works only with embedded CSS styles. If the "display: none" style was applied using a CSS class contained in a style sheet the WatiN Element.Style property would NOT automatically reflect this.
  • It doesn't determine true element visibility--only whether the element is displayed. Elements may also be hidden using "visibility: hidden", occluded by other elements with a higher z-index, or moved offscreen using the position style.

As a side note, I highly recommend that you grab the Internet Explorer Developer Toolbar and take some time to understand the WatiN page model before writing many tests.

5 comments:

braincells2pixels.net said...

Great tip! I urge you to check out MBUnit for ASP.Net UI testing in conjunction with WatiN. What I like about MBUnit is the ability to capture the state of the UI (Screen capture) when tests fail. Sometimes, failed test with a picture is worth more than the red! MBUnit has sample code that demonstrates the use of WatiN.

AT said...

I did not know that about MBUnit. It does sound very useful and I will check it out!

John said...

Hello,

I just started working with WatiN this week, and ran into a problem that your blog post helped me to solve!

So thanks a bunch sir. I am much obliged.

AT said...

@John: Great to hear! Thanks for the feedback.

JohnP said...

An alternative that works by invoking JavaScript to determine element visibility can be found here:

http://stackoverflow.com/questions/6890282/how-to-check-with-watin-is-element-hidden/7026506#7026506

HTH!

JohnP

 
Header photo courtesy of: http://www.flickr.com/photos/tmartin/ / CC BY-NC 2.0