A training excercise for those relatively new to automated web testing, using Cucumber, Watir Webdriver, and TestFactory.
Keep in mind that you need only be competent in basic object-oriented programming in Ruby to get started, and that your skillset in this regard will absolutely grow in a relatively short time. Certainly don't be intimidated simply because you don't think of yourself as a programmer yet.
If you'd like, there are a couple of free online resources that will help you get familiar with the basics:
Let's start with automating some simple operations on a website you likely know well and use every day. This excercise will be incremental in that we'll start with a single action on a single page, progress to an action on a different page, and then end up with a test that spans multiple pages, which is where we'll introduce the Page Object pattern, which in short is how we'll apply object-oriented design principles to our test code.
Some basic first steps:
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Follow on-screen instructions to run "brew doctor" after the install.
\curl -sSL https://get.rvm.io | bash -s stable --autolibs=enable
gem install bundler --no-document
bundle install
gem install rubygems-bundler --no-document
gem regenerate_binstubs
Another important step: how to run Cucumber tests!
cucumber #runs all tests
cucumber features/my_google.feature #runs just one feature file's tests
cucumber features/my_google.feature:5 #runs just one test located by line number in the feature file
Given this Cucumber scenario:
features/my_google.feature:5
Scenario: Basic search
Given I am on the Google Home Page
When I search for Kittens
Then I see the Google Search Results Page
And the Google Search Results Page has Kittens
Insert Watir-Webdriver code into these steps to successfully perform a Google search for Kittens. You'll find some hints along the way. Ignore all hints related to TestFactory for now.
features/step_definitions/my_google_steps.rb:
Given(/^I am on the Google Home Page$/) do
pending # express the regexp above with the code you wish you had
end
When(/^I search for Kittens$/) do
pending # express the regexp above with the code you wish you had
end
Then(/^I see the Google Search Results Page$/) do
pending # express the regexp above with the code you wish you had
end
Then(/^the Google Search Results Page has Kittens$/) do
pending # express the regexp above with the code you wish you had
end
Given these two Cucumber steps:
features/my_google.feature:16
When I click the first result on the Google Search Results page
Then I am redirected to the corresponding website from the search result
Insert Watir-Webdriver code into these steps to successfully find one search result and click on it.
features/step_definitions/my_google_steps.rb
When(/^I click the first result on the Google Search Results page$/) do
pending # express the regexp above with the code you wish you had
end
Then(/^I am redirected to the corresponding website from the search result$/) do
pending # express the regexp above with the code you wish you had
end
Given this Cucumber scenario:
features/my_google.feature:21
Scenario: Basic search, then switch to News
Given I am on the Google Home Page
And I search for Kittens
When I click the News Tab on the Google Search Results Page
Then I see the Google News Results Page
And the Google News Results Page has Kittens
Insert Watir-Webdriver code into these steps to successfully perform a search for Kittens, click the News tab, and verify that Kitten-related stuff is on the News page.
features/step_definitions/my_google_steps.rb
When(/^I click the News Tab on the Google Search Results Page$/) do
pending # express the regexp above with the code you wish you had
end
Then(/^I see the Google News Results Page$/) do
pending # express the regexp above with the code you wish you had
end
Then(/^the Google News Results Page has Kittens$/) do
pending # express the regexp above with the code you wish you had
end
Your completed automation code isn't going to be that messy right now since we're talking about a fairly trivial example, but we do still have an opportunity to apply some solid object-oriented design principles. Enter the Page Object pattern.
If an object is an entity modeled by software that has attributes (eg. a Car object would have many wheels, a motor, etc.) and behavior (eg. a Car object would accelerate, brake, turn, etc.), then we can imagine that an HTML web page conforming to this pattern quite easily. A page's DOM elements would comprise the page object's attributes, and methods could be written using those elements to describe and execute page behavior. Therefore, in our use of the Page Object pattern, every page we seek to test against should be defined as a Ruby class that our step definitions would then instantiate and use.
It is quite possible to roll your own page object framework and doing so for yourself would be a great extra-credit excercise to undertake.
However, for our purposes, we will use TestFactory to streamline our implementation of page objects and to give our objects really neat built-in behavior. Give the README documentation, which is quite good, a good read to get an idea of all that TestFactory can do for us.
Page Object class stubs have been provided for you, with hints. The Cucumber step definitions have also been sprinkled with some additional hints related to TestFactory and page objects, which you are now free to pay attention to.
Your mission:
Let's say you have a scenario failing and you just can't figure out why. Pry is...a lot of things, but for us it's a debugging tool with some pretty neat source code browsing features.
When a test fails, you'll see a stack trace in your console that should give you some indication of what part of your test code is the culprit:
Feature: As a web automation tester in training I want to automate basic searching with Google
Scenario: Basic search # features/my_google.feature:5
Given I am on the Google Home Page # features/step_definitions/my_google_steps.rb:3
When I search for Kittens # features/step_definitions/my_google_steps.rb:11
unable to locate element, using {:id=>"gbqfqqq", :tag_name=>"input or textarea", :type=>"(any text type)"} (Watir::Exception::UnknownObjectException)
./features/step_definitions/my_google_steps.rb:15:in `/^I search for Kittens$/'
features/my_google.feature:8:in `When I search for Kittens'
Then I see the Google Search Results Page # features/step_definitions/my_google_steps.rb:26
And the Google Search Results Page has Kittens # features/step_definitions/my_google_steps.rb:42
Failing Scenarios:
cucumber features/my_google.feature:5 # Scenario: Basic search
1 scenario (1 failed)
4 steps (1 failed, 2 skipped, 1 passed)
The above means either the page isn't loading or you've identified the element incorrectly - in either case the element is not being found. We can stop the test execution just before the failing line not only to freeze the browser view and observe visually, but to explore the relevant code in the Pry console as well. To set such a breakpoint:
features/step_definitions/my_google_steps.rb:12
When(/^I search for Kittens$/) do
binding.pry #Set a binding.pry at the line of code where you want the program to stop executing for further inspection
@browser.text_field(id: "gbqfqqq").set 'Kittens'
@browser.text_field(id: "gbqfqqq").click
end
You can then re-run the cucumber scenario to trigger the breakpoint and investigate further.
From there you can:
Inspect the desired element in the browser and discern the correct element identifier to use.
Try out the new identifier right in the console to make sure it works before committing the code:
You also have three basic step debugging commands to use in your Pry console:
The 'continue' command will be by far the most common for us - use it when you're doing exploring and ready for the test to continue executing. Don't forget to remove all binding.pry statements when you're finished debugging.
This definitely isn't everything you can do with Pry, but it covers most of how we'll use it as UI test automators.
Rubocop is a tool we use to enforce good Ruby coding practices according to Ruby community standards.
Run it in your console like so:
rubocop --auto-correct
That will fix all the trivial problems it finds (missing spaces, indentation, etc.) and will alert you of more serious problems that you need to fix.
Rubocop is configured in .rubocop.yml. Note the exceptions that have been configured.