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++ )
            {
                try
                {
                    return driver.FindElement(by);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception was raised on locating element: " + e.Message);
                }
            }
            throw new ElementNotVisibleException(by.ToString());
        }
    }
}

Watir-Page-Helper 0.3.0: now with added frames

I’ve just release version 0.3.0 of my watir-page-helper gem, with support for frames.

To use a frame, you define it as you would any other element:

class PageIFrame < BasePageClass
  direct_url TEST_URL
  frame :iframe, :id => "myiframe"
  link(:ilink) { |page|  page.iframe.link(:text => 'Link in an iFrame') }
end

and then you can use the frame, or any elements within that frame:

it "should support elements within a iframe" do
  page = PageIFrame.new @browser, true
  page.iframe.exist?.should be_true
  page.ilink_link.exist?.should be_true
  page.ilink
end

I hope you find this update useful.

Visible content locators and i18n in automated tests

I recently read a rebuttal to my post about death to xpath selectors, which raises a point of not using user visible strings in/as selectors to identify elements. The reasoning is that if the time comes to internationalize your site, then your selectors will be brittle as they’re written in a specific language.

Fair point, but if you’re not testing the location of user visible content, then what are you testing? In Australia, I have found it rare (like one project out of about thirty I’ve worked on) that additional languages are supported. But on that one project I used visible user strings to locate objects that weren’t brittle whatsoever. But how? Adam says you can’t do it!

Well, I translate my locators too. That way I am testing both the functionality of the site, the content of the site, and the internationalized content of the site, all at once! No hands.

So how would I do it for my said poor example I used previously?

I’d wrap any selector with something like translate

  @browser.link(:text => translate('Buy')).click

and have a translate method defined in a mix-in:

def translate phrase
  #translate some phrase here using same method as AUT
  phrase
end

Setting Firefox download.dir with watir-webdriver on Windows

I was recently unsuccessfully trying to set the Firefox download directory on Windows using a Watir-WebDriver/Selenium-WebDriver profile. Thanks to a comment on this blog, it turns out there is a bug whereby if your download path contains a \n or \r, then it reverts back to the default location.

So, a download path like “C:\new\raw” will fail without telling you why.

Fortunately, it’s now been fixed, but hasn’t been released, so in the meantime, you can double escape it

require 'watir-webdriver'
p = Selenium::WebDriver::Firefox::Profile.new
p['browser.download.dir'] = "C:\\\\new\\\\raw"
p['browser.download.folderList'] = 2
p['browser.helperApps.neverAsk.saveToDisk'] = "application/pdf"
b = Watir::Browser.new :firefox, :profile => p

Disabling native events when using Firefox with WebDriver

Imagine this, you’ve got a whole suite of regression tests (thousands of steps) written in Watir-WebDriver that you run on a corporate Windows XP SOE using Firefox.

The tests have been run numerous times and are running perfectly without any intermittent failures.

A new version of selenium-webdriver is released with promised bug fixes and stability improvements, so you update your selenium-webdriver gem to 2.6.0 and re-run your test suite.

Red light: half of the tests fail. The suite takes longer than ever to run. Oh my.

After some investigation, Jari Bakken points out that it’s Firefox native events related. This causes text field sets to take a long time if they include capital letters, and locating elements seems to often intermittently fail.

I add a config option to disable native events to my Firefox profile, and my tests run perfectly again. Phew!

So, if you’re using Windows and Firefox and come across any of these problems, include this code to disable native events when you start your browser.

profile = Selenium::WebDriver::Firefox::Profile.new
profile.native_events = false
Watir::Browser.new WEB_DRIVER, :profile => profile

Determining file MIME types to autosave using Firefox & Watir-WebDriver

Update: Jari Bakken points out you can do this on Mac/Linux with one terminal command:

curl -I http://dl.dropbox.com/u/18859962/temp.csv | grep Content-Type

Introduction

When using Firefox with Watir WebDriver, there’s a nifty trick to set certain file types to automatically download so it’s not necessary to deal with troublesome ‘save as’ dialog boxes.

The problem with it is that you need to explicitly tell Firefox which file types you want to automatically save. Whilst this seems like an easy idea in concept, in practice it’s a bit harder as the web site serving the file can affect the MIME type which Firefox uses to determine what to do.

I recently found a way to determine what MIME type Firefox uses for a particular file so that this can be automatically captured. Here’s how:

1) Navigate to the site in Firefox and click on the link to the file (here’s an example CSV file). This should display a dialog such as the one below, where you’ll want to click ‘Save File’ and ‘Do this automatically for files like this from now on’

2) What this does is create an entry in the Applications tab of the settings to always download the file. Unfortunately, this doesn’t show us the MIME type which is what we need to specify this in our Firefox WebDriver profile.

3) What we want to do is open a file in our Firefox profile called mimeTypes.rdf. To find your Firefox profile on your disk, first open the page ‘about:support’ in Firefox, and click the ‘Show in Finder’ or ‘Open Containing Folder’ button.

4) Then navigate into your profile directory and open mimeTypes.rdf in your favorite text editor. We simply need to find the MIME type we just added, which is my case is found by searching for ‘excel’. The following text is included:

 <RDF:Description RDF:about="urn:mimetype:text/csv"
                   NC:fileExtensions="csv"
                   NC:description="Microsoft Excel.app Document"
                   NC:value="text/csv"
                   NC:editable="true">
    <NC:handlerProp RDF:resource="urn:mimetype:handler:text/csv"/>
  </RDF:Description>

The thing we’re looking for is NC:value=”text/csv“. This is our MIME type.

5) Now we simply add this MIME type to our file types we want to automatically save. This is done when creating the Firefox Watir-WebDriver instance:

profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.folderList'] = 2 #custom location
profile['browser.download.dir'] = "#{Dir.pwd}/downloads"
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv"

Note: you can add multiple MIME types to this value in the same string separated by commas.

Summary

While it’s a fairly long winded process, this takes the guess work out of ensuring you automatically download files of certain types.

Running Watir-WebDriver tests on Travis CI: a distributed build system

I recently came across Travis CI, a distributed build system that has close links to Github. I’ve seen quite a few projects use it as a CI system, but none that run headless browser tests.

Leveraging off the work I had done recently setting up my own Jenkins server in the cloud to run headless Watir-WebDriver tests, I thought I would have a go at running my WatirMelonCucumber and EtsyWatirWebDriver headless browser tests using Travis CI.

What I didn’t realize is how easy it’d be. The only things I had to do was make sure my Gemfile included rake, and also make sure there was some file existance checking happening for some log files, and it pretty much ran straight away. Wow!

Caveat Emptor

This is pretty new territory, so there’s a few things to watch out for:

  • Every now and, Travis complains about not having Firefox installed. I am not sure why this happens, maybe something to do with the different agents in use;
  • The locale of the build agents seems to be German, so when running my Google tests, the page content is in German, so it fails because it can’t find my expected (English) results; and
  • I can’t seem to capture my test results html file nor screenshot pngs, so it’s a red/green only affair at the moment.

But still, neat distributed free headless CI!

Running your watir-webdriver tests in the cloud, for free!

  • What if you could run unlimited Watir WebDriver tests in the cloud? Check.
  • What if the Watir WebDriver tests would run automatically as soon as you pushed a change to github? Check.
  • What if you would have a full visual history of results with embedded screenshots on failure? Check.
  • What if all of this was free?* Checkmate.

I’ve spent a bit of time over the last week working out how to do this. Here are the basics of what you need to do:

And here’s the detailed instructions.

Set up an Amazon EC2 micro instance running Ubuntu.

  1. First you need to sign up for an Amazon AWS account. This means you’re eligible for a free-tier micro instance for a year.
  2. Once you have an account set up, you need to launch a new instance. I found a free tier eligible Ubuntu image (11.04 Natty 64 bit desktop) and launched that.
  3. You will also want to create an elastic IP and associate it to your instance so that if you reboot your machine, you will have the same IP address. This is done through the AWS console under Elastic IPs.
  4. While you’re here, you’ll want to edit your machine’s security group and open up port 22 for SSH, and 80 for HTTP.
  5. This gives you secure shell (SSH) access to this machine using the provided key, and user ‘ubuntu’:
    ssh -i your-key-name.pem ubuntu@your-ip-address
  6. Everything you will do to configure this machine will be through this SSH session, so polish up your unix command line skills!

Set up Jenkins on your machine

There is a useful page for installing Jenkins on Ubuntu.

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo aptitude update
sudo aptitude install jenkins

Make Jenkins available on port 80 so that you don’t need to specify port

Jenkins installs by default on port 80. Ubuntu won’t let applications run on port 80 unless they’re running as root, so it’s best to set up an Apache 2 proxy to port 80 to 8080.

sudo aptitude install apache2
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod vhost_alias
sudo a2dissite default

Then create a file called jenkins in /etc/apache2/sites-available


	ServerAdmin webmaster@localhost
	ServerName ci.company.com
	ServerAlias ci
	ProxyRequests Off
	
		Order deny,allow
		Allow from all
	
	ProxyPreserveHost on
	ProxyPass / http://localhost:8080/

Then run the following commands:

sudo a2ensite jenkins
sudo apache2ctl restart

Password Protect Jenkins

You should go to your Jenkins site (accessible directly at your instance’s IP address through a web browser), and create an account, and then configure the security of Jenkins.

Install Jenkins Plugins

You will need to install the following Jenkins plugins

  • Github: to integrate to Github SCM
  • Rake: to run ruby rake tasks that run Watir-WebDriver tests
  • Green balls: because blue balls are just plain wrong

Install RVM for the Jenkins user

First we’ll need to install git

sudo apt-get install git

Jenkins will need to be able to run ruby, so we’ll install RVM as the Jenkins user.

To run as the jenkins user, we’ll use the sudo command, with the -Hiu arguments to load the home directory and bash profile:

sudo -Hiu jenkins

Once we are user Jenkins, we’ll install RVM using Git.

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Now we need to work out what Ubuntu packages Ruby needs, which is easily done via RVM.

rvm notes

which gives me something like

For Ruby (MRI, Rubinius, & REE)  you should install the following OS dependencies:
/usr/bin/apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake

So, we can log-out as the Jenkins user (control-D) and install the following as ubuntu

sudo apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake

Once we’ve done this, we’ll want to run the following as the Jenkins user (
sudo -Hiu jenkins) to install Ruby 1.9.2.

rvm pkg install zlib
rvm install 1.9.2 --with-zlib-dir=$rvm_path/usr

Running headless Watir-WebDriver tests

I choose a desktop version of Ubuntu, so it’ll already have Firefox installed, but if you don’t, you can install it by:

sudo apt-get install firefox

To run our Watir WebDriver tests headlessly using the headless gem, we’ll need xvfb

sudo apt-get install xvfb

Configuring Jenkins to run tests via Rake

You add a new build in Jenkins where you can specify the github repository location.

As we’ve installed the rake plugin, we can configure a new Jenkins project to use an RVM ruby install (in my case ruby-1.9.2-p290@watirmelon-cucumber).

I simply set up a default task in rake, which runs all my cucumber tests. This generates a results.html file which is captured as an artifact, and also creates and captures junit xml results, which are used to show test summary information.I also capture any file created under the ‘screenshots’ directory.

Summary and Outcome

I have set up both my WatirMelonCucumber and EtsyWatirWebDriver projects on jenkins.watirmelon.com.

My Jenkins Dashboard looks something like this:

Please feel to leave a comment below and let me know what you think.

* Free for one year using an free tier EC2 micro instance

Running headless Watir-WebDriver tests using a real browser

I seem to get quite a few questions from people trying to use Watir-WebDriver in headless mode using a WebDriver server and HTMLUnit. It seems to me that it’s problematic, especially when your web app contains JavaScript (who’s app doesn’t?).

The problem stems from HTMLUnit’s JavaScript support. Whilst it does support JavaScript, myself and many others have found the JavsScript support to be pretty poor as it uses its own JavaScript engine (Rhino) that no other ‘real’ browser actually uses, which sorta raises a question: are you really testing your app’s JavaScript?

The other thing about HTMLUnit is the lack of screenshot capability, as it’s purely headless, there’s no way to capture a screenshot when something goes wrong, so you’ll find yourself re-running failed tests using a different browser, which may or may not reproduce your problem. Not ideal!

Finally, running WebDriver headless tests requires you to run a Selenium Server, which is additional overhead for your tests.

But why headless?

Whilst running automated browser tests in a headless form can speed things up, the main reason I see people wanting headless watir-webdriver support is so that tests can be run on headless Linux machines, for example, a Jenkins Server. I’ve found running tests in parallel speeds things up more than headless execution can, so it’s mainly headless server support most people are after.

Enter the headless gem.

The headless gem is a ruby wrapper for Xvfb that makes it super easy to run graphical applications (such as real web browsers) on a headless machine. This gem is perfect for running headless watir-webdriver tests using a real browser.

How? It’s simple.

require 'watir-webdriver'
require 'headless'
headless = Headless.new
headless.start
b = Watir::Browser.start 'www.google.com'
puts b.title
b.close
headless.destroy

You’ll need Xvfb installed, which is as easy as:

sudo apt-get install xvfb

Or if you’re using cucumber like me, you just need the following code in your env.rb file:

if ENV['HEADLESS']
  require 'headless'
  headless = Headless.new
  headless.start
  at_exit do
    headless.destroy
  end
end

This then means you can still launch and use Firefox (or Chrome) on a headless machine.

The best thing about it though is that Watir-WebDriver’s inbuilt screenshots still work perfectly, so it captures a screenshot of the actual page even though it has no display. How awesome is that!

Summary

The headless gem makes it super easy to run real browsers on headless servers. This way you get real JavaScript support without the need to run a Selenium server, and is perfect for running your tests as part of continous integration.

Stay tuned as I’ll be writing a post soon about how to use an EC2 instance to run your headless watir-webdriver tests in the cloud, for free!

Determining your host operating system using ruby

I found out this is how you programatically determine your host operating system using ruby:

require 'rbconfig'
RbConfig::CONFIG['host_os']

This came in handy when setting the automatic browser downloads for browsers on Windows, as the location needs to use backslashes on Windows instead of Ruby’s default forward-slashes:

require 'rbconfig'
download_directory = "#{Dir.pwd}/downloads"
download_directory.gsub!("/", "\\") if  RbConfig::CONFIG['host_os'] =~ /mswin|mingw/