Many a customer has asked us "What, the heck, is XhtmlPage and do I need it to run your components?" It is an oddity in our QuickStart examples application that needs some explanation. Atanas
, the creator of the class, has already started that in his "Making ASP.NET XHTML 1.1 compliant" post
Today I was describing a testing approach on the Extreme Programming mailing list
that relied on the fact that our controls render standards compliant XHTML, and you could leverage that to write tests using the XML API in .NET -- XPath is sooo convenient for that. And then it hit me! What if I could work all my HTML as an XML document and write XPath queries against it? Web page testing would be a whole lot easier if ASP.NET has been XHTML compliant, but wait, we already have a solution for that.
You don't need much:
- Get a trial of a telerik product. I am playing more and more with r.a.d.grid, so I picked its trial distro.
- Add a reference to Telerik.QuickStart.dll in your project. You can find the assembly inside the NET1/bin or NET2/bin folders.
- Get your page to inherit from Telerik.QuickStart.XhtmlPage instead of the standard Page class.
- Start writing tests!
Here is a simple test that asserts if the DropDownList1 control has its "False" option selected:
public void TestFalseSelected()
string page = "http://localhost/telerik/r.a.d.grid3.0_NET1/Grid/Examples/GeneralFeatures/Sorting/DefaultCS.aspx";
XmlDocument doc = GetPageDocument(page);
XmlNode selectedOption = doc.SelectSingleNode("//select[@name='DropDownList1']//option[@selected='selected']");
I am using the fact that drop-down lists are rendered as HTML <select> elements that contain a set of <option> ones. The XPath means "get me the <select> that has a name attribute of "DropDownList1", then look for a child <option> element that has its selected attribute set to "selected". The assertion is straight-forward -- does that <option>'s value attribute equal to "False".
Here is the GetPageDocument method. It has some gotchas: I remove the <!DOCTYPE> header, so that XmlDocument does not slow-down while trying to fetch the DTD off W3C's servers. Well, removing the doctype gets you some "unresolved entities" errors for , ©, and the likes, so I added a dummy definition for those entities -- just a simple <span> element:
public XmlDocument GetPageDocument(string pageAddress)
WebClient client = new WebClient();
using (Stream dataStream = client.OpenRead(pageAddress))
StreamReader reader = new StreamReader(dataStream);
string contents = reader.ReadToEnd();
contents = Regex.Replace(contents, "<!DOCTYPE[^>]+>", "", RegexOptions.IgnoreCase);
string customEntitiesDeclaration = @"<!DOCTYPE testdocument [
<!ENTITY nbsp ""<span />"">
<!ENTITY copy ""<span />"">
contents = customEntitiesDeclaration + contents;
XmlDocument document = new XmlDocument();
So, that wasn't hard. Get all your tags closed, write their names in lowercase, use the XhtmlPage class to force that for most of ASP.NET's broken controls, and get those tests rolling.