Ruby on Rails
HowToTestRailsWithWatir

WATIR (Web Application Testing in Ruby) is a nice tool for functional testing using Internet Explorer automation (see http://wtr.rubyforge.org/). It is nice that you can see the IE window when the tests are running – the links are clicked, forms filled and submited. It is great to show this to our customers.

See Watir User Guide and API to get more details about Watir.

——

There is now a WatirOnRails plugin hosted at http://watir-on-rails.rubyforge.org/

——

Here is how to integrate Watir tests into Rails:

1) create test/watir directory in your rails app

2) create and modify test/watir/watir_setup.rb which starts webrick on test DB, creates IE instance and can perform some preparing tasks like user creation in test db, user login, language selection and so on.


END {
$ie.close if $ie
$test_server.shutdown
}

require File.dirname(__FILE__) + ‘/../test_helper’
require ‘dispatcher’
require ‘watir’
require ‘webrick’
require ‘webrick_server’

$BASE_URL = ‘http://localhost:3003/’
$USER_PASSWORD = ‘xxx’
$USER = User.new {|u|
u.username = ‘myuser’
u.new_password = $USER_PASSWORD
u.first_name = ‘Test’
u.last_name = ‘User’
}

def create_user
$USER.save! unless User.find_by_username($USER.username)
end

def start_test_webrick
options = {
:port => 3003,
:ip => “0.0.0.0”,
:environment => “test”,
:server_root => File.expand_path(RAILS_ROOT + “/public/”),
:working_directory => File.expand_path(RAILS_ROOT),
:server_type => WEBrick::SimpleServer
}

params = { :Port => options[:port].to_i, :ServerType => options[:server_type], :BindAddress => options[:ip], :AccessLog => [] } $test_server = WEBrick::HTTPServer.new(params) $test_server.mount(‘/’, DispatchServlet, options) trap("INT") { $test_server.shutdown } Thread.new do $test_server.start end

end

def start_and_setup_ie
$ie = Watir::IE.new
$ie.set_fast_speed
login
english_locale
end

def login
$ie.goto($BASE_URL + ‘users/login’)
$ie.text_field(:name, ‘user[username]’).set($USER.username)
$ie.text_field(:name, ‘user[password]’).set($USER_PASSWORD)
$ie.button(:name, ’commit’).click
end

def english_locale

  1. bindtextdomain(‘messages’, “#{RAILS_ROOT}/locale”, ‘en’, ‘utf-8’) # if gettext localization used
    $ie.goto($BASE_URL + ’settings’)
    $ie.select_list(:name, ‘settings[locale]’).option(:value, ’en’).select
    $ie.button(:name, ’commit’).click
    end

create_user
start_test_webrick
start_and_setup_ie

It stops webrick and closes IE when the tests are finished.

3) create your tests. For example incoming_mails_web_test.rb


require File.dirname(__FILE__) + ‘/watir_setup’

class IncomingMailsWebTest < Test::Unit::TestCase
self.use_transactional_fixtures = false
fixtures :incoming_mails

def setup $ie.goto($BASE_URL + ’incoming_mails’) assert_equal ‘Suppliers .:. Incoming mails’, $ie.title
  1. assert_equal “Suppliers .:. #{_(‘Incoming mails’)}”, $ie.title # if gettext localization used
    assert $ie.contains_text(‘User: Metada Admin’)
    end

    def test_navigation
    $ie.link(:text, ‘Incoming mails’).click
    assert_equal ‘Suppliers .:. Incoming mails’, $ie.title
    end
    end

Notice that transactional fixtures must be disabled to make it work properly, because the browser is accessing the DB through webrick which is not in the same transaction as the test itself.

4) create rake task for running Watir tests. Create lib/tasks/test_watir.rake


desc “Run the watir web tests in test/watir”
Rake::TestTask.new("test_watir") { |t|
t.libs << “test”
t.pattern = ‘test/watir//_test.rb’
t.verbose = true
}
task :test_watir => [ :prepare_test_database ]

5) add test_watir to the default rake task to have watir tests to be run together with unit and functional test by creating lib/tasks/default.rake


task :default do # adds :test_watir task to default (:test_units and :test_functional are already there)
Rake::Task[:test_watir].invoke rescue got_error = true
raise “Test failures” if got_error
end

The watir_setup.rb makes the tests to run faster, because webrick and IE are initialized at the begining. But you must keep in mind
the fact that the information stored in http session can influence/interfere the tests, so you have to adjust it to your test scenarios.

Enjoy!
Karel Miarka

Another example of CRUDL test for your inspiration (also with pushing js confirm button at delete)

require File.dirname(__FILE__) + '/watir_setup'

class InternalSequencesWebTest < Test::Unit::TestCase
  self.use_transactional_fixtures = false
  fixtures :internal_sequences
  
  def setup
    $ie.goto($BASE_URL + 'internal_sequences')
    assert_equal 'Suppliers .:. Internal sequences', $ie.title
    assert $ie.contains_text('User: Metada Admin')
  end
  
  def test_navigation
    $ie.link(:text, 'Internal sequences').click
    assert_equal 'Suppliers .:. Internal sequences', $ie.title
  end
  
  def test_listing
    assert $ie.contains_text('Partner\'s Sequence')
    assert $ie.contains_text('PRN-0024/05')
    
    assert $ie.contains_text('Payment Requests Sequence')
    assert $ie.contains_text('PRQ-0004')
    
    $ie.link(:text, 'Name').click unless $ie.table(:id, 'listingTable').row_values(2)[1] == 'Name *'
    t = $ie.table(:id, 'listingTable')
    assert_equal 7, t.row_count
    assert_equal "Incoming Mails Sequence", t.row_values(3)[1]
    assert_equal "INMAIL-0004", t.row_values(3)[7]
  end

  
  def test_validation
    $ie.link(:text, 'Create').click
    assert $ie.contains_text('New Internal sequence')
    $ie.button(:name, 'commit').click
    assert $ie.contains_text('2 errors prohibited')
    assert $ie.contains_text("Name can't be blank")
    assert $ie.contains_text("class must be selected")
  end

  def test_create
    $ie.button(:name, 'create').click
    assert_equal 'Suppliers .:. New Internal sequence', $ie.title
    $ie.text_field(:name, "internal_sequence[name]").set('New Test Sequence')
    $ie.select_list(:name, "internal_sequence[for_item_class]").select('Partner')
    $ie.button(:name, 'commit').click
    assert $ie.contains_text("Internal sequence was successfully created.")
    $ie.button(:name, 'list').click
    assert_equal 8, $ie.table(:id, 'listingTable').row_count
  end

  def test_edit
    $ie.link(:url, $BASE_URL + 'internal_sequences/edit/1').click
    assert $ie.contains_text("Change Internal sequence")
    assert_equal "Partner's Sequence", $ie.text_field(:name, 'internal_sequence[name]').value
    $ie.text_field(:name, 'internal_sequence[name]').set('Changed PRN Sequence')
    $ie.button(:value, 'Update').click
    assert $ie.contains_text("InternalSequence was successfully updated.")
    assert $ie.contains_text("Changed PRN Sequence")
    assert_nil $ie.contains_text("Partner's Sequence")
    $ie.button(:value, 'List').click
    assert $ie.contains_text("Changed PRN Sequence")
  end

  def test_delete
    $ie.link(:url, $BASE_URL + 'internal_sequences/edit/1').click
    assert $ie.contains_text("Change Internal sequence")
    assert_equal "Partner's Sequence", $ie.text_field(:name, 'internal_sequence[name]').value
    Thread.new { system("rubyw -e 'require \"watir/WindowHelper\"; WindowHelper.new.push_confirm_button_ok'") }
    $ie.button(:value, "Delete").click
    assert_equal 6, $ie.table(:id, 'listingTable').row_count
  end
  
  def test_list_ordering
    $ie.link(:text, 'Name').click
    assert_equal "Name ^", $ie.table(:id, 'listingTable').row_values(2)[1]
    assert_equal "Payment Requests Sequence", $ie.table(:id, 'listingTable').row_values(3)[1]

    $ie.link(:text, 'For item class').click
    assert_equal "For item class *", $ie.table(:id, 'listingTable').row_values(2)[2]

    $ie.link(:text, 'Prefix').click
    assert_equal "Prefix *", $ie.table(:id, 'listingTable').row_values(2)[3]
    
    $ie.link(:text, 'Digits').click
    assert_equal "Digits *", $ie.table(:id, 'listingTable').row_values(2)[4]
    $ie.link(:text, 'Digits').click
    assert_equal "Digits ^", $ie.table(:id, 'listingTable').row_values(2)[4]
  end

  def test_list_filtering
    $ie.text_field(:name, 'filter[name]').set('In*')
    $ie.button(:name, 'set_filter').click
    assert_equal 4, $ie.table(:id, 'listingTable').row_count
    
    $ie.text_field(:name, 'filter[digits#max]').set('5')
    $ie.button(:name, 'set_filter').click
    assert_equal 3, $ie.table(:id, 'listingTable').row_count

    $ie.button(:name, 'clear_filter').click
    assert_equal 7, $ie.table(:id, 'listingTable').row_count
  end

end