Archive for the ‘Software’ Category.

How to use a extension with chrome and selenium-webdriver

Get the extension

I thought this would be the easy part. Turns out that the new chrome web store only lets you install directly to chrome.

downloader

Create And Use a profile

  • After you download your crx file put it in the same repo as your test. Next create a chrome profile and use the add_extension method.
      profile = Selenium::WebDriver::Chrome::Profile.new
      profile.add_extension(File.dirname(__FILE__) +"/chrome_extensions/adblock/AdBlock_v2.5.61.crx")
  • Now you can use the new profile to with a driver
      Selenium::WebDriver.for(:chrome,:profile => profile)

Trouble Shooting

  • be sure that your chromedriver is updated. I used 26.0.1383.0
  • chrome  26.0.1410.43
  • selenium-webdriver  2.31.0

Managing browsers from the command line on OS X

Have you ever wanted to open a url from the command line on OS X?  Turns out open can do many cool things like that.

open -a ‘google chrome’ ‘http://www.scottcsims.com’

open -a ‘firefox’ ‘http://www.scottcsims.com’

Sometimes a parallel Selenium run might get out of control and you need to close all your browsers, try this one from the command line:

killall firefox

Yes, I know killall is a very old Unix command, but I didn’t know that I could pass it an application name that a OS X has bound to an executable.

I like the -a and -e options for open.

Usage: open [-e] [-t] [-f] [-W] [-R] [-n] [-g] [-h] [-b ] [-a ] [filenames] [--args arguments]
Help: Open opens files from a shell.
      By default, opens each file using the default application for that file.  
      If the file is in the form of a URL, the file will be opened as a URL.
Options: 
      -a                Opens with the specified application.
      -b                Opens with the specified application bundle identifier.
      -e                Opens with TextEdit.
      -t                Opens with default text editor.
      -f                Reads input from standard input and opens with TextEdit.
      -F  --fresh       Launches the app fresh, that is, without restoring windows. Saved persistent state is lost, excluding Untitled documents.
      -R, --reveal      Selects in the Finder instead of opening.
      -W, --wait-apps   Blocks until the used applications are closed (even if they were already running).
          --args        All remaining arguments are passed in argv to the application's main() function instead of opened.
      -n, --new         Open a new instance of the application even if one is already running.
      -j, --hide        Launches the app hidden.
      -g, --background  Does not bring the application to the foreground.
      -h, --header      Searches header file locations for headers matching the given filenames, and opens them.

Minesweeper Programming Contest. Using Selenium Web Driver to win Minesweeper

I had a great time attending the Test Automation Bazaar  in Austin. Alister Scott put on a contest to see who could write a program to win Minesweeper.  After checking out what was required, I started coding the Minesweeper robot. Before I noticed, I had spent hours coding tests and methods for the robot.  It was one of the most addictive and exciting code I had written.  I spent about 3 days coding along to get something to win on basic and intermediate level. I spent hours trying to win on advanced.

I ended up winning the Minesweeper Challenge!  I encourage everyone to take a look at Alister’s code.  Alister wrote some of the  best cukes and examples I have seen.  I was very impressed by the time he put into writing unit tests that work on logic only, taking the browser out of the mix.  Thanks Alister for putting on the contest.  If you wish to see what 3 days of coding gets you in a mine sweeper robot you can checkout my code on github.  As I mentioned before I got really engaged with writing this code.  I could have spent weeks tuning and polishing it.  I did have a chance to refractor the code to use Nokogiri instead of the find all elements selenium method to check the game state.  I believe that this might have actually slowed it down.

Sadly to say, I had to withdraw from polishing and tuning the code.  If you want to run my robot checkout the code and run the test “Minesweeper should win” in this file.

 

What does the SeleniumFury generator find on a page for you?

What should you expect SeleniumFury to find on a page for you?   Take a look behind the curtains at the PageParser class on git hub.
You will find that I am using Nokogiri xml parser to find elements and you will see this list of html elements that I am looking for.

          @nokogiri_selectors= ["select",
                              "textarea",
                              "form",
                              "input",
                              "input[type='button']",
                              "input[type='file']",
                              "input[type='checkbox']",
                              "input[type='password']",
                              "input[type='radio']",
                              "input[type='reset']",
                              "input[type='image']",
                              "input[type='submit']",
                              "input[type='text']"]

The only fields that are found are simple HTML fields.

For more complex UI elements like jquery select menus, I usually will define the class and write a unit test for the actions that can be done on the component.
You can use the page method on PageObject to define a subpage or page component like this.

  
class SelectMenu < PageObject     #This could be a jquery select menu     element :select_menu, {:id => "selectSomething"}
    def select index
      #code to select
    end 
end
class SearchPage < PageObject
     #add the component to your main page
     page :select_menu, SelectMenu
end
#Use your page component
SearchPage.new(driver).select_menu.select(2)

I have more examples of this in the SeleniumFury source. See this PageObject Unit Test(spec)

Selenium Fury is on RelishApp.com

Checkout Selenium Fury on relishapp.com. I found the site when I was searching for Rspec2 documentation. The site organizes your cucumber features into a really nice presentation so that your features can be consumed as documentation. It has been a great tool for learning more about Rspec 2. To illustrate the difference this is what it is like to view Features on github and here is the same feature on rellishapp.

Selenium Fury 5.5 released

I was able to restructure the gem and remove the dependency on Rspec. I have tested successfully with Rspec 1 and 2.

Selenium Fury 5.2 with custom generators has been released.

The latest release of Selenium Fury is ready for your install.  Checkout the new cucumber features at the project home  https://github.com/scottcsims/SeleniumFury. This version includes extended page element recognition, custom generators, and the git hub project includes support for bundler and rvm.

Install the new release:   gem install selenium_fury

https://rubygems.org/gems/selenium_fury

 

The Selenium Fury gem is ready! Page object factory for Selenium and Ruby.

I have been working on converting our page object factory to open source for a few weeks. Now it is time to launch the  HomeAway sponsored open source project under the Apache 2.0 license.  It is a furiously quick way to implement test automation.  I am planning to add more configuration options in the future.

This project started when I had to test a page with 300+ check boxes and I did not want to enter them by hand.  I used the page object generator to build a page of ruby variables with Selenium locators. Everything was great until some number of the check boxes changed their ids and my tests started failing.  I needed  a quick way to find out how many changed so I could update the locators by hand or regenerate the page.  This is where the validators came in.  I used Ruby’s support of reflection to open a class, navigate to the url of the page and use Selenium to validate the locators and return a list of missing locators on the page.  It worked perfectly for my page of 300+ check boxes.  I had over 40 that changed I quickly regenerated the page.

Install with:

  • gem install selenium_fury

Checkout the home page and examples at https://github.com/scottcsims/SeleniumFury

Thanks to HomeAway for sponsoring this project.

Use rspec partial mock to write a quick executing example.

I wanted to test an error message in my class that processes test results and sends them to Rally.  The problem was that I did not want to actually create a rally object and run the method to parse the results, just to test the error message.
This is what my class looks like.

class AutomationRun
  def send_results_to_rally
    @rally = RallyUtils.new(ENV['RALLY_WORKSPACE'])
    push_test_case_results
    raise("Test Case Results Were Not Parsed Correctly") if test_case_results.empty?
    test_case_results.each do |result|
      @rally.update_test_case_result(:tc_id =>result.test_case_number_from_spec_report, :build =>result.build_number, :verdict =>result.verdict, :notes => result.note.format_note)
    end
  end
end

I want to skip these steps to test the error message:

  • don’t instantiate RallyUtils.new  we don’t need @rally for the test
  • don’t parse the results so don’t call parse_test_case_results

This is what my test code looks like:

 it "should raise an exception if there are not test case results" do
    RallyUtils.stub!(:new).and_return(nil)
    automation_run=AutomationRun.new
    automation_run.should_receive(:push_test_case_results).and_return([])
    begin
    automation_run.send_results_to_rally
    rescue Exception=>e
    end
    e.message.should == "Test Case Results Were Not Parsed Correctly"
  end
  1. We use a rspec stub to intercept the new call to the RallyUtils class and return nil.  We could have also returned a mock object if we wanted to execute a call on the rally class. Now we are not creating a connection to Rally
  2. Now it is time to new up or AutomationRun class and setup our mock expectation to skip running the real push_test_case_results method.
  3. automation_run.should_receive tells us to intercept the symbol or method push_test_case_results
  4. and_return([]) will just return an empty array
  5. We setup a begin rescue block to capture the Exception object returned by our expected error message
  6. Now we call send_results_to_rally to get our error message
  7. Lastly we verify that the message attribute for our error is Test Case Results Were Not Parsed Correctly

So that is it, I created a partial mock  in that we are using a real automation run object but we stubbed out one of the methods.  We also stubbed out the new call to rally so we don’t create a connection.  Now I can focus my test on exactly the function I wanted to test, the error message.

Deep Test 2.0 prerelease is available.

Deep test allows you to run ruby rspec tests in parallel by providing a spec task that you include in your rake file. The 2.0 prerelease version of deep tests offers support for rspec 1.1.12. You can install it buy running: gem install deep_test_pre. Require it in your rake file like this:

gem “deep_test_pre”, “=2.0”
require “deep_test”

gem “deep_test_pre”, “=2.0”
require “deep_test”

There currently is a bug that occurs if you run Test::Unit tests with the deep test spec runner.  The tests will all run twice but are reported once.