try another color:
try another fontsize: 60% 70% 80% 90%
Wolfe Web Services

Testing Multiple Browsers with Selenium and Cucumber

Testing web applications can be a difficult task with the many complexities involved with current web technologies. At one time it was possible to test web applications without needing to rely on javascript at all. For this you could leverage java's htmlunit or even httpunit to write unit tests based on the source of a webpage. Javascript support in htmlunit was not the least bit usable on the web applications that I tested at my previous job, so it was completely off the table for the current project I'm responsible for testing. This application is fully ajax based, and thus we've had to use something with better support for javascript. Our solution originally was to use a combination of Watir and FireWatir so that we could test both IE and Firefox. I had some issues getting it to work correctly though, the api between the two is not 100% consistent yet (last I checked anyways). I then realized that the smart folks working on the Selenium project had added a new tool called Selenium Remote Control to the mix. With the Selenium remote control you no longer have the prerequisite of having the selenium javascript installed on the server application. I wanted our testing environment to not rely on server side extras being installed unless absolutely necessary, so the obvious solution was to leverage Selenium Remote instead. Selenium remote creates a proxy server which the client connects to, and uses to intercept javascript calls made by the client browser. This provides a workaround for javascript's same origin policy. To use selenium you must start up the selenium remote control server first. If you have installed the Selenium rubygem you can do this by simply typing

$ selenium

in a shell window Install the gem using the following: (note the case sensitive Selenium)

$ gem install Selenium

Note that the last time I checked the selenium jar file bundled with the Selenium gem is crap and will not work correctly. Instead use the latest build from the selenium site. Download the latest jar here: http://seleniumhq.org/download/ (I actually downloaded a more recent nightly release and it seemed to be more stable than the one listed on the home page -- current home page lists 1.0 beta2) Anyways, once you've done this you need to take that jar file and copy it to your where your current Selenium gem has the selenium-rc jar file. On my system it was in this directory: C:\ruby\lib\ruby\gems\1.8\gems\Selenium-1.1.14\lib\selenium\openqa and the filename is selenium-server.jar.txt Supposedly there was an issue with a file name ending in .jar in ruby so they gave the file a .txt extension (who knows?). Anyways, you can make a backup of that one and copy the newest version there and give it the same name as the old one. From there you can just type selenium at the command prompt and the server will start up for you. One option I usually run with is -singleWindow when I'm trying to see what is going on (its very hard to see when the windows are real small). Anyways, on my system I also have the selenium-server.jar file installed at: c:\selenium-rc\selenium-server.jar which is where I run it from within my custom rake tasks. If you use the rakefile I've posted below to run your tests, you won't need to bother starting selenium first. In fact, if you start selenium before you run the rake tasks, the selenium server you start up will be immediately shut down by the rake tasks. The rake tasks starts up its own server so that you don't have to remember to start up selenium first. Its nice to be able to run cucumber tests one a time when you are developing though, and for those times you'll want to start up selenium without messing with rake. Here is the rakefile i'm currently using which will run your cucumber tests through each browser (if the test uses a browser).

 require 'cucumber/rake/task' require 'selenium/rake/tasks' #require 'rubygems' #add this if you don't have rubygems added automatically # Change these to specify which browsers on which # platforms you want to cover @win_browsers = ["*iexploreproxy","*firefox"] @osx_browsers = ["*safari", "*firefox"] @linux_browsers = ["*firefox"] # Supported platforms @platforms = {"win"=>"Windows", "osx"=>"OS X", "linux"=>"Linux"} if RUBY_PLATFORM.downcase.include?("darwin") @platform = 'osx' elsif RUBY_PLATFORM.downcase.include?("mswin") @platform = 'win' elsif RUBY_PLATFORM.downcase.include?("linux") @platform = 'linux' end if ENV["SELENIUM_RC_JAR"] # User override SELENIUM_RC_JAR = ENV["SELENIUM_RC_JAR"] elsif File.exists?(File.dirname(__FILE__) + \ "/vendor/selenium-server/selenium-server.jar") # Bundled version included with project SELENIUM_RC_JAR = File.dirname(__FILE__) + \ "/vendor/selenium-server/selenium-server.jar" else SELENIUM_RC_JAR = case @platform when 'osx' then "/var/lib/selenium/selenium-server.jar" when 'linux' then "/var/lib/selenium/selenium-server.jar" when 'win' then "C:/selenium-rc/selenium-server.jar" else raise 'Unsupported Operating System' end end if not File.exists?(SELENIUM_RC_JAR) raise "File Not Found -- SELENIUM_RC_JAR" end desc "Invoke behaviours on all browsers on specified platform" task :test do @browsers = case @platform when 'win' then @win_browsers when 'osx' then @osx_browsers when 'linux' then @linux_browsers end puts "Running tests for the #{@platforms[@platform]} platform" Rake::Task[:"selenium:rc:stop"].execute [] rescue nil begin Rake::Task[:"selenium:rc:start"].execute [] @browsers.each do |browser| puts "executing on browser" + browser.to_s + "\n" @current_browser = browser ENV['SELENIUM_BROWSER'] = browser year,month,day = Date.today.strftime("%Y,%m,%d").split(",") dir = "reports/#{year}/#{month}" FileUtils::mkdir_p(dir) filename = "#{dir}/#{day}-#{browser.delete "*"}.html" ENV['CUCUMBER_OPTS'] = "--format progress --format html \ --out=#{filename} features" begin Rake::Task[ :run_browser_tests ].execute() rescue RuntimeError puts "Error while running task" end end ensure Rake::Task[:"selenium:rc:stop"].execute [] end end Cucumber::Rake::Task.new(:'run_browser_tests') do |t| #t.cucumber_opts = "--format progress --format html \ --out=#{filename} features" end Selenium::Rake::RemoteControlStartTask.new do |rc| rc.port = 4444 rc.timeout_in_seconds = 30 rc.background = true rc.wait_until_up_and_running = true rc.jar_file = SELENIUM_RC_JAR rc.additional_args << "-singleWindow" end Selenium::Rake::RemoteControlStopTask.new do |rc| rc.host = "localhost" rc.port = 4444 rc.timeout_in_seconds = 30 rc.wait_until_stopped = true end desc "Restart Selenium Remote Control" task :'selenium:rc:restart' do Rake::Task[:"selenium:rc:stop"].execute [] rescue nil Rake::Task[:"selenium:rc:start"].execute [] end task :default => [:test] 

Then in your env.rb file do this:

 Before do profile = ENV['PROFILE'] || 'default' c = YAML.load_file('selenium.yml')[profile] browser_type = ENV['SELENIUM_BROWSER'] || "*firefox" @browser = Selenium::Client::Driver.new(c['server_host'], \ c['server_port'], browser_type, c['root_url'], c['timeout']) @browser.start end 

Which means you'll need a selenium.yml file like this (mine is in the same directory as the rakefile):

default: 
  server_host: localhost  
  root_url: http://server-ip-address
  server_port: 4444
  timeout: 28

And that should be it. Now just put your feature tests in a features directory and then put all your step definitions in files in a step_definitions directory.. Your tree should end up looking like this:

path/to/project/feature_tests/Rakefile.rb
path/to/project/feature_tests/selenium.yml
path/to/project/feature_tests/features/my_feature.rb
path/to/project/feature_tests/features/step_definitions/my_feature_steps.rb
path/to/project/feature_tests/features/support/env.rb
path/to/project/feature_tests/features/lib/SomeClassToAbstractFeature.rb

Thats how I have my tests structured and it seems to be working out good.