dinsdag 22 december 2009

Released WatiN 2.0 RC 1

A short shout out to announce the release of WatiN 2.0 Release Candidate 1.

Many fixes and new features since the last beta 1 release way back in March. I’m still compiling the list of changes so check back on this page later this week. But if you follow my blog you are well informed already. If you haven’t been using beta 1, start reading the release note of that release here.

And of course  you want to download the new release.

Enjoy testing with WatiN!

Technorati Tags:

vrijdag 11 december 2009

Wrapping complex logic in a Control

Update 18 December 2009: Added missing file to code download

WatiN is all about simplifying the way you can interact with a web browser and the elements on a page. Simple elements are just wrapped (like divs, links and alike) but for more complex elements WatiN offers you functionality which hides complex interactions with the browser. For instance TextField.TypeText will not only set the value of an input field but will also fire all the appropriate events, basically simulating a real user typing in text.

But what if you want to automate/model some action that involves complex logic and/or multiple elements. Yes indeed I am referring to all those ASP and third party controls out there. In this post I will show you how to create your own control which you can use as if it is an element on the page and natively supported by WatiN.

You can download the code for this post here (which also contains a build of WatiN 2.0 RC1)

The control to automate: JQuery-UI Datepicker

I’m going to show you how to create a basic control for the jQuery UI Datepicker. But that’s simple you might think, just use TypeText of the TextField class, the WatiN wrapper for input elements of type text. True, but then I need to think about formating the date correctly every time I automate a datepicker. And there might be other things I would like to check on the datepicker (see  jQuery-UI Datepicker for all the options that can be set and read on this widget). So I’m going to use the javascript API of the datepicker to automate the control.

imageimage

Wondering how to use this control in your test code?

image

Looks familiar (and simple) doesn’t it.

The implementation of DatePicker

To create the control I need a root WatiN.Core.Element subtype which will be the base/root Element for my DatePicker control. Since a html input of type text serves as the root element for the jQuery UI datepicker widget, it makes sense that DatePicker will use TextField as its root Element.

image

Since I decided I’m going to use the datepicker’s javascript API, the control needs to execute scripts inside the browser. Fortunately WatiN offers this functionality through the RunScript() and Eval() methods, both exposed by the DomContainer class. Control<T>, the base class for every control, exposes the property Element which returns the root Element of the control, in this case TextField. From there we can get to the DomContainer to execute javascript using Eval().

image

Next thing to do is to create the javascript to set the date using the API of the jQuery datepicker. This is what the script needs to look like to set the date to 10 December 2009 (indeed the month is 11, a javascript thingy):

window.jQuery(element).datepicker(‘setDate’, new Date(2009, 11, 10));

To make sure that the javascript references the correct html element in the DOM, I will make use of the new method  GetJavascriptElementReference(), available on every (subtype of) Element (in WatiN 2.0 RC1). And of course the Date should be created  correctly.

I’m also using window.jQuery() instead of window.$() to make sure this script will also work when $() is not a shortcut for the jQuery() function (but instead is used by some other javascript library like Prototype).

I will combine all this in the setter part of the Date property of the DatePicker control:

image

For the getter part there is one catch, transforming the returned javascript date in to a DateTime instance. Fortunately DateTime.Parse parses a UTC date format without any problem, so I let the javascript return the date in such a format.

image 

Now that we can set and get the date of the jQuery UI Datepicker widget we can start using it in our tests. And it offers a create place to add more functionality.

To conclude

I hope this post will help you start creating controls for your own or third party controls. There is much more that you can do so check out the download with this post to see:

  • How to restrict the use of this control to input elements which are a datepicker.
  • How to handle Date = null and reading a null date.
  • How to read options set on a datepicker widget instance.

There is also a WatiN-Contrib project started on Google code. So if you like to share your third party WatiN control library, let us know.

Enjoy testing with WatiN!

Technorati Tags:

zondag 6 december 2009

Using WatiN to parse and scrape HTML

Of course you can scrape web pages with WatiN so why this blog post you might ask. Well, with the out-of-the-box WatiN browser support you need to instantiate a browser to get the HTML for a page and scrape it. If you don’t need to interact with the page, like clicking on links, type in some text or rely on cookies for session state, you don’t need all the overhead (memory, start up time) of the browser.

This article will show you how you can use WatiN browserless by implementing a new browser: MsHtmlBrowser, using techniques described in this article.

For this code I use the current development code which will soon be released as WatiN 2.0 RC. You can download the code for this post here.

Load a url with HTMLDocumentClass

The trick to make this work is to make use of IPersistStreamInit and HTMLDocumentClass.

First lets get the definition of IPersistStreamInit in place:

image

And this is how we can combine it with the HTMLDocumentClass (don’t forget to add a reference to the assembly Microsoft.mshtml.dll distributed with WatiN):

image

Using multi browser support in WatiN 2.0

Knowing this we now need to give this code a place in the WatiN architecture. With the introduction of multi browser support in WatiN 2.0, the architecture of the WatiN API has been changed to allow adding new implementations for different browsers without having to change the WatiN.Core code. To create a new Browser implementation we need to create concrete implementations for the INative* interfaces specific for the browser we are adding. Since we are basing our new browser implementation on the same mshtml dll that Internet Explorer uses, we can reuse a lot of the IE specific native classes already available in the WatiN.Core.Native.InternetExplorer namespace.

But since we don’t want to use WatiN.Core.IE and need to use WatiN.Core.Browser to tap into the WatiN architecture, we need to create our own browser class. Lets call it MsHtmlBrowser (inheriting the abstract class Browser). This forces us to implement 2 abstract methods (WaitForComplete and Close) and 1 abstract property (NativeBrowser). Lets focus on implementing the NativeBrowser property.

Implementing MsHtmlNativeBrowser

NativeBrowser returns a type implementing INativeBrowser. So lets create a class MsHtmlNativeBrowser which implements INativeBrowser. This requires several methods and properties to be implemented. Many of these we can’t provide an implementation for since we aren’t wrapping a real browser. Two of these we need to focus on NavigateTo(url) and the property NativeDocument.

As you might guess, we can add our code (to load a page in an HtmlDocumentClass instance) to the NavigateTo method. After initialization of the object we wrap it into an IEDocument which will be returned by the NativeDocument property. Following the implementation. All the other methods do throw a NotImplementedException.

image

Back to implementing MshHtmlBrowser.

MsHtmlBrowser continued

Now that we have MsHtmlNativeBrowser, we can return an instance of this class in the NativeBrowser property of MsHtmlBrowser.

The implementation of the Close method is empty since we don’t have a real browser we need to close. You might consider disposing the instance of MsHtmlNativeBrowser here.

For the WaitForComplete method we can reuse functionality in the IEWaitForComplete class by passing in the IEDocument instance of the MsHtmlNativeBrowser.

This results in the following implementation:

image 

 

Using the new MsHtmlBrowser

image

Which concludes this example on creating a browserless Browser implementation.

Enjoy testing with WatiN!

Technorati Tags: