Web Application Testing in Ruby
Web Application Testing in Ruby
Željko Filipin
Buy on Leanpub

About the Book

Web Application Testing in Ruby (with Selenium and friends) is a book on, well, web application testing in Ruby (Watir). It is not finished. We are working on it.

Book source code is at GitHub. You can discuss the book at Google Groups. More information about the book is available at filipin.eu/tag/watirbook.

The book is available as PDF, EPUB (iPad, iPhone, iPod) and MOBI (Kindle) file at leanpub.com/watirbook. HTML version of the book is at leanpub.com/watirbook/read. Suggested price is $9.99, but you can get the book for free! Click Buy the ebook now! button and move the You pay slider to the left hand side until the amount goes down to $0.00. Of course, you can move the slider to the right hand side and pay more for the book. All money goes to the Watir project.

Money that book readers have donated to the Watir project == $1,523.97 (Updated 2014-01-25. For more stats see stats page.)

Installation

Installation is not complicated, but unfortunately, it is not trivial either.

The tools that we will be using in the book are available on Windows, Mac and Linux, and each of them has several releases currently in use (or in case of Linux, both distributions and releases). Just the most recent releases of each operating system will be covered in the book.

Everything is tested using VirtualBox 4.3.6 virtual machines, except Mac OS, since it does not want to be virtualized. Host OS for VirtualBox is Mac OS X 10.9.1.

You will probably be bored to tears if you read all installation chapters. A lot of stuff is repeated. Read only the chapters you need.

Windows 8.1

You will need internet access if you want to follow examples. All examples are tested with Microsoft Windows 8.1 Pro. All browsers are English (US) version.

Windows 8.1 default desktop

Windows 8.1 default desktop

Ruby

You probably do not have Ruby installed. To make sure, open Command Prompt application and type ruby -v. If you are not familiar with Command Prompt, see Command-line interface chapter.

1 >ruby -v
2 'ruby' is not recognized as an internal or
3 external command, operable program or batch file.

If you get the same thing as I did, you do not have Ruby installed.

Download the latest Ruby 2.0 from rubyinstaller.org/downloads. At the moment it is Ruby 2.0.0-p353. Execute the file.

Ruby Installation

Ruby Installation

You can leave all settings at default values, except at the Installation Destination and Optional Tasks screen check Add Ruby executables to your PATH checkbox. Installation should take you just a few seconds.

Let’s check if Ruby is installed. You will have to open another command prompt, because the one you have opened does not see Ruby.

1 >ruby -v
2 ruby 2.0.0p353 (2013-11-22) [i386-mingw32]

Congratulations! You now have the latest and greatest Ruby!

RubyGems

Software written in Ruby is usually distributed as RubyGems (colloquial name is gem), Ruby package manager. Sometimes Ruby installations do not have the latest versions of RubyGems, so we will first update it. RubyGems is also a gem, (a bit recursive, right?) and we get it’s version with gem -v.

1 >gem -v
2 2.0.14

You should update it with gem update --system:

1 >gem update --system
2 (...)
3 RubyGems system software updated

selenium-webdriver

Let’s try selenium-webdriver gem.

1 >gem install selenium-webdriver --no-ri --no-rdoc
2 (...)
3 Successfully installed selenium-webdriver-2.38.0
4 (...)

Internet Explorer

Internet Explorer 11

Internet Explorer 11

Since Internet Explorer (tested with version 11) is already installed, we will start with it. We will be using IRB (Interactive Ruby Shell). If you are not familiar with it, see IRB chapter.

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for
 7 :internet_explorer
 8 Selenium::WebDriver::Error::WebDriverError: Unable
 9 to find standalone executable. Please download the
10 IEDriverServer from
11 http://code.google.com/p/selenium/downloads/list
12 and place the executable on your PATH.
13 (...)

Windows Firewall popup appeared letting me know that it has blocked Ruby.

Windows Firewall has blocked some features of this program

Windows Firewall has blocked some features of this program

For now just close the popup, let’s see how to fix the error message. Follow the instructions from the error message. Go to code.google.com/p/selenium/downloads/list and download 32-bit or 64-bit IEDriverServer. Extract the downloaded zip file (with mouse right click and then Extract All.., for example). Let’s find out what is on the PATH.

1 >PATH
2 PATH=C:\Windows\system32;C:\Windows;
3 C:\Windows\System32\Wbem;
4 C:\Windows\System32\WindowsPowerShell\v1.0\;
5 C:\Ruby200\bin

C:\Ruby200\bin (or where ever you have installed Ruby) looks like a good place to me. Move the IEDriverServer file there.

Let’ try again:

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for
 7 :internet_explorer
 8 Started InternetExplorerDriver server (32-bit)
 9 2.38.0.0
10 Listening on port 5555
11 => #<Selenium::WebDriver::Driver:0x5469141e
12 browser=:internet_explorer>
13 
14 > browser.get "http://watir.com"
15 => nil

Firefox

Firefox 26

Firefox 26

If it is not installed (tested with version 25.0.1), download it from mozilla.com/firefox.

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :firefox
 7 => #<Selenium::WebDriver::Driver:0xdc8ad4a
 8 browser=:firefox>
 9 
10 > browser.get "http://watir.com"
11 => ""

Chrome

Chrome 31

Chrome 31

If it is not installed (tested with version 31), download it from google.com/chrome.

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the chromedriver executable. Please
 9 download the server from
10 http://chromedriver.storage.googleapis.com/
11 index.html and place it somewhere on your PATH.
12 More info at
13 http://code.google.com/p/selenium/wiki/
14 ChromeDriver.
15 (...)

You have to download ChromeDriver. Unzip the file and put it in any folder that is in your PATH. If you do not know what is PATH, see Internet Explorer chapter. In short, move the file to Ruby folder, probably C:\Ruby200\bin.

Let’s try again:

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 Starting ChromeDriver (v2.7.236900) on port 9515
 8 => #<Selenium::WebDriver::Driver:0x..fc23f2ebe
 9 browser=:chrome>
10 
11 > browser.get "http://watir.com"
12 => nil

I got Windows Firewall popup again letting me know that it has blocked ChromeDriver. Just close it for now, I have no idea what to do with it.

Chromium

Chromium 34

Chromium 34

First make sure that you can drive Chrome. (See Chrome chapter.) Then download Chromium. (Tested with version 33.) Replace C:\chrome\chrome.exe with path to Chromium executable.

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > Selenium::WebDriver::Chrome.path =
 7 'C:\chrome\chrome.exe'
 8 => "C:\\chrome\\chrome.exe"
 9 
10 > browser = Selenium::WebDriver.for :chrome
11 Starting ChromeDriver (v2.7.236900) on port 9515
12 => #<Selenium::WebDriver::Driver:0x..f9d38b82e
13 browser=:chrome>
14 
15 > browser.get "http://watir.com"
16 => nil

PhantomJS

To drive PhantomJS (tested with version 1.9.2) download it, unzip the file and put it in any folder that is in your PATH. If you do not know what is PATH, see Internet Explorer chapter. In short, move phantomjs.exe file to Ruby folder, probably C:\Ruby200\bin.

Let’s try driving it:

 1 >irb
 2 
 3 > browser = Selenium::WebDriver.for :phantomjs
 4 (...)
 5 => #<Selenium::WebDriver::Driver:0x442ed372
 6 browser=:phantomjs>
 7 
 8 > browser.get "http://watir.com"
 9 => {}
10 
11 > browser.save_screenshot "phantomjs.png"
12 => #<File:phantomjs.png (closed)>

The last command saves screenshot of the page. A screenshot from a headless browser. Nice, right?

PhantomJS

PhantomJS

Java

To drive Opera, you will have to install Java first. Let’s check if Java is already installed with java -version:

1 >java -version
2 'java' is not recognized as an internal or
3 external command, operable program or batch file.

Looks like we will have to install Java. There is big Free Java Download button at java.com. Execute downloaded file and install Java. Let’s check if Java is really installed with java -version:

1 >java -version
2 java version "1.7.0_45"
3 Java(TM) SE Runtime Environment
4 (build 1.7.0_45-b18)
5 Java HotSpot(TM) Client VM (build 24.45-b08,
6 mixed mode, sharing)

Looks good to me!

Opera

Opera 18

Opera 18

And finally, let’s drive Opera. If you do not have it installed, you can get it at opera.com (tested with version 18.0).

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the Selenium server jar. Please download
 9 the standalone server from
10 http://code.google.com/p/selenium/downloads/list
11 and set the SELENIUM_SERVER_JAR environmental
12 variable to its location. More info at
13 http://code.google.com/p/selenium/wiki/OperaDriver.
14 (...)

Download selenium-server-standalone-2.39.0.jar (or newer version) from Google Code and put it in C:\Ruby200\bin. Then make SELENIUM_SERVER_JAR environmental variable and set it to C:\Ruby200\bin\selenium-server-standalone-2.39.0.jar. (If you have a newer version of selenium-server-standalone file, replace 2.39.0 appropriately.)

If you just want to try driving Opera, typing this into Command Prompt will do the trick:

1 >set SELENIUM_SERVER_JAR=C:\Ruby200\bin\
2 selenium-server-standalone-2.39.0.jar

Let’s try driving Opera again.

 1 >irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 Selenium::WebDriver::Error::UnknownError: Could
 8 not find a platform that supports bundled
 9 launchers, please set it manually
10 Build info: version: '2.39.0', revision: 'ff23eac',
11 time: '2013-12-16 16:11:15'
12 System info: host: 'IE11WIN8_1', ip: '10.0.2.15',
13 os.name: 'Windows 8',
14 os.arch: 'x86', os.version: '6.2', java.version:
15 '1.7.0_45'
16 Driver info: driver.version: OperaDriver
17 (org.openqa.selenium.WebDriverException)

Looks like Selenium can not drive Opera on Windows 8.1.

If I ever manage to drive Opera on Windows, to create a permanent environmental variable, use setx:

1 >setx SELENIUM_SERVER_JAR C:\Ruby200\bin\
2 selenium-server-standalone-2.39.0.jar
3 SUCCESS: Specified value was saved.

Open new command prompt, the old one will not see SELENIUM_SERVER_JAR variable.

Mac OS X 10.9

You will need internet access if you want to follow examples. All examples are tested with Mac OS X 10.9. All browsers are English (US) version.

Mac OS X 10.9 default desktop

Mac OS X 10.9 default desktop

Ruby

Good news is that Ruby is already installed by default. To check Ruby version, open Terminal application any type ruby -v. If you are not familiar with Terminal, see Command-line interface chapter.

You should get this:

1 $ ruby -v
2 ruby 2.0.0p247 (2013-06-27 revision 41674)
3 [universal.x86_64-darwin13]

RubyGems

It is already installed, but an old version. Let’s see which version is here with gem -v.

You should get this:

1 $ gem -v
2 2.0.3

Fortunately, it is easy to upgrade RubyGems with sudo gem update --system:

1 $ sudo gem update --system
2 (...)
3 RubyGems 2.1.11 installed
4 (...)

selenium-webdriver

Let’s try selenium-webdriver gem. Install it with sudo gem install selenium-webdriver --no-ri --no-rdoc.

You will probably get this:

1 $ sudo gem install selenium-webdriver
2 (...)
3 Fetching: ffi-1.9.3.gem (100%)
4 Building native extensions.  This could take a
5 while...
6 ERROR:  Error installing selenium-webdriver:
7 ERROR: Failed to build gem native extension.
8 (...)

Fortunately, it is easy to fix. Install command line developer tools. To install them, type this into Terminal.

1 $ git --version

A popup will appear asking if you would like to install command line developer tools.

Install command line developer tools popup

Install command line developer tools popup

Click Install. After the installation is finished, try again:

1 $ sudo gem install selenium-webdriver --no-ri
2 --no-rdoc
3 (...)
4 Successfully installed selenium-webdriver-2.37.0
5 (...)

Safari

Safari 7

Safari 7

Since Safari (tested with version 7.0) is already installed, all you have to do is to open IRB and type this. If you are not familiar with IRB, see IRB chapter.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :safari
 7 => #<Selenium::WebDriver::Driver:0x..
 8 f93d5546968bec45e browser=:safari>
 9 
10 > browser.get "http://watir.com"
11 => nil

Firefox

Firefox 26

Firefox 26

To drive Firefox (tested with version 25.0.1), make sure you have it installed. Open our old friend IRB and type this:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :firefox
 7 => #<Selenium::WebDriver::Driver:
 8 0x10e1416dd9107ffe browser=:firefox>
 9 
10 > browser.get "http://watir.com"
11 => ""

Great! We can drive Firefox.

Homebrew

To drive Chrome, you need Homebrew. To install it, paste this into Terminal. You will have to type your password during installation.

1 $ ruby -e "$(curl -fsSL
2 https://raw.github.com/mxcl/homebrew/go/install)"
3 (...)
4 ==> Installation successful!
5 You should run `brew doctor' *before* you install
6 anything.
7 Now type: brew help

To check if everything is set up correctly, type brew doctor:

1 $ brew doctor
2 Your system is ready to brew.

Everything looks good!

(You can thank me later for Homebrew.)

Chrome

Chrome 31

Chrome 31

To drive Chrome (tested with version 31), make sure you have it installed.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the chromedriver executable. Please
 9 download the server from
10 http://code.google.com/p/chromedriver/downloads/
11 list and place it somewhere on your PATH. More
12 info at
13 http://code.google.com/p/selenium/wiki/
14 ChromeDriver.
15 (...)

Looks like we have to install something called ChromeDriver executable. The easiest way to install ChromeDriver is via Homebrew.

1 $ brew install chromedriver
2 (...)

Let’s try again:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 => #<Selenium::WebDriver::Driver:
 8 0xec6568f803e9898 browser=:chrome>
 9 
10 > browser.get "http://watir.com"
11 => ""

Finally! It works!

Chromium

Chromium 34

Chromium 34

Let’s try driving Chromium (tested with version 33) too, just for fun. Download zip file from download-chromium.appspot.com. Unzip the file and move Chromium.app file to /Applications folder. If you did not already install ChromeDriver, see Chrome chapter. To open the browser for the first time you will have to right click it while holding control, then click Open from context menu. The next time you can open it in an usual way.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > Selenium::WebDriver::Chrome.path =
 7 "/Applications/Chromium.app/Contents/MacOS/
 8 Chromium"
 9 => "/Applications/Chromium.app/Contents/MacOS/
10 Chromium"
11 
12 > browser = Selenium::WebDriver.for :chrome
13 => #<Selenium::WebDriver::Driver:
14 0x1e35d5faa9511ec6 browser=:chrome>
15 
16 > browser.get "http://watir.com"
17 => nil

PhantomJS

To drive PhantomJS (tested with version 1.9.2), make sure you have it installed. The easiest way to install it is via Homebrew. (You can thank me now for Homebrew. You are welcome.)

1 $ brew install phantomjs
2 (...)

Let’s try driving it:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :phantomjs
 7 => #<Selenium::WebDriver::Driver:0x..
 8 fbdc736b89bb162d0 browser=:phantomjs>
 9 
10 > browser.get "http://watir.com"
11 => ""
12 
13 > browser.save_screenshot "phantomjs.png"
14 => #<File:phantomjs.png (closed)>

The last command saves screenshot of the page. A screenshot from a headless browser. Nice, right?

PhantomJS

PhantomJS

Opera

Opera 18

Opera 18

To drive Opera (tested with version 12.16), make sure you have it installed.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the Selenium server jar. Please download
 9 the standalone server from
10 http://code.google.com/p/selenium/downloads/list
11 and set the SELENIUM_SERVER_JAR environmental
12 variable to its location. More info at
13 http://code.google.com/p/selenium/wiki/OperaDriver.
14 (...)

Error message similar to the one when we first tried to open Chrome. The solution is similar too. Install selenium-server-standalone via Homebrew! (If you did not thank me for Homebrew, you can do it now. You are welcome.)

1 $ brew install selenium-server-standalone
2 (...)

Let’s try again:

1 $ irb
2 
3 > require "selenium-webdriver"
4 => true
5 
6 > browser = Selenium::WebDriver.for :opera
Install Java

Install Java

A popup window will appear saying To open “java,” you need a Java SE 6 runtime. Would you like to install one now?. Click buttion Install, agree with license agreement and Java will install.

Check if Java is installed. Open new Terminal window or tab (it is important to open new window or tab, Terminal will not see Java otherwise) and type java -version:

1 $ java -version
2 java version "1.6.0_65"
3 Java(TM) SE Runtime Environment
4 (build 1.6.0_65-b14-462-11M4609)
5 Java HotSpot(TM) 64-Bit Server VM
6 (build 20.65-b04-462, mixed mode)

The last step is setting SELENIUM_SERVER_JAR environmental variable.

If you just want to try driving Opera, typing this into Terminal will do the trick (if you have a newer version of selenium-server-standalone file, replace 2.37.0 appropriately):

1 $ export SELENIUM_SERVER_JAR=
2 /usr/local/opt/selenium-server-standalone/
3 selenium-server-standalone-2.37.0.jar

Let’s drive Opera, finally! (Following steps will work only in Terminal tab or window where you have exported SELENIUM_SERVER_JAR environment variable.)

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 Selenium::WebDriver::Error::UnknownError: Invalid
 8 service list received:
 9 (...)
10 (java.lang.IllegalStateException)
11 (...)

If you get above error message, install an older version of Opera. Looks like Selenium can not drive newer versions. The last version that I managed to drive was 12.16. You can get older versions at opera.com/download/guide/?os=mac&list=all or arc.opera.com/pub/opera.

Let’s try again.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 => #<Selenium::WebDriver::Driver:0x..
 8 fc28c93dae7536a48 browser=:opera>
 9 
10 > browser.get "http://watir.com"
11  => nil

Success!

If you plan to drive Opera frequently, you should add SELENIUM_SERVER_JAR to .bash_profile file. Create (if the file does not exist) or edit .bash_profile file in your home folder (/Users/zeljko/.bash_profile in my case, or shorter ~/.bash_profile) with your favorite text editor. Add export SELENIUM_SERVER_JAR... line to the file.

This is how to do it with GNU nano. Type type nano ~/.bash_profile. GNU nano text editor will open. Paste (cmd-v, for example) export SELENIUM_SERVER_JAR... line. Exit GNU nano and save the file with control+x. Press y when it asks Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES)? and press Enter when it displays File Name to Write: .bash_profile or Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES)? (text is different if the file already exists or not).

GNU nano asking should it save changes to `.bash_profile` file

GNU nano asking should it save changes to .bash_profile file

If you have done everything right, GNU nano will close and you will see normal Terminal window. We can check if the line is written to .bash_profile file:

1 $ cat ~/.bash_profile
2 export SELENIUM_SERVER_JAR=
3 /usr/local/opt/selenium-server-standalone/
4 selenium-server-standalone-2.37.0.jar

Open new Terminal window or tab (this is important, already opened windows or tabs would not see SELENIUM_SERVER_JAR variable). Run the same commands again and everything should just work.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 => #<Selenium::WebDriver::Driver:0x..
 8 fc28c93dae7536a48 browser=:opera>
 9 
10 > browser.get "http://watir.com"
11  => nil

Ubuntu Linux 13.10

You will need internet access if you want to follow examples. All examples are tested with Ubuntu Linux 13.10 32-bit. All browsers are English (US) version.

Ubuntu Linux 13.10

Ubuntu Linux 13.10

Ruby

Let’s see if Ubuntu comes with Ruby installed. Open Terminal and type ruby -v:

1 $ ruby -v
2 The program 'ruby' can be found in the following
3 packages:
4  * ruby1.8
5  * ruby1.9.1
6 Try: sudo apt-get install <selected package>

Install it with sudo apt-get install ruby1.9.1:

1 $ sudo apt-get install ruby1.9.1
2 (...)
3 Setting up ruby1.9.1 (1.9.3.194-8.1ubuntu2.1) ...
4 (...)

Check the version with ruby -v:

1 $ ruby -v
2 ruby 1.9.3p194 (2012-04-20 revision 35410)
3 [i686-linux]

RubyGems

Let’s see the version of RubyGems we got with Ruby with gem -v:

1 $ gem -v
2 1.8.23

Update RubyGems with gem update --system:

 1 $ gem update --system
 2 ERROR:  While executing gem ... (RuntimeError)
 3 gem update --system is disabled on Debian, because
 4 it will overwrite the content of the rubygems
 5 Debian package, and might break your Debian system
 6 in subtle ways. The Debian-supported way to update
 7 rubygems is through apt-get, using Debian official
 8 repositories. If you really know what you are
 9 doing, you can still update rubygems by setting
10 the REALLY_GEM_UPDATE_SYSTEM environment variable,
11 but please remember that this is completely
12 unsupported by Debian.

Since I do not really know what I am doing, I will leave RubyGems at current version and hope everything will work.

selenium-webdriver

Let’s try selenium-webdriver gem. Install it with sudo gem install selenium-webdriver --no-ri --no-rdoc.

1 $ sudo gem install selenium-webdriver --no-ri
2 --no-rdoc
3 (...)
4 Fetching: ffi-1.9.3.gem (100%)
5 Building native extensions.  This could take a
6 while...
7 ERROR:  Error installing selenium-webdriver:
8 ERROR: Failed to build gem native extension.
9 (...)

This should fix the problem:

1 $ sudo apt-get install ruby1.9.1-dev
2 (...)
3 Setting up ruby1.9.1-dev (1.9.3.194-8.1ubuntu2.1)

Let’s try installing selenium-webdriver again:

1 $ sudo gem install selenium-webdriver --no-ri
2 --no-rdoc
3 (...)
4 Successfully installed selenium-webdriver-2.37.0
5 (...)

Sucess!

Firefox

Firefox 25

Firefox 25

Since Firefox (tested with version 25.0.1) is installed by default on Ubuntu, you do not have to install it.

Let’s check if it can drive Firefox:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :firefox
 7 => #<Selenium::WebDriver::Driver:0x21564606
 8 browser=:firefox>
 9 
10 > browser.get "http://watir.com"
11 => ""

No problem here, works just fine.

PhantomJS

To drive PhantomJS (tested with version 1.9.0), install it via apt-get:

1 $ sudo apt-get install phantomjs
2 (...)
3 Setting up phantomjs (1.9.0-1) ...

Let’s try driving it:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :phantomjs
 7 => #<Selenium::WebDriver::Driver:0x..fa5f26f44
 8 browser=:phantomjs>
 9 
10 > browser.get "http://watir.com"
11 => {}
12 
13 > browser.save_screenshot "phantomjs.png"
14 => #<File:phantomjs.png (closed)>

The last command saves screenshot of the page. A screenshot from a headless browser. Nice, right?

PhantomJS 1.9.0

PhantomJS 1.9.0

Chrome

Chrome 31

Chrome 31

Now, lets see if it can really drive Chrome (tested with version 31) too. Ubuntu does not have Chrome installed by default, so you have to install it yourself. Download it from google.com/chrome.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the chromedriver executable. Please
 9 download the server from
10 http://code.google.com/p/chromedriver/downloads/
11 list and place it somewhere on your PATH. More
12 info at
13 http://code.google.com/p/selenium/wiki/
14 ChromeDriver.
15 (...)

Looks like we have to install something called ChromeDriver executable. Fortunately, the error message is pretty clear. code.google.com/p/chromedriver/downloads/list will let you know that ChromeDriver executable is now located at chromedriver.storage.googleapis.com. Download the latest version of chromedriver_linux32.zip or chromedriver_linux64.zip (check if you have 32-bit or 64-bit operating system) and unzip it (mouse right click and then Extract Here, for example). You will get a file named chromedriver. Put it somewhere on your PATH, as the error message said.

Let’s find out what is on our PATH.

1 $ echo $PATH
2 /home/zeljko/bin:/usr/local/sbin:/usr/local/bin:
3 /usr/sbin:/usr/bin:/sbin:/bin:/usr/games

/usr/bin looks like a nice place, so let’s move chromedriver there. You will have to provide your password to move the file there.

1 $ sudo mv chromedriver /usr/bin

Let’s drive Chrome, finally:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :chrome
 7 => #<Selenium::WebDriver::Driver:0x5b77effe
 8 browser=:chrome>
 9 
10 > browser.get "http://watir.com"
11 => nil

And it really works!

Chromium

Chromium 30

Chromium 30

Let’s try driving Chromium (tested with version 30) too, just for fun. Install it with sudo apt-get install chromium-browser:

1 $ sudo apt-get install chromium-browser
2 (...)
3 Setting up chromium-browser
4 (30.0.1599.114-0ubuntu0.13.10.2) ...
5 (...)

If you did not already install ChromeDriver, see Chrome chapter.

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > Selenium::WebDriver::Chrome.path =
 7 "/usr/bin/chromium-browser"
 8 => "/usr/bin/chromium-browser"
 9 
10 > browser = Selenium::WebDriver.for :chrome
11 => #<Selenium::WebDriver::Driver:0x..fb4c9860a
12 browser=:chrome>
13 
14 > browser.get "http://watir.com"
15 => nil

Java

To drive Opera, you will have to install Java first. Let’s check if Java is already installed:

1 $ java -version
2 The program 'java' can be found in the following
3 packages:
4  * default-jre
5  * gcj-4.6-jre-headless
6  * gcj-4.7-jre-headless
7  * openjdk-7-jre-headless
8  * openjdk-6-jre-headless
9 Try: sudo apt-get install <selected package>

Looks like we will have to install Java. Install it with sudo apt-get install openjdk-7-jre-headless:

1 $ sudo apt-get install openjdk-7-jre-headless
2 (...)
3 Setting up openjdk-7-jre-lib (7u25-2.3.12-4ubuntu3)
4 (...)

Opera

Opera 12.16

Opera 12.16

To drive Opera (tested with version 12.16) make sure you have it installed.

Let’s see how it drives Opera. Open our old friend, IRB:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 Selenium::WebDriver::Error::WebDriverError: Unable
 8 to find the Selenium server jar. Please download
 9 the standalone server from
10 http://code.google.com/p/selenium/downloads/list
11 and set the SELENIUM_SERVER_JAR environmental
12 variable to its location. More info at
13 http://code.google.com/p/selenium/wiki/OperaDriver.
14 (...)

Error message similar to the one when we first tried to open Chrome. The solution is similar too. We have to download a file, put it somewhere and point a variable to it. Do not worry, it sounds more complicated than it really is. Fortunately again, the error message says it all. Go to code.google.com/p/selenium/downloads/list and download selenium-server-standalone-2.39.0.jar (or newer version, the description should be Use this if you want to use the Selenium RC or Remote WebDriver or use Grid 2 without needing any additional dependencies).

The last step is setting SELENIUM_SERVER_JAR environmental variable. If you just want to try driving Opera, typing this into Terminal will do the trick (assuming that the file is located in Downloads folder, if you have a newer version of selenium-server-standalone file, replace 2.39.0 appropriately):

1 $ export SELENIUM_SERVER_JAR=
2 ~/Downloads/selenium-server-standalone-2.39.0.jar

Let’s drive Opera, finally! (Following steps will work only in Terminal tab or window where you have exported SELENIUM_SERVER_JAR environment variable.)

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4 => true
 5 
 6 > browser = Selenium::WebDriver.for :opera
 7 => #<Selenium::WebDriver::Driver:0x..fb4bb92ce
 8 browser=:opera>
 9 
10 > browser.get "http://watir.com"
11 => nil

If you plan to drive Opera frequently, you should add SELENIUM_SERVER_JAR to .bashrc file. Create (if the file does not exist) or edit .bashrc file in your home folder (/home/z/.bashrc in my case, or shorter ~/.bashrc) with your favorite text editor. Add export SELENIUM_SERVER_JAR... line to the file.

1 $ nano ~/.bashrc

Save the file (ctrl+x) and close all Terminal windows. Open Terminal again. To check if the variable is set, try printenv | grep SELENIUM:

1 $ printenv | grep SELENIUM
2 SELENIUM_SERVER_JAR=/home/zeljko/bin/
3 selenium-server-standalone-2.39.0.jar

Looks good to me!

Quick Start

You will need internet access if you want to follow examples in this chapter. If you do not have Ruby, RubyGems, Selenium and Firefox installed, please see Installation chapter. If you are not familiar with Command-line interface or IRB, see Command-line interface and IRB chapters.

To start IRB, just type irb in command line. You will see something like this:

1 $ irb
2 >

Now you can enter any Ruby command and you will immediately get a result. We will start with telling Ruby that we want to use selenium-webdriver gem with require "selenium-webdriver":

You should see something like this:

1 > require "selenium-webdriver"
2 => true

Every Ruby command returns something. You should get => true after require "selenium-webdriver". There are two parts in the returned line. The first one is =>. It looks like an arrow. It means Ruby returned this. The second part is true, the thing that is actually returned. When true is returned, it usually means that everything is fine. Unless I say differently, just ignore what is returned, for now.

Open Firefox.

1 > browser = Selenium::WebDriver.for :firefox
2 => #<Selenium::WebDriver::Driver:...
3 browser=:firefox>

As I said earlier, you can ignore #<Selenium::WebDriver::Driver:...>. Opening Firefox returned the browser as an object, and this is textual representation of the object.

Just opening a browser is not so useful. Let’s open google.com. I would suggest that you literally follow the example, and then try a few sites yourself.

So, go to google.com:

1 > browser.get "https://www.google.com/"
2 => ""

And google.com opens. (Since I am in Croatia, google.hr opened. If you are not in the US, some other Google site could open.)

Controlling the browser is really useful but, as I am sure you already know, there is more to testing than just performing the actions. You have to check what happened after the action. What happens when I enter a URL in browser address bar, when I click a link or a button, when I enter some text in a text field or select something from select box…?

This is the first time we will perform a check. It is also the first time we will take a look what Ruby returns after the command. Let’s check if the browser really opened google.com.

1 > browser.current_url
2 => "https://www.google.hr/"

It really works! Ruby returned a string (the thing in double quotes) that contains the text from the browser address bar.

It’s time to click on a link. It is easy to explicitly say which link to click on. Right now I want to click on a link with the text Google.com. If your browser already opened google.com, ignore this step.

1 > browser.find_element(link_text: "Google.com").
2 click
3 => "ok"

And google.com opens. Now that all of us are on literally on the same page, let’s click another link:

1 > browser.find_element(link_text: "Images").click
2 => "ok"

This time, let’s check the page title.

1 > browser.title
2 => "Google Images"

We got back the string with the page title.

Let’s search for something. This will enter book in search text field:

1 > browser.find_element(name: "q").send_keys "book"
2 => ""

Maybe you are wondering how I knew the text field had the value of name attribute set to q. (I am talking about name: "q".) If you do not know how to inspect pages, read on. It will be explained in Browser Developer Tools chapter.

Now, click the search button:

1 > browser.find_element(name: "btnG").click
2 => "ok"

Page with search results will open. Let’s check how many images are on the page.

1 > browser.find_elements(tag_name: "img").size
2 => 126

You might get a different number, it does not have to be 126. And finally, let’s close the browser.

1 > browser.close
2 => ""

Well, that was a lot of fun. But you do not want to type into IRB all the time. You want to run the tests and do something else while they run. As for almost everything else in Ruby, there is a simple solution. Paste all code you have entered in IRB in a text file, and save it with rb extension. IRB is used only for development or debugging, so do not paste irb as the first line of the file. The file should look like this:

 1 require "selenium-webdriver"
 2 browser = Selenium::WebDriver.for :firefox
 3 browser.get "https://www.google.com/"
 4 browser.current_url
 5 browser.find_element(link_text: "Google.com").click
 6 browser.find_element(link_text: "Images").click
 7 browser.title
 8 browser.find_element(name: "q").send_keys "book"
 9 browser.find_element(name: "btnG").click
10 browser.find_elements(tag_name: "img").size
11 browser.close

You can use any text editor to edit the file. I use RubyMine or Sublime Text.

Save the file as quick_start.rb. If IRB is still running in your command line, press ctrl+d to return to normal command prompt, or open a new command prompt. (To exit from IRB to normal command line, instead of pressing ctrl+d, you can also type quit or exit.) You should remove clicking Google.com link if Firefox opens it automatically for you.

To run the file, navigate in command prompt to the folder where you have saved it and run it:

1 $ ruby quick_start.rb

Smile while the browser clicks around.

What is the output in the command prompt? Nothing? Yes, nothing. IRB displays values that Ruby returns, but when you execute Ruby file from the command line, it does not display the values Ruby returns. You have to explicitly say to Ruby that you want them displayed. It is as easy as adding p in front of the command. Add p in front of three lines. Modify the script to look like this. You can add p in front of every command, but you really do not care about what some commands return:

 1 require "selenium-webdriver"
 2 browser = Selenium::WebDriver.for :firefox
 3 browser.get "https://www.google.com/"
 4 p browser.current_url
 5 browser.find_element(link_text: "Google.com").click
 6 browser.find_element(link_text: "Images").click
 7 p browser.title
 8 browser.find_element(name: "q").send_keys "book"
 9 browser.find_element(name: "btnG").click
10 p browser.find_elements(tag_name: "img").size
11 browser.close

Run the script. This time the output should look like this:

1 $ ruby quick_start.rb
2 "https://www.google.hr/"
3 "Google Images"
4 126

Later I will show you how to make cool looking reports.

Getting Help

TODO

How to get help might be most important thing to learn. In general good resources are Stack Overflow, Google Groups, IRC and project web sites.

It might seem almost a joke that project web sites are mentioned, but all the time I see people asking for help without doing even the basic research. Also, common pattern is asking for help in the wrong place. You will not get good support asking for help with Selenium on a general purpose Ruby mailing list, or asking a basic Ruby question at a Selenium mailing list. You have to learn enough Ruby to know where the language (Ruby) ends and where a library (like Selenium) starts.

It is really important that you learn where you can get more information. A good start is selenium-webdriver gem page at RubyGems.org. You will find links to it’s homepage, source code, API documentation, wiki and bug tracker there. Another good API documentation is automatically generated at selenium-webdriver section of rdoc.info site. Looks like rdoc.info is more up to date than the official API documentation. At the moment, you should focus on API documentation and wiki. The wiki says that Selenium::WebDriver::Driver and Selenium::WebDriver::Element are the two main classes.

Driver

You will need internet access if you want to follow examples in this chapter. All examples in this chapter are tried on Mac OS X 10.8.5, Firefox 27.0.1, Ruby 2.1.0p0 and selenium-webdriver 2.40.0 but everything should work on all supported platforms. If you are not familiar with Command-line interface or IRB, see Command-line interface and IRB chapters.

In this chapter you will learn how to control the browser using Selenium. In Quick Start chapter we have touched two important part of Selenium API, driver and element. In this chapter we will focus on the driver. The chapter will not cover the entire driver API, for more information see Selenium::WebDriver::Driver API documentation.

The first thing you have to do is to open the browser. According to the documentation, currently supported browsers are Firefox, Internet Explorer, Chrome, Android, iPhone, Opera, PhantomJS, Safari and remote browser. Let’s focus on desktop drivers for now. See Mobile chapter on how to drive mobile browsers and Selenium in the Cloud chapter on how to driver remote browsers. How to set up everything is explained in detail in Installation chapter.

Browser Symbol Shortcut
Chrome :chrome  
Firefox :firefox :ff
Internet Explorer :internet_explorer :ie
Opera :opera  
PhantomJS :phantomjs  
Safari :safari  

How to start a browser

Open Firefox:

1 $ irb
2 
3 > require "selenium-webdriver"
4  => true
5 
6 > browser = Selenium::WebDriver.for :firefox
7 => #<Selenium::WebDriver::Driver:0x..
8 f8698791d2bff9778 browser=:firefox>

or

1 > browser = Selenium::WebDriver.for :ff
2 => #<Selenium::WebDriver::Driver:...
3 browser=:firefox>

If you want to drive a different browser, just replace :firefox with another symbol.

Let’s try a few interesting methods. get opens a page:

1 > browser.get "http://google.com"
2 => ""

current_url returns page URL:

1 > browser.current_url
2 => "https://www.google.hr/"

title returns page title:

1 > browser.title
2 => "Google"

close closes the current window or the entire browser if there is only one window open.

When you are done with the browser, close it:

1 > browser.close
2 => ""

If you want to close multiple browser windows at once, use quit:

1 > browser.quit
2 => nil

Create a Ruby file from the above IRB session and save it as driver.rb. Of course, add a p in front of a few commands, so the script outputs something.

1 require "selenium-webdriver"
2 browser = Selenium::WebDriver.for :firefox
3 browser.get "http://google.com"
4 p browser.current_url
5 p browser.title
6 browser.close
7 browser.quit

Run the file:

1 $ ruby driver.rb
2 "https://www.google.hr/"
3 "Google"

Element

You will need internet access if you want to follow examples in this chapter. All examples in this chapter are tried on Mac OS X 10.8.5, Firefox 27.0.1, Ruby 2.1.0p0 and selenium-webdriver 2.40.0 but everything should work on all supported platforms. If you are not familiar with Command-line interface or IRB, see Command-line interface and IRB chapters.

After you had a taste of Selenium in Getting Started chapter, it is time to take a closer look at the Selenium API. This chapter will get you introduced to the API but it will not cover it entirely. For more information see Selenium::WebDriver::Element API documentation.

Let’s start Firefox and open Google home page:

 1 $ irb
 2 
 3 > require "selenium-webdriver"
 4  => true
 5 
 6 > browser = Selenium::WebDriver.for :firefox
 7 => #<Selenium::WebDriver::Driver:0x..
 8 f8698791d2bff9778 browser=:firefox>
 9 
10 > browser.get "http://google.com"
11 => ""

Most of the time you will be dealing with page elements, so let’s see how to do that. First, you need to find the element on the page, then you usually need to do something with it, like entering text or clicking it. To find the element, use find_element method.

1 > browser.find_element(name: "q")
2 => #<Selenium::WebDriver::Element:...
3    id="{25201324-ac0c-8e40-9766-c35aa5b54786}">

There are many options available to find an element.

How Symbol Shortcut
class name :class_name :class
css selector :css  
id :id  
link text :link_text :link
name :name  
partial link text :partial_link_text  
tag name :tag_name  
xpath :xpath  

How to find an element

Looks like we have found the element, but we did not do anything with it yet. Since the element we have found is a text field, let’s enter some text into it:

1 > browser.find_element(name: "q").send_keys "watir"
2 => ""

We can also clear the text field:

1 > browser.find_element(name: "q").clear
2 => ""

There is a shortcut if you want to find an element via it’s id. Just provide the id:

1 > browser["gbqfq"]
2 => #<Selenium::WebDriver::Element:...
3    id="{fca96529-8bc6-bf4f-8e78-376f037c351a}">

To get the value of any element attribute, use attribute. Try a few attributes:

 1 > browser["gbqfq"].attribute(:name)
 2 => "q"
 3 
 4 > browser["gbqfq"].attribute(:class)
 5 => "gbqfif"
 6 
 7 > browser["gbqfq"].attribute(:type)
 8 => "text"
 9 
10 > browser["gbqfq"].attribute(:autocomplete)
11 => "off"
12 
13 > browser["gbqfq"].attribute(:style)
14 => "border: medium none; padding: 0px; margin: ...
15 
16 > browser["gbqfq"].attribute(:outerHTML)
17 => "<input spellcheck=\"false\" dir=\"ltr\" ...

Create a Ruby file from the above IRB session and save it as element.rb. Of course, add a p in front of a few commands, so the script outputs something.

 1 require "selenium-webdriver"
 2 browser = Selenium::WebDriver.for :firefox
 3 browser.get "http://google.com"
 4 browser.find_element(name: "q")
 5 browser.find_element(name: "q").send_keys "watir"
 6 browser.find_element(name: "q").clear
 7 browser["gbqfq"]
 8 p browser["gbqfq"].attribute(:name)
 9 p browser["gbqfq"].attribute(:class)
10 p browser["gbqfq"].attribute(:type)
11 p browser["gbqfq"].attribute(:autocomplete)
12 p browser["gbqfq"].attribute(:style)
13 p browser["gbqfq"].attribute(:outerHTML)

Run the file:

1 $ ruby element.rb
2 "q"
3 "gbqfif"
4 "text"
5 "off"
6 "border: medium none; padding: 0px; margin: 0px;...
7 "<input spellcheck=\"false\" dir=\"ltr\" style=...

Nesting

TODO

How and why to use nesting when working with page elements.

Collections

TODO

How to work with collections of page elements.

Frames

TODO

Frames have a special treatment.

Pop Ups

TODO

Pop up windows are causing a lot of trouble for people.

Headless

I have noticed a lot of confusion about headless testing, but there is really nothing special there. The confusion may be caused by the term headless being a bit vague. In the context of driving a browser, headless means you can drive a real browser, but without seeing anything on the machine. It can be useful for running tests on a headless machine, or on a desktop machine. For example, if you want to run tests on a headless machine as part of continuous integration, or if you want to run tests on your desktop machine without browsers opening and closing on the screen all the time, while you are doing something else.

There are two ways to run browser in a headless mode that I am aware of. One is to use a headless browser like PhantomJS. Another option is using Xvfb (X virtual framebuffer) and Headless gem. Please notice that Xvfb works only on Linux.

The advantage of running tests in PhantomJS is that it is supported on all major operating systems. The browser is pretty good, it has the same Selenium API as all other browsers, so the vast majority of the tests developed using another browser will just work. It also has a pretty good JavaScript engine, so even JavaScript heavy pages should work fine. The browser is also faster than other browsers. More speed is always good, but speed improvement depends on a lot of things, so sometimes you will see a lot of improvement, and sometimes just a few percent.

The disadvantage is that the users of your web application are not using PhantomJS to access it, they are using one of the major browsers. Sometimes you will have to tweak the tests or the application to get all tests to run fine. It is also harder to debug failures, since the browser is headless. Fortunately, you can take screen shots and HTML of the page (the entire page or just the relevant part).

The advantage of using Xvfb is that it works with any browser that Selenium can drive. You can delevop tests using your favorite browser and then run them in headless mode with no modifications. The disadvantage is that is it somewhat slower than PhantomJS (but not a lot), and it works only on Linux. Let me repeat that, Xvfb does not work on Windows or Mac OS.

PhantomJS

You will need internet access if you want to follow examples in this chapter. All examples in this chapter are tried on Mac OS X 10.8.5, PhantomJS 1.9.7, Ruby 2.1.1p76 and selenium-webdriver 2.40.0 but everything should work on all supported platforms.

If you do not have Ruby, Selenium and PhantomJS already installed, please see Installation chapter. If you are not familiar with Selenium API, please see Quick Start, Driver and Element chapters.

All you have to do to drive PhantomJS is to let Selenium know that you want to drive it:

1 $ irb
2 
3 > require "selenium-webdriver"
4  => true
5 
6 > browser = Selenium::WebDriver.for :phantomjs
7 => #<Selenium::WebDriver::Driver:...
8 browser=:phantomjs>

The rest of the API is the same as for any other browser. For example, go to a page:

1 > browser.get "http://google.com"
2 => {}

Get it’s URL and title:

1 > browser.current_url
2 => "http://www.google.hr/"
3 
4 > browser.title
5 => "Google"

Enter text into the text field and then clear the text field:

1 > browser.find_element(name: "q").send_keys "watir"
2 => nil
3 
4 > browser.find_element(name: "q").clear
5 => nil

Play with element attributes:

 1 > browser.find_element(name: "q").attribute(:name)
 2 => "q"
 3 
 4 > browser.find_element(name: "q").attribute(:class)
 5 => "lst tiah"
 6 
 7 > browser.find_element(name: "q").attribute(:type)
 8 => "text"
 9 
10 > browser.find_element(name: "q").
11 attribute(:autocomplete)
12 => "off"

When driving Firefox or any of the usual browsers, you are able to see how to page looks like. With PhantomJS you do not see anything, so it is really important to know how to debug problems. Two features are really useful, taking screenshots and getting page HTML.

To take a screenshot, use save_screenshot method:

1 > browser.save_screenshot "phantomjs.png"
2 => #<File:phantomjs.png (closed)>

To get page HTML, use

1 > browser.page_source
2 => "<!DOCTYPE html><html itemscope=\"\"
3 itemtype=\"http://schema.org/WebPage\"><head><meta
4 itemprop=\"image\"
5 content=\"/images/google_favicon_128.png\">
6 <title>Google</title><script>
7 ...
8 </script></body></html>"

To get HTML of just a part of the page, ask for outerHTML attribute:

1 > browser.find_element(name: "q").
2 attribute(:outerHTML)
3 => "<input autocomplete=\"off\" class=\"lst tiah\"
4 ...

At the end, close the browser:

1 > browser.quit
2 => nil

Create a Ruby file from the above IRB session and save it as headless_phantomjs.rb. Of course, add a p in front of a few commands, so the script outputs something.

 1 require "selenium-webdriver"
 2 browser = Selenium::WebDriver.for :phantomjs
 3 browser.get "http://google.com"
 4 p browser.current_url
 5 p browser.title
 6 browser.find_element(name: "q").send_keys "watir"
 7 browser.find_element(name: "q").clear
 8 p browser.find_element(name: "q").attribute(:name)
 9 p browser.find_element(name: "q").attribute(:class)
10 p browser.find_element(name: "q").attribute(:type)
11 p browser.find_element(name: "q").
12   attribute(:autocomplete)
13 browser.save_screenshot "phantomjs.png"
14 p browser.page_source
15 p browser.find_element(name: "q").
16   attribute(:outerHTML)
17 browser.quit

Run the file:

1 $ ruby headless_phantomjs.rb
2 "http://www.google.hr/"
3 "Google"
4 "q"
5 "lst tiah"
6 "text"
7 "off"
8 "<!DOCTYPE html><html itemscope=\"\" itemtype=...
9 "<input autocomplete=\"off\" class=\"lst tiah\"...

Xvfb

You will need internet access if you want to follow examples in this chapter. All examples in this chapter are tried on Ubuntu Linux 13.10, Firefox 27.0.1, Ruby 2.1.1p76 and selenium-webdriver 2.40.0 but everything should work on all supported platforms.

Xvfb works only on Linux. It does not work on Windows or Mac OS.

If you do not have Firefox, Ruby or Selenium installed, see Installation chapter. If you are not familiar with Selenium API, please see Quick Start, Driver and Element chapters.

Without getting into a lot of technical detail, Xvfb (X virtual framebuffer) is a piece of software that makes is possible to run browsers (and other applications) in a headless mode.

Install Xvfb via apt-get:

1 $ sudo apt-get install xvfb
2 ...

Then install headless Ruby gem:

1 $ gem install headless --no-ri --no-rdoc
2 ...

“To sudo or not to sudo, that is the question…”

On the machine I was using while writing this chapter, Ruby was installed via RVM (Ruby Version Manager). If you are using Ruby that was preinstalled on the computer (as it is on a Mac OS X) or if you have installed Ruby via apt-get (on Ubuntu) then you have to add sudo in front of gem:

1 $ sudo gem install headless --no-ri --no-rdoc
2 ...

There are two modes of using headless gem, block and object. Block mode will automatically start and destroy headless session. In object mode, you have to explicitly start and destroy the session.

This is an example of block mode (using IRB):

 1 $ irb
 2 
 3 > require "headless"
 4 => true
 5 
 6 > require "selenium-webdriver"
 7 => true
 8 
 9 > Headless.ly do
10 >   browser = Selenium::WebDriver.for :firefox
11 >   browser.get "http://google.com"
12 >   browser.title
13 > end
14 => "Google"

This is an example of object mode (using IRB):

 1 $ irb
 2 
 3 > require "headless"
 4 => true
 5 
 6 > require "selenium-webdriver"
 7 => true
 8 
 9 > headless = Headless.new
10 => #<Headless:0x9e957d8 @display=99,
11 @autopick_display=true, @reuse_display=true,
12 @dimensions="1280x1024x24",
13 @video_capture_options={}, @destroy_at_exit=true>
14 
15 > headless.start
16 => #<Proc:...>
17 
18 > browser = Selenium::WebDriver.for :firefox
19 => #<Selenium::WebDriver::Driver:...
20  browser=:firefox>
21 
22 > browser.get "http://google.com"
23 => ""
24 
25 > browser.title
26 => "Google"
27 
28 > headless.destroy
29 => ["/tmp/.X99-lock"]

Of course, block and object mode can be used in Ruby files, not just in IRB. Save the following text as headless_block_mode.rb file.

1 require "headless"
2 require "selenium-webdriver"
3 
4 Headless.ly do
5   browser = Selenium::WebDriver.for :firefox
6   browser.get "http://google.com"
7   p browser.title
8 end

Run the file:

1 $ ruby headless_block_mode.rb
2 "Google"

Save the following text as headless_object_mode.rb file.

 1 require "headless"
 2 require "selenium-webdriver"
 3 
 4 headless = Headless.new
 5 headless.start
 6 
 7 browser = Selenium::WebDriver.for :firefox
 8 browser.get "http://google.com"
 9 p browser.title
10 
11 headless.destroy

Run the file:

1 $ ruby headless_object_mode.rb
2 "Google"

As usual, you can take screenshots using Selenium API while running tests, even in headless mode. If you do not know how to do that, see Driver chapter.

Xvfb has it’s own screenshots and video recording API, but it is beyond the scope of this book to cover it. For more information see documentation for headless gem.

Selenium in the Cloud

TODO

In addition to being able to drive browsers on your machine, Selenium can also drive browsers on remote machines. This chapter will let you know how to do that using services like Sauce Labs, TestingBot and BrowserStack.

Mobile

TODO

Android and iPhone drivers will be deprecated really soon, but fortunately there are good alternatives. See Android and iOS Support blog post at Official Selenium Blog for more detail. In this chapter you will learn how to test mobile browsers with tools like Selendroid, ios-driver and Appium.

Alternative APIs

TODO

In addition to Selenium WebDriver API, there are other APIs that you can use, like Capybara, Webrat and Watir.

Page Object Pattern

TODO

Page Object pattern is the best way to organize your Selenium code. This chapter will show you how you can create a simple implementation of the pattern and how to use page-object gem.

Recorders

TODO

Test Frameworks

TODO

While writing tests, you will need a way to set up the environment before the test, clean up after the test, create reports after all tests are executed and similar tasks. There is no need to implement that functionality yourself because Ruby has a lot of good and mature test frameworks. Two really popular ones are Cucumber and RSpec.

Ruby Tools

TODO

You will be writing a lot of Ruby code. It is beyond scope of this book to teach Ruby, so if you are not familiar with it, you should read a book or two about it. You should also get familiar with Ruby tools like IRB (Interactive Ruby Shell), RubyGems, Bundler, RDoc, RVM (Ruby Version Manager) and The Ruby Toolbox.

IRB (Interactive Ruby Shell)

You do need internet access if you want to follow examples in this chapter. All examples in this chapter are tried on Mac OS X 10.8.5 and Ruby 2.1.1p76 but everything should work on all supported platforms.

If you are familiar with Ruby, I am sure you already think IRB (Interactive Ruby Shell) is one of the greatest tools for learning a new Ruby library. If you are new to Ruby, you are probably thinking: What is this IRB thing? IRB is Interactive Ruby Shell. We will not get into technical details here, all you need to know is that it is a shell that executes Ruby commands. Every command executes immediately and returns something. Sometimes you will be interested in the return value, the rest of the time you can ignore it.

IRB is a command-line interface (CLI) tool. If you are not familiar with CLI, see Command-line interface chapter.

To start IRB, type irb in command line. On Mac and Linux, it should look like this:

1 $ irb
2 2.1.1 :001 >

On Windows, it should look like this:

1 >irb
2 DL is deprecated, please use Fiddle
3 irb(main):001:0>

If you see something slightly different, do now worry, if the examples from this chapter work fine. Let’s take a look at the output. Mac and Linux have 2.1.1 :001 > as prompt and Windows has irb(main):001:0>. On Mac/Linux, 2.1.1 part is Ruby version. Windows does not display it. Windows has irb(main), so you do not forget you are using IRB. Windows also displays DL is deprecated, please use Fiddle warning message. Feel free to ignore it.

:001 on Mac/Linux and :001:0 on Windows is line number. If you just press enter/return (depending on your keyboard), you should see something like this.

Mac/Linux:

1 $ irb
2 2.1.1 :001 >
3 2.1.1 :002 >

Windows:

1 >irb
2 DL is deprecated, please use Fiddle
3 irb(main):001:0>
4 irb(main):002:0*

Since the part before the > or * is not important for us at the moment, we will ignore it in the rest of the book. To differentiate between regular CLI and IRB, the book will use $ for the regular CLI and > for IRB. Let me explain that with a couple of examples.

Executing ls command in Mac/Linux CLI:

1 $ ls
2 Book.txt Gemfile.lock README.md VERSION images lib
3 misc Gemfile LICENSE.md Subset.txt epub_images
4 installation main old

Executing 1+1 in IRB:

1 $ irb
2 
3 > 1+1
4 => 2

The above IRB example shows that Ruby knows how to calculate sum of two numbers. You can also ask it to output something:

1 > p "wow much output so hip"
2 "wow much output so hip"
3 => "wow much output so hip"

After outputting the string, Ruby returned it. You can ignore it for now. All you need to know is that it did not complain. Let’s try something that will fail:

1 > doge
2 NameError: undefined local variable or method
3 `doge' for main:Object
4 from (irb):7
5 from /Users/z/.rvm/rubies/ruby-2.1.1/bin/irb:11:in
6 `<main>'

Looks like Ruby does not know about Doge meme. Important thing here is to notice how an error message looks like. Let’s do something useful now, like nicely formatting output. First, we will create a doge variable:

1 > doge = {dogecoin: "To the moon!",
2 hello: "This is Doge", wow: "much addon",
3 so: "internet"}
4 => {:dogecoin=>"To the moon!",
5 :hello=>"This is Doge", :wow=>"much addon",
6 :so=>"internet"}

Then we will try to output is nicely with pp library:

1 > pp doge
2 NoMethodError: undefined method `pp' for
3 main:Object
4 from (irb):9
5 from ...irb:11:in `<main>'

Looks like Ruby does not know about pp too. All you need to do to fix the problem is to require the library:

1 > require "pp"
2 => true

Let’s output doge, finally:

1 > pp doge
2 {:dogecoin=>"To the moon!",
3 :hello=>"This is Doge",
4 :wow=>"much addon",
5 :so=>"internet"}
6 => {:dogecoin=>"To the moon!",
7 :hello=>"This is Doge", :wow=>"much addon",
8 :so=>"internet"}

PP is a pretty-printer for Ruby objects. It is really useful for outputting big objects.

IRB is not the only Ruby shell. There is irb Alternatives category at The Ruby Toolbox. The most popular alternative tool is Pry, but there is another one called ripl.

RVM (Ruby Version Manager)

On Mac and Linux you can install and use multiple versions of Ruby at the same time using RVM (Ruby Version Manager).

RVM on Ubuntu

On Ubuntu, first you have to install curl:

1 $ sudo apt-get install curl
2 ...

Then, you have to configure Terminal. Go to Terminal > Edit > Profile Preferences.

PhantomJS

PhantomJS

Select Title and Command tab, check Run command as a login shell checkbox and then click Close button.

PhantomJS

PhantomJS

In case of trouble see RVM documentation on Terminal.

Install RVM:

1 $ \curl -sSL https://get.rvm.io | bash -s stable
2 ...

Open new Terminal tab or window. That is important. RVM might not work properly if you do not open new tab/window after installation. Finally, install a recent version of Ruby:

1 $ rvm install 2.1.1
2 ...

Ask RVM which versions for Ruby are installed:

1 $ rvm list
2 
3 rvm rubies
4 
5    ruby-2.1.0 [ i686 ]
6    ruby-2.1.1 [ i686 ]

Terminal will not be aware of the Ruby installed via RVM until you explicitly tell it to use it. Try asking the Terminal for Ruby version:

1 $ ruby -v
2 The program 'ruby' can be found in the following
3 packages:
4 * ruby1.8
5 * ruby1.9.1

See, Terminal does not think Ruby is installed. Now, tell RVM you want to use the latest version:

1 $ rvm use ruby-2.1.1
2 Using /home/z/.rvm/gems/ruby-2.1.1

Ask Terminal again for Ruby version:

1 $ ruby -v
2 ruby 2.1.1p76 (2014-02-24 revision 45161)
3 [i686-linux]

Now it knows about Ruby installed via RVM. You can also ask RVM which Ruby is it using currently:

 1 $ rvm list
 2 
 3 rvm rubies
 4 
 5    ruby-2.1.0 [ i686 ]
 6 => ruby-2.1.1 [ i686 ]
 7 
 8 # Default ruby not set. Try 'rvm alias create
 9 default <ruby>'.
10 
11 # => - current
12 # =* - current && default
13 #  * - default

Currently used Ruby (ruby-2.1.1) is marked with the arrow (=>).

The Ruby Toolbox

The Ruby Toolbox is a really useful site where you can find and compare a lot of libraries. Libraries are grouped in categories. Whatewer you are looking for, it is probably listed there. Some of categories and tools are: IRB alternatives (like Pry), PDF processing (like PDF::Reader), image processing (like Chunky PNG), log analysis (like logstash), dependency management (like Bundler), acceptance test frameworks (like Cucumber), browser testing (like Selenium), distributed testing (like ParallelTests) or unit test frameworks (like RSpec).

Browser Developer Tools

TODO

Every contemporary browser has developer tools built in. This chapter will give a short overview of available options and how to use them.

Continuous Integration

TODO

There is only limited value in running tests here and there on your local machine. The best way to run tests is as frequently as possible using a continuous integration tool like Jenkins or Travis CI. In this chapter you will learn how to set up hosted Jenkins at CloudBees and Travis CI.

Virtual Machines

TODO

It is really convenient to run tests in virtual machines. In this chapter you will learn how to use VirtualBox, Parallels, VMware and Windows Virtual PC.

Tools

TODO

You will have to learn how to use Command-line interface (CLI) since you will be spending a lot of time there. You will be spending a lot of time typing text so picking up a good text editor like Sublime Text or IDE (integrated development environment) like RubyMine will help. You will also be changing the code a lot so learning how to use a version control tool like Git is important. A lot of tools that are mentioned in this book are hosted at GitHub, Git hosting service.

Command-line interface

Command-line interface (CLI) is just another application. It is already installed, whether you are using Windows, Mac or Linux. CLI looks similar and behaves similarly on Mac and Linux, and it it slightly different on Windows.

Windows

On Windows, the application is called Command Prompt. To open it (on Windows 8.1), go to Apps screen (swipe up, or click down arrow at the bottom of the screen) and it should be located in Windows System section.

*Command Prompt* app on Windows 8.1 *Apps* screen

Command Prompt app on Windows 8.1 Apps screen

You can also search for it.

Searching for *Command Prompt* app on Windows 8.1

Searching for Command Prompt app on Windows 8.1

I could not find a keyboard shortcut to open Command Prompt.

By default, when you open Command Prompt, text similar to this will be displayed:

1 Microsoft Windows [Version 6.3.9600]
2 (c) 2013 Microsoft Corporation. All rights
3 reserved.
4 
5 C:\Users\IEUser>
*Command Prompt* app on Windows 8.1

Command Prompt app on Windows 8.1

You can ignore the first two lines. The last line, C:\Users\IEUser> is important. It is called command prompt (or just prompt). C:\Users\IEUser part is the folder where Command Prompt commands will be executed, also called path. IEUser is the name of the current user. The last character, >, separates path from the text that you will enter. Since both Mac and Linux use $ as separator, this book will use that character. In short, if an instruction in the book says you should run a Ruby file with this command:

1 $ ruby file_name.rb

Your screen should look similar to this:

1 Microsoft Windows [Version 6.3.9600]
2 (c) 2013 Microsoft Corporation. All rights
3 reserved.
4 
5 C:\Users\IEUser>ruby file_name.rb

Mac

On Mac, CLI application is called Terminal.app and you can find it in /Applications/Utilities folder.

`Terminal.app` in *Finder*

Terminal.app in Finder

A quick way to open it is by using built in Spotlight search. Press cmd + space or click magnifying icon and Spotlight will open.

Spotlight

Spotlight

Start typing terminal and you should see Terminal in search results.

*Terminal* app in *Spotlight*

Terminal app in Spotlight

I could not find a keyboard shortcut to open Terminal.

When you open Terminal, text similar to this will be displayed:

1 Last login: Thu Feb 27 16:11:16 on ttys002
2 imac:~ z$
*Terminal* app on Mac

Terminal app on Mac

You can ignore the first line. The second line contains several things. imac is machine name, ~ is the folder where Terminal commands will be executed, also called path. ~ is shortcut for /Users/z. z is the name of the current user. The last character, $, separates path from the text that you will enter. If an instruction in the book says you should run a Ruby file with this command:

1 $ ruby file_name.rb

Your screen should look similar to this:

1 Last login: Thu Feb 27 16:11:16 on ttys002
2 imac:~ z$ ruby file_name.rb

Ubuntu Linux

On Ubuntu Linux, the application is called GNOME Terminal. You can open it with keyboard shortcut Ctrl + Alt + T.

*Terminal* app on Ubuntu Linux

Terminal app on Ubuntu Linux

Alternatively, search for terminal and you should find it.

*Terminal* app in Ubuntu search

Terminal app in Ubuntu search

When you open Terminal, text similar to this will be displayed:

1 z@ubuntu1310:~$

Text contains several things. z is the name of the current user, ubuntu1310 is machine name, ~ is the folder where Terminal commands will be executed, also called path. It is shortcut for /home/z. (Again, z is user name of the current user.) The last character, $, separates path from the text that you will enter. If an instruction in the book says you should run a Ruby file with this command:

1 $ ruby file_name.rb

Your screen should look similar to this:

1 z@ubuntu1310:~$ ruby file_name.rb

Contributors

Changes

2014

0.9.2

  • 2014-03-08
    • Added chapters: Driver, Element, Getting Help, Headless, RVM, IRB, Ruby Toolbox, CLI
    • Running scripts from the book at Travis CI

0.9.1

  • 2014-01-25
    • Updated contributors, stats and todo.
    • Deleted unused files.
    • Added Quick Start chapter.

0.9.0

  • 2014-01-18
    • Published PDF, EPUB, MOBI and HTML at Leanpub.
    • Renamed the book from “Homebrewer’s Guide to Watir” to “Web Application Testing in Ruby (With Selenium and friends.)”
    • Installation chapters updated. Everything else removed from the book until updated.

2013

  • 2013-11-14
    • Moved HTML version to https://leanpub.com/watirbook/read
    • Changed license to BSD.

2012

  • 2012-11-28 Moved book repository to https://github.com/watir/watirbook and HTML version to http://watir.github.com/watirbook/
  • 2012-11-22 The book finally has a usable HTML version at http://zeljkofilipin.github.com/watirbook
  • 2012-11-21 Sold the first book via Leanpub.

0.8.0

  • 2012-11-20 Published PDF, EPUB and MOBI at Leanpub, The first time the book is published at Leanpub.
    • New landing page at https://leanpub.com/watirbook
    • New or improved chapters: About, Link, Button, Image, Checkbox…
    • Created table with all supported HTML elements.
    • A lot of small improvements and fixes.
    • Renamed the book from “Watir Book” to “Homebrewer’s Guide to Watir”.
  • 2012-11-17 Started working on the book again.
  • 2012-11-14 Sold the last book via PayPal.

2011

0.7.1

  • 2011-09-22 Published PDF, EPUB and MOBI at GitHub. Looks like this is the first time I have published free and paid versions of the book. Until now the entire book was available for free.

0.7

  • 2011-09-17 Published PDF, EPUB and MOBI at GitHub.

0.6

  • 2011-08-01 Published PDF, EPUB and MOBI at GitHub. Fixed images at GitHub.

0.5

  • 2011-07-23 Published PDF, EPUB and MOBI at GitHub.

0.4.2

  • ????-??-?? Started counting downloads.

0.4.1

  • 2011-05-28 Published PDF, EPUB and MOBI at GitHub. The first time the book is published as MOBI.

0.4

  • 2011-05-25 Published PDF and EPUB at GitHub.

0.3

  • 2011-05-25 Published PDF and EPUB at GitHub.

0.2

  • 2011-05-15 Published PDF and EPUB at GitHub.

0.3 installation

  • 2011-03-23 Published PDF and EPUB at GitHub.

0.2 installation

  • 2011-03-23 Published PDF and EPUB at GitHub. This version contains installation chapters only. The first time the book is published as EPUB.

0.1.3

  • 2011-03-15 Published PDF at GitHub. Created book landing page at http://watir.com/book

0.1.2

  • 2011-03-15 Published PDF at GitHub.

0.1.1

  • 2011-03-15 Published PDF at Dropbox and GitHub.

0.1

  • 2011-03-14 Published the book in PDF format at Dropbox. The first time the book is published as PDF and at at Dropbox. Sold the first book via PayPal.
  • 2011-03-11 Started working on the book again.

2010

  • 2010-04-27 Moved the book to GitHub. The first time the book is published as HTML and at GitHub.

2009

  • 2009-11-16 First commit to the Git repository.
  • 2009-11-08 Decided to write the book.

Stats

Updated 2014-01-25. Time is in hours, money in USD.

  • royalties: 2,797.18
    • PayPal: 1,273.21
    • Leanpub: 1,523.97 == Money that book readers have donated to the Watir project
  • hours worked: 215 (1.)
  • USD/hour: 13 (2.)
  • books sold: 377
    • PayPal: 144
    • Leanpub: 233
  • books downloaded for free: 18,580
    • GitHub: 12,983 (3.)
    • Leanpub: 5,597
  • records
    • maximum amount payed for one book: 100.00 (2012-03-06)
    • minimum amount payed for one book: 0.99 (8 times)
    • number of books sold in one day: 4 (2012-04-30, 2013-06-04)
  1. probably double, but this is what I have in my notes
  2. probably half, see (1.)
  3. a bit more, I started counting downloads from version 0.4.2

License


Copyright (c) 2009-2014 Željko Filipin All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name Željko Filipin nor the names of any other contributors to this software may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS’’ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


(based on BSD Open Source License)