Thursday, March 29, 2012

Passing Test Parameters on the Cucumber Command Line


When I was researching watir, watir-webdriver and cucumber, I came across a number of articles by Alister Scott.  One in particular was helpful in structuring my code. It talked about implementing page objects.

As I started writing Cucumber tests, I was also learning the architecture of my company's website.  We have a number of silo-ed sites, one for each client.  Some are using older versions of code, and most are using a newer version.  I needed a way to pass which site I was using.  While I was at it, I decided to pass in which browser I wanted to use (IE, FF, Chrome, etc), as well as the testing environment (QA, Staging, Prod, etc), and whether or not I want the browser to stay open.  I also wanted defaults in case someone ran this without passing a parameter.

case ENV['BROWSER']
  when 'ie', 'Internet Explorer'
    browser = Watir::Browser.new :ie
    browser_name = 'Internet Explorer'
  when 'ff', 'Firefox'
    browser = Watir::Browser.new :ff
    browser_name = 'Firefox'
  when 'chrome'
    browser = Watir::Browser.new :chrome
    browser_name = 'Chrome'
  when 'opera'
    browser = Watir::Browser.new :opera
    browser_name = 'Opera'
  when 'debug'
    debug_profile = Selenium::WebDriver::Firefox::Profile.new
    debug_profile.add_extension "firebug-1.9.1-fx.xpi"
    browser = Watir::Browser.new :firefox, :profile => debug_profile
    browser_name = 'Firefox (Firebug)'
  else
    browser = Watir::Browser.new :ie
    browser_name = 'Internet Explorer'
end

URLS = {     'production' => "https://www.trialnet.com/",
           'qa' => "https://qa.trialnet.com/",
           'staging' => "https://stage.trialnet.com/",
           'dev' => "https://devel.trialnet.com/"
}

if URLS[ENV['URL']].nil?
  environment = 'QA'
  url = URLS['qa']
else
  environment = ENV['URL'].upcase
  url = URLS[ENV['URL']]
end

if ENV['CLIENT'].nil?
  client = 'Client-A'
else
  client = ENV['CLIENT']
end

puts "Browser      " + browser_name
puts "URL          " + url
puts "Environment: " + environment
puts "Client:      " + client

Before do
    @browser = browser
  @test_env = { :browser => browser,
                :browser_name => browser_name,
                :url => url,
                :env => environment,
                :client => client,
                :login => nil
  }
end 

Then I can just add the following on the command line or in my cucumber yaml file:

default: END_STATE=open URL=qa CLIENT=My-Client BROWSER=ie --format pretty --format html --out results.html -r features -r features\support -r features\step_definitions -r features\pages

END_STATE=open indicates I want to leave my browser open.  I decided to call it END_STATE in case I come up with other things I want to happen at the end of a run.  Any other value defaults to shutting the browser.

URL= indicates the environment I want to use.  If I can't resolve the environment passed, I default to the qa environment to make sure this doesn't accidentally get run in production.

BROWSER= tells me what browser to use.  The default is IE, because  95% of our customers use IE.  However, I may make it a headless browser in the future.

CLIENT= indicates the customer site I want to test.  Currently I'm limited to one client per execution, but for now that's ok.  I have a default set to one of the more generic sites, in case it isn't defined.  This is mainly for the developers that may use this on their own and don't care what site we're on.  In addition to choosing the site, I can call this code to deal with buttons that are named differently on older clients.

When /^I upload invoice "(.*)"$/ do |filename|
  @upload_invoice_page = UploadInvoicePage.new(@test_env)
  @upload_invoice_page.upload_file(filename)
end


In the above cucumber step you can see that I pass a @test_env instance instead of a @browser instance.  Then in my page object I use it as follows:

class UploadInvoicePage

  def initialize(test_env)
    @browser = test_env[:browser]
    case test_env[:client]
      when 'Old-Client-Named-Bob'
        @invoice_file       = @browser.file_field(:id => 'invoice_file')
        @upload_button      = @browser.div(:class => 'actionbar').image(:alt => 'Upload')
      else
        @invoice_file       = @browser.file_field(:name => 'file')
        @upload_button      = @browser.input(:type => 'image', :alt => 'Upload')
    end

    @upload_complete_button = @browser.div(:id => 'upload-footer').link
  end

  def upload_file(file_name)
    self.invoice_file.set(file_name)
    self.upload_button.click
    self.upload_complete_button.when_present.click
  end

end


The invoice_file and upload_button objects are set based on which client site I am on.  As sites are deprecated, I can remove the case statements and they should continue to work without any additional refactoring on my part.

2 comments:

  1. Thanks for the article. Below are the questions:-

    1.Where do you need to write the code snippet for env determination and browser identification that you have provided in the beginning of the article.

    2.How the cucumber knows and makes use if the above new file ?

    Thanks for your time.

    ReplyDelete
  2. Hi Onlinewebsurfer,

    I've been playing around with this code, myself, and I think I can help answer some questions.

    1) This code should go into the hooks.rb file of your tests. As for the environment determination, these are variables that can be passed in on the command line.

    For example:
    cucumber features/myfeature.feature BROWSER=ff URL=production --format pretty

    2) Cucumber makes use of the hooks file on startup, it will follow the Before and After hooks as follows.

    Before hooks start before any tests are run, in this case it will open the browser, and navigate to the prescribed url.

    Unfortunately, there are no After hooks in this example, but you can use them for data cleanup and closing the browser.

    For example:
    Before do
    @browser = Watir::Browser.new browser
    @browser.goto url
    end

    After do
    @browser.close
    end

    These would allow you to open the browser, navigate to the URL you want, and then close at the end. (This moves the "Watir::Browser.new" and uses just the argument of :ie, :firefox, :chrome, etc. as the "browser" argument.

    Hope that helps!

    ReplyDelete