Selenium/Ruby/Very Basic Howto

From mediawiki.org

The work of creating browser tests is all conceptual and abstracted until the very last step. Here is a step by step description of a proper test development process.

Describe the behavior by which we will know that the feature being tested functions correctly[edit]

If you've installed all the stuff you need, you create a feature file in the /tests/browser/features folder, for example my_test.feature.

In my_test.feature, you'll have a Scenario and a Feature:

Feature: My First Cucumber Test

  Scenario: My First Scenario
    Given I am on my page that has the setup I need to test
    When I click the link on my page that takes me somewhere I need to test
    Then I see the special thing that tells me that the test has passed

Generate the steps file[edit]

You execute the test at this point

$ bundle exec cucumber features/my_test.feature 

And the resulting output tells you what comes next:

Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/my_test.feature:4
    When I click the link on my page that takes me somewhere I need to test # features/my_test.feature:5
    Then I see the special thing that tells me that the test has passed     # features/my_test.feature:6

1 scenario (1 undefined)
3 steps (3 undefined)
0m3.074s

You can implement step definitions for undefined steps with these snippets:

Given(/^I am on my page that has the setup I need to test$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^I click the link on my page that takes me somewhere I need to test$/) do
  pending # express the regexp above with the code you wish you had
end

Then(/^I see the special thing that tells me that the test has passed$/) do
  pending # express the regexp above with the code you wish you had
end

Fill in a step in the test[edit]

This work is done step by step by step. Take the first "pending" step and paste it into a file in the /features/step_definitions directory with the title "my_test_steps.rb"

Given(/^I am on my page that has the setup I need to test$/) do
  pending # express the regexp above with the code you wish you had
end

and fill in the pending step

Given(/^I am on my page that has the setup I need to test$/) do
  visit(MyPage)
end

and run the test and see the failure:

$ bundle exec cucumber features/my_test.feature 
Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/step_definitions/my_test_steps.rb:1
      uninitialized constant MyPage (NameError)
      ./features/step_definitions/my_test_steps.rb:2:in `/^I am on my page that has the setup I need to test$/'
      features/my_test.feature:4:in `Given I am on my page that has the setup I need to test'
    When I click the link on my page that takes me somewhere I need to test # features/my_test.feature:5
    Then I see the special thing that tells me that the test has passed     # features/my_test.feature:6

Failing Scenarios:
cucumber features/my_test.feature:3 # Scenario: My First Scenario

1 scenario (1 failed)
3 steps (1 failed, 2 undefined)
0m2.731s

Make the Page Object (if it does not already exist)[edit]

In the features/support/pages directory you'll need a file called my_page.rb. Inside you'll need to put

class MyPage
  include PageObject

  page_url "<%=params[:article_name]%><%=params[:hash]%>"
end

There is a little bit of magic happening in that business of "<%=params[:article_name]%><%=params[:hash]%>" but don't worry about that for now...

Run the test again and the error is gone:

$ bundle exec cucumber features/my_test.feature 
Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/step_definitions/my_test_steps.rb:1
    When I click the link on my page that takes me somewhere I need to test # features/my_test.feature:5
    Then I see the special thing that tells me that the test has passed     # features/my_test.feature:6

1 scenario (1 undefined)
3 steps (2 undefined, 1 passed)
0m5.427s

Implement the When step[edit]

Go back to /features/step_definitions/my_test_steps.rb and add the pending step

When(/^I click the link on my page that takes me somewhere I need to test$/) do
  pending # express the regexp above with the code you wish you had
end

Decide what the pending step should do:

When(/^I click the link on my page that takes me somewhere I need to test$/) do
  on(MyPage).my_special_link_element.click
end

and run the test to watch it fail:

$ bundle exec cucumber features/my_test.feature 
Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/step_definitions/my_test_steps.rb:1
    When I click the link on my page that takes me somewhere I need to test # features/step_definitions/my_test_steps.rb:5
      undefined method `my_special_link_element' for #<MyPage:0x00000101cf2b80> (NoMethodError)
      ./features/step_definitions/my_test_steps.rb:6:in `/^I click the link on my page that takes me somewhere I need to test$/'
      features/my_test.feature:5:in `When I click the link on my page that takes me somewhere I need to test'
    Then I see the special thing that tells me that the test has passed     # features/my_test.feature:6

Failing Scenarios:
cucumber features/my_test.feature:3 # Scenario: My First Scenario

1 scenario (1 failed)
3 steps (1 failed, 1 undefined, 1 passed)

This tells us that the MyPage object does not contain a method called "my_special_link_element", which of course is true.

So far everything we have done has been conceptual and abstract. This next part is where we actually tie the test itself to the page being tested. Read over the documentation at https://github.com/cheezy/page-object/wiki/Elements and then add this to your page object:

class MyPage
  include PageObject

  page_url "<%=params[:article_name]%><%=params[:hash]%>"

  a(:my_special_link, href: /Special:UserLogin/)
end

Here "my_special_link" is the first link on the page whose target contains "Special: UserLogin", and this test is going to click that link. Note that appending "_element" to a label in a Page Object has some special properties, noted in the documentation linked above.

Run the test again:

$ bundle exec cucumber features/my_test.feature 
Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/step_definitions/my_test_steps.rb:1
    When I click the link on my page that takes me somewhere I need to test # features/step_definitions/my_test_steps.rb:5
    Then I see the special thing that tells me that the test has passed     # features/my_test.feature:6

1 scenario (1 undefined)
3 steps (1 undefined, 2 passed)
0m5.609s

Make an assertion in the Then step[edit]

The Given steps talk about what the test needs to have in place before it runs

The When steps talk about the actions that the test must perform to arrive at its final state

The Then steps talk about how we know that the feature functions correctly

So we will finish the test and make it pass. Put the last pending step into the steps file:

Then(/^I see the special thing that tells me that the test has passed$/) do
  pending # express the regexp above with the code you wish you had
end

So this will become

Then(/^I see the special thing that tells me that the test has passed$/) do
  expect(on(MyPage).page_content).to match "Create Account"
end

This step says "expect (some condition) to exist". We could also say things like

  • expect(on(MyPage.my_special_element).to be_visible or
  • expect(on(MyPage.my_crummy_element).not_to be_visible

or many other similar things the the RSpec assertion library allows.

The Page Object becomes

class MyPage
  include PageObject

  page_url "<%=params[:article_name]%><%=params[:hash]%>"

  a(:my_special_link, href: /Special:UserLogin/)
  div(:page_content, id: "content")
end

Run the test and it passes:

$ bundle exec cucumber features/my_test.feature 
Feature: My First Cucumber Test

  Scenario: My First Scenario                                               # features/my_test.feature:3
    Given I am on my page that has the setup I need to test                 # features/step_definitions/my_test_steps.rb:1
    When I click the link on my page that takes me somewhere I need to test # features/step_definitions/my_test_steps.rb:5
    Then I see the special thing that tells me that the test has passed     # features/step_definitions/my_test_steps.rb:9

1 scenario (1 passed)
3 steps (3 passed)