Archive for the ‘Software’ Category.

Advanced Test Automation – Generate your own css locators using nokogiri

Some of the pages that I test have hundreds of check boxes. I needed a way to generate the locators to use in selenium and create classes to use those locators.
This is an example of a class that contains selenium css locators for navigation links

class Navigation
  def initialize * browser
    @location =  "css=a:contains(\"Location\")"
    @amenities =  "css=a:contains(\"Amenities\")"
    @photos =  "css=a:contains(\"Photos\")"
    @contact =  "css=a:contains(\"Contact\")"  
    @further_details =  "css=a:contains(\"Further Details\")"
  end
  attr_accessor :location, :amenities, :photos, :contact, :further_details
end

To use this class I would new it up and use standard selenium commands. This is how I would navigate to the amenities page

navigation = Navigation.new
browser.click amenities

The spec below demonstrates how to get data you need using nokogiri. I want to click an anmenity check box with the label beach whose input name is “amenity_1_1_6”. I could click this checkbox with this command browser.click “amenity_1_1_6”, but I want to have a way to store all of the amenities on the page with the variable named by their label.

require "spec"
require "nokogiri"
describe "Find elements to use as locators in a web test" do

  it "should find the value of name for the input element and the text in span" do
    sample_html = ''
    attribute_name=""
    attribute_value=""
    doc = Nokogiri::HTML(sample_html)
    doc.css("label").each do |check_box|
      attribute_name =  check_box.text
      attribute_value = check_box.children.css("input")[0]["name"]
      attribute_name = attribute_name.strip
      attribute_name = attribute_name.to_s.downcase

    end
    attribute_name.should=="beach"
    attribute_value.should=="amenity_1_1_6"
  end
end

To take this further I can print the contents of my class file to generate my locators from this spec.

puts "@#{attribute_name} = \"#{attribute_value}\""

Rubymine 2.0.2 and the gem bundler

I use bundler 0.9.6 with all of my projects. Checkout my earlier post on how to add bundled gems to your project.  I am excited about the updated bundler support in Rubymine 2.0.2 for a few reasons.

Rubymine can easily find my bundled gems in my Gemfile and attach gems to my project with suggestions. Now I can Go To Declaration for all of my attached gems.

Attech gems from the Gemfile

Attech gems from the Gemfile

I don’t have to navigate to my project through the terminal to unlock the Gemfile and add a new gem. I can use the bundler menu for all bundler functions.

Bundler 9.0 options

Bundler 9.0 options

I can get feedback from my bundler commands inside the Rubymine run window.

Unlocking through rubymine

Unlocking through rubymine

Deploy your Ruby project with out the need to install gems.

I have been using the gem bundler lately with my ruby projects to deploy to team city build agents.  My project needed to run on multiple OS X and Cent OS systems without having to manage ruby gems manually.  The bundler gem repository is located on github at http://github.com/carlhuda/bundler.  There are a few different ways to use it so I decided to write about how use it.  The short answer is that I lock and pack the gems I need, and fall back to sudo installed gems when needed. I am using bundler 0.9.6. The prerequisite is that you gem install bundler.

Use a begin / rescue to try to require the environment file.
If the file is not found then execute the bundle install command

begin
  # Try to require the preresolved locked set of gems.
  require File.dirname(__FILE__) + "/../.bundle/environment"
rescue Exception=>e
  # Fall back on doing an unlocked resolve at runtime.
  if (!system("bundle install"))
        puts $?
  end
end
require File.dirname(__FILE__) + "/../.bundle/environment"

On the first run the bundle install command will execute
This operation will create a .bundle directory in the root of your project that will contain an environment.rb file that will contain all of your gem configuration information.
All your files need to do, is include this environment file and they will have access to your bundled gems. If you run the bundle install command twice in a row it will not install again if your gems have already been installed.

Three step process to setup your bundler.
Create a Gemfile that will list what gems to install. Lock your gem file and then pack your gems.
Check out the information on github to see the format of the gemfile. You can use the bundle init command to create the Gemfile for you in the base of your project. Now run the bundle lock command. A Gemfile.lock file will be created you will check this in to your version control system. Next you need to pack the gems. Run the command bundle pack. You will see that a vendor/cache directory will be created. You will need to check in the vendor cache directory into your VCS. Now when your deploy your code will self execute the bundle install command making all of the gems you need available too your project.

Working with compiled gems
I really like using the Nokogri gem but I foud out that when I execute my project with in the Team City execution environment with a Cent OS build agent, that Nokogiri cannot build correctly because it cannot access the system files it needs. The work around is to list nokogiri in your Gemfile, but don’t check in the gem into the gem cache. Install it as the user that will be executing your scripts so it will be available to your execution environment. The bundler will resolve the dependency to your system installed gem.

That was a quick rundown of what you can get using the bundler and how to set it up. I will continue to post updates as I come across more challenging situations. For now I still have to touch every machine that needs odbc ruby configuration and nokogiri.

Don’t miss this important note if your planning to run tests against Internet Explorer using Selenium Grid

I tried to run tests in parallel against IE using the selenium grid for a few days before I found this important message on the selenium grid FAQ.
Picture 9

If you try to run multiple selenium remote controls for IE on one machine it will work for a while.   Your test will execute without any problems, but then you start getting sporadic error messages from IE.  I assumed that the xpath expressions I was using for the tests in Firefox were throwing errors in IE.  I tried different configurations for security settings in IE for a while and then I finally found out that it was a memory sharing issue that prevents the selenium remote from launching more than one IE instance.  For now I am just requesting more VMs to run a single IE remote on each.  I use ruby with deep test to run test in parallel on the grid.  I configure deep test to run 6 tests at a time, so I would only need 6 VMs for IE to run.

It puzzling to me that Watin tests run in parallel against IE without any problems on the same machine, but selenium tests cannot.  For now I will add more VMs and wait for Selenium Grid 1.2  to fix the IE problem.

Run selenium ruby scripts in parallel from Team City.

I recently found out why my automated tests run in parallel from my workstation, but then run in sequence from a team city build agent.  It all comes down to the rake runner in team city.  Team city uses a customized rake runner that extends rspec’s spec task.  You get all of the per test reporting, graphing and historical information from team city’s customized rspec reporting.  All this is great if you don’t mind running your tests in sequence, but If your using team city to launch automated web test using the selenium grid this is bad news.

I use a rake file to control the execution of my ruby selenium scripts. I modeled it from the ruby example in the selenium grid distribution. What is important to know about the run in parallel rake task is that it is not your normal rake task. It is first a rspec spec task.  This is a test runner from rspec that allows you to use a rake task to run specs. Not only is it a spec task, it also has been overridden by deep test, the software package that adds parallelization.  Since the spec task is actually deep test’s spec task and not the rspec spec task there are dependencies on what version of rspec deep tests needs.  You must run with rspec 1.1.8 so that the spec task that deep test overrides will work correctly.

So what happens when you run your deep test spec task from team city with their rake runner?   Deep test cannot launch your tests in parallel because Team City is using their customized spec task.  The solution is to use the command line runner to launch your rake task for the selenium grid, then your spec task will have access to the correct rspec gem for deep test to use as a spec runner.

Essentials of getting started with Selenium Grid and Ruby.

I have been running test/unit scripts on the grid for a while now and I was trying to remember where I got my test/unit syntax from.  I was looking to create a live template to create new test scripts in Rubymine. You actually have to make sure that you create the Selenium Driver object in a specific way or your scripts will not run on the Selenium Grid or they will not run in parallel correctly.  Your test class must also always have a setup and tear down, even if you call a method out side of the class to setup the driver.

There are 2 sources of information that you must understand and monitor for updates.  First is the Selenium Grid home page.  Recently when Firefox 3.5 became available, I needed to update the version of the grid software I was using.  The other site is the site for the selenium client gem. You can find documentation here on how to structure your spec and test/unit scripts so that they run on the grid.  The gem and the grid  are both maintained by the same person.  I revisit the sites often to pick up tips on how to structure rake files and get tips for running scripts in parallel. In working with this software, I have become very familiar with the files in the rspec, deeptest, and selenium-client gems.

Firefox cannot initialize the application’s security component.

I have noticed this alert showing up when I start Firefox. After experimenting,  I have found the solution.  On a Mac go into th ~/Library/Application Support/Firefox/Profiles directory and cd into your profile’s directory.  Remove the cert8.db file and restart Firefox. Firefox will regenerate a new file and sites that use https will start working again.

Picture 4

Fix keyboard mapping mixup on OSX

I dock my Mac laptop and use an external keyboard.  I map my dell keyboard so that the command key is in the same place as on the laptop.  This lets me use the alt key as command and the windows key as the alt/option key.   I had a problem when I undocked, the laptop mixed up the key mapping and the alt and command keys were reversed.  I used the keyboard setting tab multiple times to reset the keys do default without any success. To fix the problem I plugged in  both keyboards and selected the all option from the keyboard drop down list.  Then I deleted /Library/Preferences/com.apple.keyboardtype.plist and reconfigured both keyboards. I spend weeks trying to figure out why my keyboard mapping was wrong on my laptop.

Picture 1

Use custom Firefox profiles with selenium grid.

I started using custom Firefox profiles so that I could get around the self signed cert error in firefox.  I found a way to easily maintain one configured profile that is used across all Selenium remote control environments running on OS X and multiple windows versions.

  1. Download the selenium grid software.  I am using selenium-grid-1.0.4
  2. Create a new directory called SeleniumFireFoxProfile  in your selenium-grid-1.0.4 directory.
  3. Start your remote control using the custom profile. rake all:start SELENIUM_ARGS=”-firefoxProfileTemplate SeleniumFireFoxProfile”
  4. Create a test script to open a selenium client driver and navigate to the site that is getting the ssl cert error. Use a debugger to pause the execution of your script at the browser.open command
  5. Execute your script to the break point and accept the cert in your Firefox browser.
  6. Look for the creation of the cert_override.txt file in your user directory.   With Firefox 3.0 I found it on my mac in /private/var/folders.  I cd to the contained directory and run a find command to locate it sudo find . -name cert_override.txt. With Firefox 3.5 the profile is stored in the user directory ~/Library/Application Support/Firefox/Profiles.
  7. You should see an entry in your cert_override.txt file after you accept the certificate. Now copy the cert_override.txt from your user directory to your SeleniumFireFoxProfile directory in your selenium grid directory.
  8. Restart your remote control now using the profile with the cert_override.txt file in it.  Rerun your test and break on the open command now you should see your page render instead of the security warning.

Just a warning about the cert_override.txt file.  It is very white space sensitive, it is better to copy the whole file into your custom profile directory rather then copying a new line into an existing file.

I check in the override text file along with my selenium software.  This way I can add a cert on my local machine and then run a SVN update on the distributed grid hosts to get the new cert information. This works for both windows and OS X.

Using the selenium IDE and Rubymine

This post explains how to debug a Selenium test script in Rubymine like you would in the selenium IDE. It is common to have a missing element failure in a recorded selenium script.  A quick way to debug this in the Selnium IDE is to put a break point in your script and use the execute command button to find the right code for your failing command.
Add breakpoints start and stop test execution

Add breakpoints start and stop test execution

In the case of a failing script you can see below that the failing line is highlighted in red and you can see the log message explaining the error.
Failing script

Failing script

So when you export your selenium IDE script to your favorite language, how do you trouble shoot failures like this easily in your development environment?
Test Script

Test Script

I generated an error in the script by changing the name of the google button from “btnG” to “btn” .  Trouble shoot this error by using the Rubymine debugger and evaluate expression tool.  I put a break point on the line of code that is failing.  Then I can select the text and open the evaluate expression tool to see if I can locate the button.
picture-15

When you get the expression correct, you will see a message, result = nil.  This is a great tool for testing xpath expressions.

Successful Evaluation

Successful Evaluation

If you noticed that the code I used in this example is different than what is exported from the Selenium IDE, it is because I use the selenium-client gem and execute my tests using the selenium grid.