Tag Archives: webdriver

C# WebDriver extension: Driver.TakeScreenshot

I was having a chat to a colleague this week about how Watir in Ruby is much nicer than WebDriver in other languages because it provides a lot more functionality without any work, such as screenshots, waiting etc. I hadn’t really thought about that for a while because, despite working predominantly in C#, I have a collection of WebDriver and WebElement extensions I have written which make it much easier to use.

I plan to write a series of short posts sharing a different extension method in each one.

I previously shared these:

  • IWebElement.Set(text)
  • SelectElement.SelectBySubText(subText)
  • IWebElement.FindVisibleElement(by)
  • IWebElement.VisibleElementExists(by)

Today I will share IWebDriver.TakeScreenshot(prefix). This method allows you to easily take a timestamped screenshot of what is displayed in the browser with an optional prefix to the filename.

using System;
using System.Drawing.Imaging;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace WebDriverExtensions
    public static class WebElementExtensions
        public static string TakeScreenshot(this IWebDriver driver, string prefix)
            var fileName = String.Format("{0}{1}{2}", prefix, DateTime.Now.ToString("HHmmss"), ".png");
            var screenShot = ((ITakesScreenshot)driver).GetScreenshot();
            screenShot.SaveAsFile(fileName, ImageFormat.Png);
            return fileName;

    public class ExtensionUnitTests
        public void TakeScreenShot()
            var driver = new FirefoxDriver();
            driver.Navigate().GoToUrl("data:text/html,Some Text");
            var fileName = driver.TakeScreenshot("myScreenShot");

Using appium in Ruby for iOS automated functional testing

As previously explained, I recently started on an iOS project and have spent a bit of time comparing iOS automation tools and chose Appium as the superior tool.

The things I really like about Appium is that it is language/framework agnostic as it uses the WebDriver standard WIRE protocol, it doesn’t require any modifications to your app, supports testing web views (also known as hybrid apps) and it supports Android since we are concurrently developing an Android application (it also supports OSX and Firefox OS but we aren’t developing for those, yet). There isn’t another iOS automated testing tool, that I know of, that ticks that many boxes for me.

Getting Started

The first thing to do is download the appium.app package from the appium website. I had an issue with the latest version (0.11.2) launching the server which can be resolved by opening the preferences and checking “Override existing sessions”.

You run the server from inside the appium.app which takes your commands and relays them to the iOS simulator. There’s also a very neat ‘inspector’ tool which shows you all the information you need to know about your app and how to identify elements.

Note: there’s currently a problem with XCode 5.0.1 (the latest version as I write) which means Instruments/UIAutomation won’t work at all. You’ll need to downgrade (uninstall/reinstall) to XCode 5.0 to get appium to work at all.

Two Ruby Approaches

This confused me a little to start, but there’s actually two vastly different ways to use appium in ruby.

1) Use the standard selenium-webdriver gem

If you’re used to using WebDriver, like me, this will be the most straightforward approach (this is the approach I have taken). Appium extends the API to add different gestures by calling execute_script from the driver, so all other commands stay the same (for example, find_element).

2) Use the appium_lib library

There is a Ruby gem appium_lib that has a different API to the selenium-webdriver gem to control appium. I don’t see any massive benefits to this approach besides having an API that is more specific to app testing.

Using Selenium-WebDriver to start appium in ruby

Launching an appium app is as simple as defining some capabilities with a path to your .app file you have generated using XCode (this gets put into a deep folder so you can write the location to a file and read it from that file).

capabilities = {
'browserName' => 'iOS',
'platform' => 'Mac',
'version' => '6.1',
'app' => appPath
driver = Selenium::WebDriver.for :remote,
desired_capabilities: capabilities,
url: ""

Locating elements

Once you’ve launched your app, you’ll be able to use the appium inspector to see element attributes you can use in appium. Name is a common attribute, and if you find that it’s not being shown, you can add a property AccessibilityIdentifier in your Objective C view code which will flow throw to appium. This makes for much more robust tests than relying on labels or xpath expressions.

driver.find_element(:name, "ourMap").displayed?

Enabling location services for appium testing

This got me stuck for a while as there’s quite a bit of conflicting information about appium on how to handle the location services dialog. Whilst you should be able to interact with it as a normal dialog in the latest version of appium, I would rather not see it at all, so I wrote a method to copy a plist file with location services enabled in it to the simulator at the beginning of the test run. It’s quite simple (you can manually copy the clients.plist after manually enabling location services):

def copy_location_services_authentication_to_sim
source = "#{File.expand_path(File.dirname(__FILE__))}/clients.plist"
destination = "#{File.expand_path('~')}/Library/Application Support/iPhone Simulator/7.0/Library/Caches/locationd"
FileUtils.cp_r(source, destination, :remove_destination => true)

Waiting during appium tests

This is exactly the same as selenium-webdriver. There’s an implicit wait, or you can explicitly wait like such:

driver.manage.timeouts.implicit_wait = 10
wait = Selenium::WebDriver::Wait.new :timeout => 30
wait.until {driver.find_element(:name, 'monkeys').displayed? }

Mobile gestures

The obvious difference between a desktop web browser and a mobile app is gestures. Appium adds gestures to WebDriver using execute_script. I recommend using the percentage method (0.5 etc) instead of pixel method as it is more resilient to UI change.

For example:

driver.execute_script 'mobile: tap', :x => 0.5, :y => 0.5


b = driver.find_element :name, 'Sign In'
driver.execute_script 'mobile: tap', :element => b.ref

Testing Embedded Web Views

The native and web views seamlessly combine so you can use the same find_element method to find either. The appium.app inspector displays the appropriate attributes.

Note: I can’t seem to be able to execute a gesture (eg. swipe) over a Web View. I don’t know whether this is a bug or a limitation of Appium.


I have found that using the familiar selenium-webdriver gem with appium has been very powerful and efficient. Being able to open an interactive prompt (pry or irb) and explore your app using the selenium-webdriver library and the appium.app inspector is very powerful as you can script on the fly. Whilst appium still seems relatively immature, it seems a very promising approach to iOS automation.

Now to get watir-webdriver to work with appium.

Writing your own WebDriver selectors in C#

I am working on a C# project at the moment, writing tests using WebDriver, and one of the things I miss most about Watir-WebDriver is its variety of selectors, for example, being able to specify a value for value. Since the application I am testing uses value a huge amount, I started using a css selector for each element I was interacting with:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("data:text/html,<div value=\"Home\">Home</div>");
var divByCss = driver.FindElement(By.CssSelector("[value=\"Home\"]"));

But I got sick of typing out this fairly unattractive CSS selector each time I came across a new element.

I wanted to write an extension method so that I can use something like By.Value(“Home”) instead of By.CssSelector(…) but soon realized that you can’t write extension methods for static classes in C#, as you need an instance of the class to extend.

So, instead of extending the original By class, I wrote my own custom MyBy class that I can use in addition to the original.

namespace WebDriverExtensions
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using OpenQA.Selenium;
  using OpenQA.Selenium.Firefox;

  public static class MyBy
    public static By Value(string text)
      return By.CssSelector("[value=\"" + text + "\"]");

  public class WebElementExtensionTests
    public void ByValue()
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,<div value=\"Home\">Home</div>");
      var divByValue = driver.FindElement(MyBy.Value("Home"));
      var divByCss = driver.FindElement(By.CssSelector("[value=\"Home\"]"));
      Assert.AreEqual(divByCss, divByValue);
      Assert.AreEqual("Home", divByValue.Text);
      Assert.AreEqual("Home", divByValue.GetAttribute("value"));

I think this solves the problem fairly nicely. Do you do something similar? Is there a better way?

Watir-WebDriver tests on Firefox 7: getting rid of the send data to Mozilla message

Update 6 October 2011: The send data to Mozilla question will be turned off by default in the next release (2.8.0) of the selenium-webdriver gem which watir-webdriver uses.

I’ve been running Watir-WebDriver tests against Firefox 7, which works superbly. The biggest change is Firefox 7 now supports performance metrics, so this means you can use the watir-webdriver-peformance gem: yay! It also means my EtsyWatirWebDriver project now collects page metrics using Firefox.

The only slight annoyance is the presence of the ‘send data to Mozilla?’ dialog bar. Never fear, it’s easily dismissed.

require 'watir-webdriver'
profile = Selenium::WebDriver::Firefox::Profile.new
profile['toolkit.telemetry.prompted'] = true
b = Watir::Browser.new :firefox, :profile => profile


Send data to mozilla

C#: Avoiding the WebDriverException: No response from server for url

When it comes to automated testing, there’s not much worse than intermittent failures, especially when they stem from the driver itself. The current version of the C# WebDriver bindings has such a failure, but I worked out a reasonable way to avoid it happening. Basically it involves creating a WebDriver extension method that I use instead of Driver.FindElement, which tries a number of times to find the element, ignoring the exception that is intermittently raised.

I hope you find this useful if you’re consuming WebDriver in C#.

using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
namespace Extensions
    public static class WebDriverExtensions
        public static SelectElement GetSelectElement(this IWebDriver driver, By by)
            return new SelectElement(driver.GetElement(by));
        public static IWebElement GetElement(this IWebDriver driver, By by)
            for (int i = 1; i <= 5; i++ )
                    return driver.FindElement(by);
                catch (Exception e)
                    Console.WriteLine("Exception was raised on locating element: " + e.Message);
            throw new ElementNotVisibleException(by.ToString());

Using the super-duper ChromeDriver with Watir-WebDriver (updated)

Anyone who has used Watir-WebDriver (or WebDriver for that matter) to test Google Chrome will know that it’s been pretty unreliable, and pretty much unusable in the past… until now.

The ChromeDriver executable was released recently which enables WebDriver to control Google Chrome natively using the Wire protocol. This means your Watir-WebDriver tests will run super fast, and super reliably.

For Mac OSX:

  1. Get the latest Watir-WebDriver gem
    gem update watir-webdriver
  2. Download the ChromeDriver binary from the Chromium site, and copy it to your path (such as /usr/local/bin/)
  3. This will work with any current version of Chrome
  4. Change your Watir-WebDriver script to use Watir::Browser.new :chrome and voila, super fast Chrome, with no weird first tab opened in the background. This is the key to tell if you’re doing it right, your app should appear in the first tab of Chrome, not the second.

I haven’t done this on Windows yet, so your mileage may vary, but I imagine it wouldn’t be too different.

SpecDriver now includes Etsy.com examples

A fellow ThoughtWorker, Paul Hammant, recently announced his intent for QuickTest Professional. And his method? Provide some new technology tutorials for newbies, in the form of a series of open source automated tests for craft site Etsy.com.

He asked me to assist by providing some SpecDriver examples, and since I enjoy doing this stuff I am more than happy to help out.

So, I’ve updated the SpecDriver repository on Github to include some Etsy.com feature files, and working tests. It was a lot of fun to write these tests, because Etsy.com is awesomely testable. Its nicely formatted code with proper ids and class names makes automating against it a real treat.

The benefit of doing this exercise is that it’s meaty enough for me to get some insight into how other people code real automated tests. For example, I’ve had a look into a couple of the code samples and I see a lot of XPath selectors. I personally really dislike XPath stuff, just like I dislike XML as I find it hard to read, and less intuitive than using straight identifiers. I am proud that there isn’t a single XPath used in my Etsy.com examples.

Another thing that stood out to me was how embedded some of the stories are. For example, in the JBehave example the features are located under //etsy-stories/src/main/resources/stories, which took me some time to locate at first, and every time I forget where they are. I much prefer having a features folder in root that makes it pretty obvious what’s in there.

One thing I am very interested in is seeing how people specify tests. I found two of Paul’s scenarios repetitious so I moved them into a single scenario outline. Moving them into a scenario outline made me think about some different ways to test, so I added a new scenario, which didn’t require much more code, but strengthened my feature.

For example, Paul’s two scenarios:

Scenario: Advanced Search for a hat
  Given I am searching on Etsy.com
  When I specify the Knitting sub category
  And I search for hat
  Then there are search results

Scenario: Advanced Search for a ring
  Given I am searching on Etsy.com
  When I specify the Jewelry sub category
  And I search for ring
  Then there are search results

became my:

Scenario Outline: Advanced Search for items in various categories that exist and don't exist
  Given I am searching on Etsy.com
    When I specify the <Sub Category> sub category
    And I search for <Search Term>
    Then I should see <Search Results> search results for <Search Term> 

  | Sub Category | Search Term  | Search Results |
  | Knitting     | 'hat'        | some           |
  | Jewelry      | 'necklace'   | some           |
  | Jewelry      | 'specdriver' | no             | 

While I was at it, I noticed there was a spelling correction feature of the advanced search. I also thought it was a good idea to test that this was working correctly.

Scenario: Misspelling a word corrects search automatically
  Given I am searching on Etsy.com
  When I specify the Knitting sub category
  And I search for 'scalf'
  Then I should see some search results for 'scarf'
  And I should see that the search was for 'scarf' instead of 'scalf'

Now I’ve done this exercise using SpecFlow and WebDriver in C#, I’m keen to do it again using Cucumber & Watir (WebDriver) in Ruby, to compare the implementation. When I am done I will post it on here for you all to see. Enjoy.

SpecDriver: A simple, open-source, page object model framework for C# automated web testing

There doesn’t seem to be a lot of material available in the C# .NET automated testing space, so I thought I would create and share my own page object model centered framework: SpecDriver.

It uses SpecFlow to define features, scenarios and steps, and then WebDriver to actually drive the browser to automate these steps, with a page object model in between to ensure maximum maintainability of the solution.

I have previously documented the steps to getting SpecFlow up and running with Visual Studio C# Express which is free to use for both commercial and non-commercial reasons. You should follow these if you would like to play around with SpecDriver.

You can access all the source code on the github repository, and please feel free to fork/improve it as you see fit.

I will explain the various elements here and how they fit together.

Feature Files for Test Specifications

SpecFlow uses .feature files exactly the same as Cucumber, so it’s pretty easy to create these. I actually used my feature files from my Cucumber framework for this example; the benefits of writing these in a non-technical style!

Feature: Google Search
  As a casual internet user
  I want to find some information about watir, and do a quick conversion
  So that I can be knowledgeable being

Scenario: Search for Watir
  Given I am on the Google Home Page
  When I search for "Watir"
  Then I should see at least 100,000 results

Scenario: Do a unit conversion
  Given I am on the Google Home Page
  When I convert 10 cm to inches
  Then I should see the conversion result "10 centimetres = 3.93700787 inches"

Scenario: Do a search using data specified externally
  Given I am on the Google Home Page
  When I search for a ridiculously small number of results
  Then I should see at most 100 results

Step Definitions that call page objects

The step definitions are small, granular methods that call methods on page objects and do assertions against expected results.

namespace Project1.StepDefinitions
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using TechTalk.SpecFlow;
    using NUnit.Framework;
    using Project1.Pages;

    public class GoogleSearchStepDefinitions : BaseStepDefinitions

        [Given(@"I am on the Google Home Page")]
        public void GivenIAmOnTheGoogleHomePage()
            GoogleHomePage = new GoogleHomePageModel(Driver);
            Assert.AreEqual("Google", GoogleHomePage.Title);

        [When(@"I search for ""(.+)""")]
        public void WhenISearchForSomething(string searchTerm)
            GoogleSearchResultsPage = GoogleHomePage.Search(searchTerm);

        [When(@"I search for a ridiculously small number of results")]
        public void WhenISearchForARidiculouslySmallNumberOfResults()
            GoogleSearchResultsPage = GoogleHomePage.Search("macrocryoglobulinemia marvel");

        [When(@"I convert (.+)")]
        public void WhenIConvertSomething(string ConversionString)
            GoogleSearchResultsPage = GoogleHomePage.Search("convert " + ConversionString);

        [Then(@"I should see at most ([\d,]+) results")]
        public void ThenIShouldSeeAtMostNumberOfResults(string expMaxNumberResults)
            expMaxNumberResults = expMaxNumberResults.Replace(",", "");
            Assert.LessOrEqual(Convert.ToInt32(GoogleSearchResultsPage.NumberOfResults), Convert.ToInt32(expMaxNumberResults));

        [Then(@"I should see at least ([\d,]+) results")]
        public void ThenIShouldSeeAtLeastNumberOfResults(string expMinNumberResults)
            expMinNumberResults = expMinNumberResults.Replace(",", "");
            Assert.GreaterOrEqual(Convert.ToInt32(GoogleSearchResultsPage.NumberOfResults), Convert.ToInt32(expMinNumberResults));

        [Then(@"I should see the conversion result ""(.+)""")]
        public void ThenIShouldSeeTheConversionResult(string expectedConversionResult)
            Assert.AreEqual(expectedConversionResult, GoogleSearchResultsPage.ConversionResult);

Page Object Model

Each page in the application under test is represented by a page class (that inherits from a base page class), and this page class has elements and methods associated with it. The pages are the things that actually use WebDriver to interact with browsers. You can see, like my ruby page object pattern, methods that change pages return an instance of that new page. The other thing to note is that there is a base page class that has a constructor, that requires an known element to instantiate the page. This is a way of knowing where you are in your application and constantly checking it is in the right place. This also ensures consistent syncronization, especially when pages contain dynamic content such as AJAX calls.

namespace Project1.Pages
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using OpenQA.Selenium;

    public class GoogleHomePageModel : BasePageModel
        private static readonly By SearchEditSelector = By.Name("q");
        private static readonly By SearchButtonSelector = By.Name("btnG");

        public GoogleHomePageModel(IWebDriver driver)
            : base(driver, SearchEditSelector)

        private IWebElement SearchEditElement
             get { return Driver.FindElement(SearchEditSelector); }

        private IWebElement SearchButtonElement
            get { return Driver.FindElement(SearchButtonSelector); }

        public GoogleSearchResultsPageModel Search(string term)
            return new GoogleSearchResultsPageModel(Driver);

Putting it all together

I have two batch files that I use in Visual Studio 2010 C# Express, one to generate the SpecFlow NUnit tests, the other to execute them and provide a visual report. I add these as external tools in VS2010 and run them from the menu. Neat.

C# ATDD on a shoestring (or the complete guide to SpecFlow & NUnit in Visual Studio 2010 Express)


When I’m working on something new at work, I like to be able to work on it in my own time at nights and on the weekend to polish my skills through experimentation, and share what I learn. I’ve recently been working on setting up Acceptance Test Driven Development in C# at work, but unfortunately Microsoft makes it really, really hard to polish your skills in C# development at home, unless you’re willing to part with large sums of cash (say from $20,775, and I’d prefer a new car). This is probably one of the reasons why I find the Microsoft .NET testing community (and the dev community too) quite insular, Microsoft just doesn’t encourage their users to share their craft.

Sure, Microsoft provides Visual Studio 2010 (VS2010) Express Edition – which can be used free of charge, even for commercial purposes, but the limitations on its functionality are borderline ridiculous. For example, it doesn’t support Microsoft’s own unit testing framework (Microsoft obviously don’t encourage TDD), and all add-ins are banned (no ReSharper for you). It also doesn’t work with Microsoft’s own version control system (TFS).

So, Microsoft it basically makes it really hard to do anything you want to do, but there are ways to get stuff done, even if they’re convoluted.

ATDD Frameworks in C#

I know of three main open source ATDD/BDD frameworks that work in C#: SpecFlow, Cuke4Nuke and StoryQ. Only two of these use Gherkin (StoryQ uses its own slightly modified DSL), and I like Gherkin, so I’ll ignore StoryQ for now. Cuke4Nuke still requires some Ruby glue, and to keep things pure, I like SpecFlow as it’s a pure .NET implementation of ATDD with full Gherkin syntax support. For this reason, SpecFlow seems to be the most prevalent ATDD framework in the .NET community and this is what I will use for this example.

SpecFlow as an Acceptance Test Driven Development Framework

SpecFlow is an open source framework that is delivered as a Windows installer, and this installs support for feature and step definition files in Visual Studio through an Add-In that automatically generates unit tests for you from the feature files. Unfortunately, as VS2010 Express doesn’t allow add-ins, SpecFlow won’t work without some tinkering.

Install SpecFlow & NUnit

Before we get started, we need to install VS2010 Express, SpecFlow and NUnit.

  1. Install VS2010 C# Express if you don’t already have it
  2. Install the latest SpecFlow version from the SpecFlow GitHub downloads page.
  3. Install the latest NUnit version from the NUnit download page.
  4. Add the Specflow directory (C:\Program Files\TechTalk\SpecFlow or similar) and the NUnit directory (C:\Program Files\NUnit 2.5.9\bin\net-2.0 or similar) to your Windows path.

Adding SpecFlow templates to Visual Studio 2010 Express

When installing SpecFlow to VS2010 (non-express) it creates templates that can be accessed through the “New Item” menu. Fortunately, it is fairly trivial to add these to VS2010 Express. Just download the templates I have uploaded here (2010, or here (2012) unzip this directory and place the .zip files (SpecFlowFeature.zip, SpecFlowStepDefinition.zip etc.) into your Visual Studio 2010 Express C# templates directory (usually: C:\Users\username\Documents\Visual Studio 2010\Templates\ItemTemplates\Visual C# or similar).

This means you now have access to the SpecFlow templates when adding a new item to your C# project.

Generating SpecFlow NUnit tests from Feature Files

When you add a SpecFlow feature to the full version of VS2010, it automatically generates a unit test file behind the feature file, so that it’s always up to date. This doesn’t work in Express edition, so you have to use the specflow.exe file to do this for you. Fortunately, this can be done in a batch file, and then added as an “external tool” to VS2010 Express, so you get the same functionality, but not quite as neat.

  1. Enable Expert Settings in VS2010 Express (if not already enabled), by choosing Tools->Settings->Expert Settings.
  2. Create a batch file in your project directory called something like “generatespecflowtests.bat” with the following content:

echo Starting to generate SpecFlow unit tests
SpecFlow generateAll %1 /force /verbose
echo Finished generating SpecFlow unit tests
  1. Add an external tool command in VS2010 Express, using Tools->External Tools->Add. Make sure you set the starting directory, and “show output”

  1. You can then generate your tests from the Tools menu or, if you like, you can add this command to a new Toolbar by using Tools -> Customize -> Toolbars -> New, then Tools -> Customize -> Commands -> Toolbar -> Add Command.

Running SpecFlow NUnit tests from Feature Files

Simon Whittemore from London wrote an excellent post about how to automatically run Specflow NUnit tests, and capture a pretty html result, on his blog. I’ve included his batch file here, as it’s what we’ll use to run our tests from within VS2010 Express.

  1. Create a batch file in your project directory named runspecflowtests.bat or similar.
  2. Include Simon’s content (below) in your batch file.
@echo off
nunit-console %1
specflow.exe nunitexecutionreport %2 /xmlTestResult:%3
if NOT %errorlevel% == 0 (
echo "Error generating report - %errorlevel%"
GOTO :exit
if %errorlevel% ==0 TestResult.html
  1. Create an external tool setting the same as we did for the generate unit tests, but with the parameters defined on this dialog:
    1. Command: Link to your batch file
    2. Arguments: $(TargetName)$(TargetExt)$(ProjectDir)$(ProjectFileName)$(BinDir)TestResult.xml
    3. Initial Directory: $(BinDir)
    4. Use Output Window: checked

  1. Optionally add this to your VS2010 Express Toolbar as above

When you run this command in VS2010, all SpecFlow features are run, and the resulting report is launched in your default web browser.


What I have shown is that although Microsoft makes it very hard, it is possible to use VS2010 Express and open source tools like SpecFlow so that you can polish your skills in your own time.

In this theme of ATDD using C# and .NET, over the coming days I will demonstrate how you can use SpecFlow to write and run automated web tests against a web browser using the open source tool WebDriver. Stay tuned!

Update: 20 Feb 2011

The original link to the templates was wrong, I have now updated it to the correct link.

Update 29 Sep 2013

Yannick de Kercadio has kindly provided VS2012 templates here.


Watir Day is happening in San Francisco on Sunday April 3rd 2011

Just to let everyone know Watir day is happening in San Francisco on Sunday April 3rd, 2011. It’s the day before the Selenium Conference officially starts, to which most of the core Watir team will be attending.

I am hoping to share some of the stuff I have been doing with Watir, Watir-WebDriver, Selenium & Cucumber.

We’re hoping the Watir day will be less formal than the conference, and this includes hacking, so please bring along your laptop.

Hope to meet you there! http://watir.com/watir-day/