Creating automated test scripts with Ruby and WATIR

To document the general process of creating automated test scripts for web applications with Ruby and the WATIR testing module. The intended audience of this document is QA engineers/testers that are going to be either creating automated test cases for their applications or testers that are going to be running and maintaining already created tests. This document assumes that the reader is already familiar with the basic methods and syntax of the Ruby language and the components of an HTML based application (links, forms, JavaScript, etc..)


Ruby is not a difficult language to learn, and someone having experience with Python, C++, JAVA, or even plain old C should be able to pick it up relatively quickly. Please refer to the reference appendix at the end of this document for links to a few Ruby documentation/tutorial sites.


Here are a few considerations and limitations to using the WATIR module for Ruby to test web based applications. The initial, most important consideration is that the module is limited to testing on the Internet Explorer 5.5 or greater platform. The WATIR module is not implemented to work with Netscape, Opera, Firefox, or any other type of browser. This means that cross browser testing of applications is not possible (nor was it the intention of the WATIR designers). The second, more a limitation than consideration, is that there is no recorder for WATIR. Most automated testing tools come with a recorder to help produce the bulk of the automated test scripts. WATIR is solely a library of common IE Browser methods and objects to be used in the manual process of handwriting scripts. Another limitation of building automated test scripts with WATIR is that there are no external tools, no spies or object analyzers to help identify the types of objects in a page and the methods available to those objects. WATIR does provide methods to dump available links, images, URLs, forms, etc. during replay. This means that the scripting process becomes a trial by error process, which is not necessarily a bad thing.


Before building any automated test scripts with any tools there is a preparation phase that must be completed. One of the most commonly overlooked items when constructing automated functional tests is that they are simply extensions of manual test cases. Many automated functional testing efforts fail because they are not based on properly built manual test cases, and it is this foundation that makes both manual and automated testing both maintainable and effective. It is critical to have a wide scope when it comes to understanding how the application is used and what business processes should be tested.

Understand the application under test (AUT)

Gather functional requirements (if they exist)

The first process to building either a manual or automated test suite is to understand the application to be tested. The easiest way to understand how an application needs to be tested is to understand the requirements to which it was built. Documenting and maintaining functional requirements is more common now than in the past. If the application has properly maintained functional requirements then these are a very good place to start understanding what the application should do and how the users are intended to use it.

Interview functional experts

In addition to reviewing functional requirements, or in the case that they’re not available, functional business processes and test case design information can come from the actual developers and users of the application. This process usually involves talking to application developers, architects, end users, functional experts, and business analysts. The first process to building either a manual or automated test suite is to understand the application to be tested. This process usually involves talking to application developers, architects, end users, functional experts, and business analysts. It is critical to have a large, diverse audience when it comes to understanding how the application is used and what business processes should be tested. Developers often have a very different perception of how an application is commonly used when compared to the actual users or functional analysts.

Document the testing business processes into manual test cases

All tests processes, weather manual or automated, should have an associated step by step test case as its foundation. Without a clear, step by step process the test cannot be maintained and estimations of code coverage and test completion cannot be made. It is not acceptable to think that the actual automated test script is in itself the documentation, because reverse engineering an automated script is time consuming and prone to numerous errors. There is an example of a standard manual test case in the appendix of this document.

Create a process for handling required dynamic data

Many applications consume or create data in their normal operation. For the purposes of functional testing, both automated and manual, the state of data in the system under test should be the same from test cycle to test cycle. Depending on what exactly the test case does, weather it consumes , produces new data, or both, there should be a data preparation and cleanup script to prepare the AUT for a test cycle and then repair the AUT after the cycle has completed. The data preparation and cleanup scripts should be run separately from the test suite in the case of a failure which breaks the test cycle. The process of handling data preparation and cleanup should be documented just like any other manual test case, as it is a pre/post requisite to the other test cases.

Determine which test cases are candidates for automation

Not all test cases are necessarily good candidates for automation. Typically the most repetitive and simplest processes are good initial candidates. Processes which involve complex data analysis and decisions by the tester are not the best cases to use as initial automation candidates. Start with test cases that have tedious, UI intensive, but condition less navigation procedures. Move to cases that involve repetitive creation and deletion of data that can be automated through the application or direct database access. Finally try to create a suite of automated tests that cover all of the major functionality (mission critical, most used, and revenue impacting) of the application.

Create a framework for automating the test case

Once a specific business process is identified as a required test and documented in step-by-step format then the process of creating an automated test script from a manual test case can begin. Take the documented test case and copy its contents into an empty Ruby script file. Turn the documented steps into comments and divide them into individual sections. In addition to building a framework from the manual test case, the script should be divided into sections based on data consumption or production. If the script generates waste data or uses seed data and fails for some reason before the process is complete then it is wise to have it try to recover gracefully and remove or complete the data that was started.


The implementation process for creating automated test scripts using Ruby and WATIR is
  • The test cases chosen for automation can be scripted by following a group of common procedures.
  • Initialize the IE object or connect to an existing IE window
  • Navigate to the initial application URL
  • Perform verification step
  • Dump the HTML/Links/Forms/Images based on the next step in the script
  • From the dumped information extract the link name, form information, or image name required for the next step
  • Perform action on the link, form, or image.
  • Repeat steps 3 – 6 to navigate through the application. Remember that each step should be followed by a verification to determine that the action was successful.

It is tremendously important to the success and readability of error messages that each step has a corresponding verification. If the verification fails, a screenshot may be captured and dumped to a log or at least an error message indicating what was expected and what actually appeared can be generated. Otherwise a typical error only contains the information regarding the failed step, such as Link not found or Form field xxx not available.

It is up to the scripter to determine how descriptive and helpful the error messages from their tests will be. Poorly created test scripts will require that the tester repeat the automated test case manually in order to determine what happened to cause a failure, while properly created test cases should provide enough information in the form of screenshots, logs, and error messages to be able to determine what happened.

Technical Implementation

Initialize IE object

Start IE by either initializing a new IE browser or attaching to an already existing one.

$ie =
$ie = IE.attach ( :title, “…”)

Go to initial URL

Start testing an application by going to a specific URL. All testing begins in this manner. It might also be necessary to navigate to a specific URL during a test case for various reasons.

$ie.goto (“http://....”)

Verify content

Content verification is most easily done by trying an assert with a content or object check. Check that a form exists, a button of some kind is available, a page contains some text, etc… Because there is no keyword “TRY” in ruby, we use instead the begin, rescue keys to accomplish the same task.

    assert ($ie.pageContainsText(“Logged out Successfully”) )
    assert ($ie.form(:name, “Login”).exists )
    $ (“Test step 5 passed!”)
    $log.error (“Test step 5 failed”)
    $ (“Error text was : “, ie.text() )

Dump links, images, or forms if necessary

While creating a script it is not always very easy to determine the exact name of a link, image, format of a URL, field names in a form, etc.. To help with this it is possible to have the script dump these objects to stdout or the log file while it’s playing. This is information that is helpful with building a script or debugging an error ,but should not be active in a finished version (as it will render the logs extremely long and essentially unusable) Outputting data can be done to either the logs (if log4r is being used) or to the standard out. puts … outputs to standard out

$ (), $log.error (), $log.warning () all output to the log4j log file.
Show links: 
puts $ie.show_links()
Show all forms: 
puts $ie.show_forms()
Show images: 
puts $ie.show_images()
Show all objects : 
puts $ie.show_all_objects()
Show complete page with all frames: 
puts $ie.html()


Click on a link

Activating a link can be done through either its name or direct URL. When working with JavaScript the only way to access a link is through its URL or if it is an image link, its src or alt image tag (see click on image) The method click is one of the WATIR standard class methods that is used to activate a link.

$ (:text, “Portfolio”).click
If the text of a link does not remain constant but its location does we can use the attribute index to access the link (use $ie.show_links() to find the index number of various links):
$ (:index, 20).click
For JavaScript, the URL (or href tag) of the link can be used :
$ (:url, /javascript:deleteClient\(\d, .*/).click
Note that the URL must be encoded (spaces become %20, etc) but can make use of regular expressions as in the example above.


Click on an image

Clicking on an image is almost exactly the same as clicking on a link except the additional tags src and alt are available. Note that the attribute name is the same as a link’s attribute text.

$ie.image (:name, “login.gif”).click

Complete a form

Completing a form is probably the most difficult step that needs to be performed in the navigation portion of the scripting (programming logic can be complex of course but is not in the scope of this document) You must know the name of any text fields, radio buttons, pick lists, or any other objects that are part of the form. Use ie.show_all_objects() to get these.
$ie.textField(:name, “username”).set(“testuser”)
$ie.textField(:name, “password”).set(“testpass”)

Submit the form by “clicking” on the submit object.

$ie.button(:value, “Login”).click

Quick Guide to Common Objects

Handle a pop up dialog


new, back, forward, send_keys, goto, close, refresh, minimize, maximize, restore






$ie =

Show Functions

showFrames, show_frames, showForms, show_forms, showImages, show_images, showActive, show_active, showLinks, show_links, showAllObjects, show_all_objects, show_tables, buttons, show_spans, show_labels,


$ie.buttons.each {|m| puts m}

Child Objects

frame, textField, span, row, selectBox, radio, select_list, text_field,

checkBox, button, checkbox, link, cell, form, table

$ie.frame(:index, 1)

$ie.textField(:name, “q”).set(“Test”)

$ie.button(:value, “OK”).click

$, “Happy link”).click

$ie.select_list(:name, “Day”).select_value(“today”)

Object Lists

checkboxes, labels, images, spans, radios, select_lists, text_fields, buttons, tables, links

$ie.checkboxes.each {|m| puts m}

$ie.radios.each {|m| puts m}

$ie.links.each {|m| puts m}


getText, text, getStatus, status, getHTML, html, pageContainsText, contains_text, title

if ($ie.text.match(“Hallo”) != nil)

puts ‘Passed!’


puts “Failed!’


Returns : True

Misc Functions

getImage, getIE, enable_spinner, set_fast_speed, enable_spinner=, wait, popup, down_load_time, getLink, set_slow_speed, getTablePart, focus, url



text name=question id= value= alt= src=


textField, text_field

Discovery technique




$ie.textfields.each { |textfield| puts textfield}

Relevant Methods

value, value=, clear, click, send, set, enabled?, flash, html, append, getContents, focus, verify_contains

Most used methods

value, set, append, verify_contains. Sometimes value= when having trouble with popups.


$ie.textField(:name, “q”).value=”Sam”

$ie.textField(:name, “q”).append(“I am”)

$ie.textField(:name, “q”).value

Returns : “Sam I am”

$ie.textField(:name, “q”).getContents

Returns : “Sam I am”

$ie.textField(:name, “q”).set(“Happy”)

$ie.textField(:name, “q”).verify_contains(“app”)

Returns : true



submit name=btnG id= value=Google Search alt= src=



Discovery technique



$ie.buttons.each { |button| puts button }

Relevant Methods

value, display, click, send, enabled?, flash, html, disabled, freeze, focus

Most used methods



$ie.button(:name, “btnG”).click

$ie.button(:name, “btnG”).value

Returns : “Google Search”



" name= id= innerText=Business Solutions href="



Discovery technique



$ie.links.each { |link| puts link }

Relevant Methods

value, title, click, link_has_image, enabled?, flash, html, href, src, text, focus, name, innerText, equal?

Most used methods



$, “Business Solutions”).click

$, “Business Solutions”).enabled?

Returns : true

$, “Business Solutions”).link_has_image

Returns : false


Notes : A link appears without type when doing show_active or show_all_objects. Note in this example it starts with empty “. Also the attribute innerText is really refered to as :text in the object description, as exemplified in the examples.



select-one name=logonForm:_idJsp15:0:Question id=logonForm:_idJsp15:0:Question value=What is your cat's name?



Discovery technique



Relevant Methods

option, select, value, getSelectedItems, click, enabled?, flash, select_item_in_select_list, html, getAllContents, select_value, clearSelection

Most used methods

select, getSelectedItems, getAllContents, select_value, clearSelection


$ie.select_list(:name, /Question/).value

Returns : “What is your cat’s name?”

$ie.select_list(:name, /Question/).getAllContents

Returns array : ["What is your favorite color?", "What is your cat's name?"]

$ie.select_list(:name, /Question/).select_value (“What is your cat’s name?”)

Interesting :

$ie.select_list(:name, /Question/).select_value ($ie.select_list(:name, /Question/).getAllContents[1] )

This would get the 2nd item in the select list, (by index, not exact text)



checkbox name=option1 id= value=Milk alt= src=




Discovery technique



$ie.checkboxes.each {|checkbox| puts checkbox}

Relevant Methods

value, clear, click, set, enabled?, checked?, flash, html, isSet?, getState

Most used methods

click, set, clear, checked?


$ie.checkbox(:name, “Milk”).set

$ie.checkbox(:name, “Milk”).isSet?

Returns : true

$ie.checkbox(:name, “Milk”).click

$ie.checkbox(:name, “Milk”).isSet?

Returns : false

$ie.checkbox(:name, “Milk”).clear

$ie.checkbox(:name, “Milk”).isSet?

Returns : false



radio name=group1 id= value=Butter alt= src=



Discovery technique



$ie.radios.each { |radio| puts radio }

Relevant Methods

value, clear, click, set, enabled?, checked?, html, isSet?, getState

Most used methods

set, checked? (clear, carefully)


$, “Butter”). Set

$, “Butter”).isSet?

Returns : true

Note: Clear is not a normal function for radio buttons. To clear a button you should push another one. Radios are not like checkboxes.

$, “Butter”). Clear



HTML Document name=message id= src=frameshop-intro.html



Discovery technique



Relevant Methods

Note : A frame is treated as just another IE window. You can reference the frame by name or by index and it is common to create another variable to reference it. It is also common to have frames within frames.

$f1 = $ie.frame(:name, “message”)

$f2 = $ie.frame(:index, 1)


Returns all objects in the frame, like a normal ie object.

Most used methods


Technical Considerations

Handle a pop up dialog

Because many applications perform client side verifications using java script and other technologies popup windows are common occurrences in testing web applications. There are two main types of popups, those generated by Internet Explorer and those generated by the application itself.

Internet Explorer generates popups that usually only occur once. These are warning type windows that often occur only one time telling a user that they’re about to submit non-encrypted data, switching to an encrypted page, submitting a form, or asking to remember a password. It is recommended that these dialogs are turned off in the configuration of IE and do not need to be handled in the script. Javascript and ActiveX generate popups that ask the user to confirm an action, indicate invalid or unexpected data, or tell the user if there is a problem with the desired action. Because IE does not consider a page completely finished loading until the Javascript dialog is closed an IE method in a Ruby script will not complete until the dialog is closed.
This presents a problem because the code to close a Javascript dialog cannot be executed until the previous step is finished, and the previous step will not finish until the Javascript window is closed.

To remedy this situation, any IE action which may produce a javascript popup should be executed in it’s own separate thread. This allows the test script to continue execution and interact with the javascript dialog while the other thread is waiting for the window to be closed. Make the existing step run within its own thread


Now click on the javascript confirmation dialog that appears:
Clicker.clickJavaScriptDialog (“OK”)

Note the addition of Thread {} around the original step and the two subsequent steps to handle the JavaScript dialog.

Hidden Frames
Sometimes, although show_frames returns 0 many or all of the objects in a browser page may be contained within a hidden frame. If you wind up with a page that visibly contains objects but returns a subset or no objects at all, check to see if they lie in a hidden frame. Use the following to access individual browser frames :

$ie.frame (:index, 1)…

This will access frames by index, the main frame being frame 0 and first sub frame being frame 1.

Interactive Scripting

After becoming comfortable with the process of creating basic scripts with Ruby and WATIR you will find that scripting can become very tedious and time consuming due to the lack of a recorder which is available in most automated testing tools. One way to help relieve the tedium involved with the edit, replay, and debug cycle is to work on scripts with a parallel running interactive ruby interpreter.

The interpreter allows you to test code line by line and interact with an existing browser. You can use methods already discussed such as show_links, show_all_objects to identify the objects on a displayed page rather than having to run a script from the very beginning to output those details.

An additional method is available using an interactive shell, which is the show_active method. This can help identify Use the show_active method to identify the object that is currently in focus in the browser.

puts $ie.show_active()

will show the details of the object currently in focus in the attached browser.


Tips and Tricks

Inline substitution :

Set up the todaysDate variable with the date in the format monthdayyear i.e. 04212006

$todaysDate ="%m%d%Y") 

Replace the date in the string with the variable todays date. This is using inline substitution

pimsSQL "delete from blotter_funds where name ='#_1' and prime_broker ='Bobby Brown'"

OR you can replace the date in the string with string concatenation. I prefer the previous method.

pimsSQL "delete from blotter_funds where name ='" + $todaysDate + "_1' and prime_broker ='Bobby Brown'"