WATIR for .NET - WatiN approaches 0.8 release and automating IE from PowerShell
I'm a big fan of WATIR (pronounced "Water"). However many folks have said they wish they could have a similar tool in .NET. WatiN may be that tool. Looks like they'll be releasing 0.8.0 around September 1st with these changes:
- An even more Watir like syntax to access an element. There's no need anymore to use MainDocument to access, for example, a TextField. You will now write code like:
ie.TextField("textfieldid).Text - Support for finding matching element attribute values by using regular expressions.
- Out of the box support for finding images by their Src attribute (no need to create your own AttributeValue class for this anymore).
- Updated documentation.
Looks like a pretty nice, pretty clean implementation of an IE abstraction layer for .NET that will be getting even cleaner very soon.
Aside: Another great .NET-based IE Automator is Alex Furman's SWExplorerAutomation. Here's an example of integrating SWEA with NUnit.
Back on the Watir side, one of the coolest things about Watir is "putting IE on a string" from the Interactive RuBy shell, or IRB. Leon has a great 3 mins to Watir tutorial that uses the IRB with Watir to interactively poke around at a site. Many folks find this more useful and interesting than using a recorder tool.
For example, assuming you've installed Ruby with the Windows Ruby Installer, open up a cmd.exe prompt and run
gem install Watir
to get Watir. Then run IRB.exe (Interactive Ruby) and do this:
irb(main):001:0> require 'watir'
irb(main):002:0> include Watir
irb(main):003:0> ie = Watir::IE.new
irb(main):004:0> ie.goto("http://google.com")
irb(main):005:0> ie.text_field(:name, "q").set("Scott Hanselman")
irb(main):006:0> ie.button(:name, "btnG").click
And that's interactive Watir, right? Yay.
So, if I take a look at this WatiN (pronounced WHAT'n as in What'n'tha'heck maybe?) using the only interactive .NET Shell I have available to me...could I do Watir/IRB style interactive work using PowerShell?
PS[1] C:\WatiN-0.7.0.4000\bin
> [System.Reflection.Assembly]::LoadFile((get-item WatiN.Core.dll).FullName)GAC Version Location
--- ------- --------
False v1.1.4322 C:\WatiN-0.7.0...PS[2] C:\WatiN-0.7.0.4000\bin
> $ie = new-object WatiN.Core.IE("http://www.google.com")
New-Object : Exception calling ".ctor" with "1" argument(s): "Could not load fi
le or assembly 'Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyTok
en=null' or one of its dependencies. The system cannot find the file specified.
"
At line:1 char:17
+ $ie = new-object <<<< WatiN.Core.IE("http://www.google.com")
Looks like since he's using an unsigned IE interop assembly it can't load it from the current application directory. That's c:/Program Files/Windows PowerShell/v1.0/, not the current directory. At this point I have two choices. I can copy the unsigned intern assembly Interop.SHDocVw.dll to the PowerShell folder, or I can rebuild the project against a Signed Primary Interop Assembly for IE. I'll copy it over for now.
PS[1] C:\WatiN-0.7.0.4000\bin
> [System.Reflection.Assembly]::LoadFile((get-item WatiN.Core.dll).FullName)GAC Version Location
--- ------- --------
False v1.1.4322 C:\WatiN-0.7.0...PS[2] C:\WatiN-0.7.0.4000\bin
> $ie = new-object WatiN.Core.IE("http://www.google.com")
New-Object : Exception calling ".ctor" with "1" argument(s): "Specified cast is
not valid."
At line:1 char:17
+ $ie = new-object <<<< WatiN.Core.IE("http://www.google.com")
Yikes. Looks like folks are pissed off; so pissed off this forcibly closed PowerShell also.
Ok, so WatiN is doing something tricky that PowerShell doesn't like. Well, since PowerShell has its own concept of how .NET and COM should interact. Let's cut out the middle man (WatiN in this case) and go direct to IE from PowerShell .
PS[1]>$psie = new-object -com InternetExplorer.Application
PS[2]>$psie.Navigate("http://www.google.com")
PS[3]>$q = ($psie.Document.GetElementsByTagname("input") | where { $_.Name -eq "q" } #get the input box called "q"
PS[4]>$q.value = "Scott Hanselman"
PS[5]>$search = $psie.Document.GetElementsByTagname("input") | where { $_.Name -eq "btnG" }
PS[6]>$search.click()
Gross, not easy, but shows potential. You know, a weekend, some UpdateType-Data action and a few functions and one could get a WatiPSH (!?) prototype running that would be very PowerShelly...I wonder if the PowerShell type extension stuff works as nicely with COM objects...
If the WatiN team considers PowerShell in their use cases, their abstraction layer might make a suitable interface for PowerShell scripting. Or, perhaps a few well written PowerShell scripts could give Watir-like syntax on PowerShell. Either way, WatiN has the potential to be pretty useful, particularly within NUnit if you find the Watir NUnit Integration distasteful (some do, I don't, I started it).
For now, I'll stick with the simplicity and IJW of Watir, but I'm keeping my eye on WatiN.
Now playing: Stephen Lynch - Superhero
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
I'm the developer of WatiN. Thanks for mentioning WatiN on your weblog! Regarding the invalid cast exception, this has to do with the apartmentstate of the thread the (powershell) code is running on. To succesfully automate Internet Explorer (in this case with WatiN) the code should be running on a single threaded apartment Thread. As you already mentioned in the weblog, powershell needs a -com statement to interact with COM objects. I suspect using WatiN with powershell might need this/something special to. Following is a part of a post about apartmentstate to the watin-users mailing list. Maybe, with this info, you'll find a way to get WatiN working with powershell. In the 0.8.0 a more explicit exception is thrown which points out to the user (of watin) to set the aparmentstate of the currentthread to STA.
Regards,
Jeroen van Menen
>> START
** Why Is setting the ApartmentState needed in the first place?
Copied from MSDN (http://msdn2.microsoft.com/en-us/library/system.threading.apartmentstate.aspx):
“Because COM classes use apartments, the common language runtime needs to create and initialize an apartment when calling a COM object in a COM interop situation. A managed thread can create and enter a single-threaded apartment (STA) that allows only one thread, or a multithreaded apartment (MTA) that contains one or more threads.”.
Since Internet Explorer is not Thread safe we need to use STA.
** Differences in ApartmentState between .Net 1.1 and .Net 2.0
Digging through MSDN I found out that Microsoft not only has changed the calling convention for setting or getting the ApartmentState, it also changed the default ApartmentState for a Thread in .Net 2.0.
In .Net 1.1 the default ApartmentState of a Thread is Unknown. A running Thread with this ApartmentState can be set to STA or MTA, but only once. Trying to set the Apartment state of a running Thread from MTA to STA (or vice versa) doesn’t have any effect, it remains MTA (or STA).
In .Net 2.0 the default ApartmentState of a Thread is MTA. Trying to reset the ApartmentState of a running Thread from MTA to STA (or vice versa) doesn’t have any effect, it remains MTA. Setting the ApartmentState to Unknown or STA instead of MTA, can ONLY be done BEFORE the Thread starts.
** Implications
As you already mentioned in a previous mail. Using WatiN works fine in a console or GUI application when you apply the [STAThread] attribute to the main methode (the sole entry point of the application). This way the main Thread runs as STA and all goes well. When using a runner like MBUnit, NUnit or any other runner that starts the main Thread, your code/tests depend upon the ApartmentState the runner started with.
My biggest question, I am struggling to find a winform unittester that can be embeded in cruisecontrol.net. I have tried to use NUnitAsp & SharpRobo. I have not had any luck with either under .net Framework 2.0 on our smart client / winforms project. I attempted to contact the principle owners with no luck. Any thoughts?
Testing for asp.net controls using IE (based on nunitasp and ietest).
I finally started looking at Watir and I like it. So I decided to look at WatirRecorder++ and like what it does.
Had a look at the codeplex project for it and managed to download the text file in a zip :)
Do you know when you might have the code on there? I'd like to see what is going on inside it and poke around a bit.
Thanks.
I have built a WATiN web recorder application based on the WebRecorder++. You can download it from the blog post. I would like to upload my fixes to the web recorder++ and start a new branch for the WATiN web recorder in source forge if you are interested. The application is stable but there are still some bugs that I would like to get fixed up, some design changes to the code and some new functionality to the app.
Enjoy
Rich.
http://blogs.conchango.com/richardgriffin/default.aspx
Comments are closed.
http://qainsight.net/2006/02/19/Automating+Web+UI+Testing+With+SWEA+C+Amp+NUnit+Part+3.aspx
and
http://www.testingreflections.com/node/view/2763