page-object 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +87 -0
- data/Rakefile +51 -0
- data/cucumber.yml +5 -0
- data/features/check_box.feature +39 -0
- data/features/html/static_elements.html +34 -0
- data/features/link.feature +42 -0
- data/features/page_level_actions.feature +19 -0
- data/features/radio_button.feature +40 -0
- data/features/select_list.feature +40 -0
- data/features/step_definitions/accessor_steps.rb +88 -0
- data/features/step_definitions/element_steps.rb +28 -0
- data/features/step_definitions/page_level_actions_steps.rb +12 -0
- data/features/step_definitions/page_traversal_steps.rb +5 -0
- data/features/support/env.rb +18 -0
- data/features/support/page.rb +45 -0
- data/features/support/url_helper.rb +16 -0
- data/features/text_field.feature +39 -0
- data/lib/page-object.rb +52 -0
- data/lib/page-object/accessors.rb +171 -0
- data/lib/page-object/elements.rb +8 -0
- data/lib/page-object/elements/button.rb +15 -0
- data/lib/page-object/elements/check_box.rb +15 -0
- data/lib/page-object/elements/element.rb +52 -0
- data/lib/page-object/elements/link.rb +34 -0
- data/lib/page-object/elements/radio_button.rb +15 -0
- data/lib/page-object/elements/select_list.rb +21 -0
- data/lib/page-object/elements/text_field.rb +33 -0
- data/lib/page-object/selenium_element.rb +12 -0
- data/lib/page-object/selenium_page_object.rb +190 -0
- data/lib/page-object/version.rb +3 -0
- data/lib/page-object/watir_element.rb +12 -0
- data/lib/page-object/watir_page_object.rb +190 -0
- data/page-object.gemspec +29 -0
- data/spec/page-object/accessors_spec.rb +297 -0
- data/spec/page-object/elements/button_spec.rb +23 -0
- data/spec/page-object/elements/check_box_spec.rb +21 -0
- data/spec/page-object/elements/element_spec.rb +54 -0
- data/spec/page-object/elements/link_spec.rb +34 -0
- data/spec/page-object/elements/radio_button_spec.rb +21 -0
- data/spec/page-object/elements/select_list_spec.rb +22 -0
- data/spec/page-object/elements/text_field_spec.rb +32 -0
- data/spec/page-object/page-object_spec.rb +78 -0
- data/spec/spec_helper.rb +31 -0
- metadata +179 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jeff Morgan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# page-object
|
2
|
+
|
3
|
+
[![Build Status](http://travis-ci.org/cheezy/page-object.png)](http://travis-ci.org/cheezy/page-object)
|
4
|
+
|
5
|
+
|
6
|
+
A simple gem that assists in creating flexible page objects for testing browser based appications. The goal is to facilitate creating abstraction layers in your tests to decouple the tests from the item they are testing and to provide a simple interface to the elements on a page. It works with both watir-webdriver and selenium-webdriver.
|
7
|
+
|
8
|
+
### Defining your page object
|
9
|
+
|
10
|
+
You define a new page object by including the PageObject module:
|
11
|
+
|
12
|
+
class LoginPage
|
13
|
+
include PageObject
|
14
|
+
end
|
15
|
+
|
16
|
+
When you include this module numerous methods are added to your class that allow you to easily define your page. For the login page you might add the following:
|
17
|
+
|
18
|
+
class LoginPage
|
19
|
+
include Page Object
|
20
|
+
|
21
|
+
text_field(:username, :id => 'username')
|
22
|
+
text_field(:password, :id => 'password')
|
23
|
+
button(:login, :id => 'login')
|
24
|
+
end
|
25
|
+
|
26
|
+
Calling the _text_field_ and _button_ methods adds several methods to our page object that allow us to interact with the items on the page. To login using this page we could simply write the following code:
|
27
|
+
|
28
|
+
login_page.username = 'cheezy'
|
29
|
+
login_page.password = 'secret'
|
30
|
+
login_page.login
|
31
|
+
|
32
|
+
Another approach might be to create higher level methods on our page object that hide the implementation details even further. Our page object might look like this:
|
33
|
+
|
34
|
+
class LoginPage
|
35
|
+
include Page Object
|
36
|
+
|
37
|
+
text_field(:username, :id => 'username')
|
38
|
+
text_field(:password, :id => 'password')
|
39
|
+
button(:login, :id => 'login')
|
40
|
+
|
41
|
+
def login_with(username, password) do
|
42
|
+
self.username = username
|
43
|
+
self.password = password
|
44
|
+
login
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
and your usage of the page would become:
|
49
|
+
|
50
|
+
login_page.login_with 'cheezy', 'secret'
|
51
|
+
|
52
|
+
### Creating your page object
|
53
|
+
page-object supports both [watir-webdriver](https://github.com/jarib/watir-webdriver) and [selenium-webdriver](http://seleniumhq.org/docs/03_webdriver.html). The one used will be determined by which driver you pass into the constructor of your page object. The page object can be create like this:
|
54
|
+
|
55
|
+
browser = Watir::Browser.new :firefox
|
56
|
+
my_page_object = MyPageObject.new(browser)
|
57
|
+
|
58
|
+
or
|
59
|
+
|
60
|
+
browser = Selenium::WebDriver.for :firefox
|
61
|
+
my_page_object = MyPageObject.new(browser)
|
62
|
+
|
63
|
+
## Documentation
|
64
|
+
|
65
|
+
The project [wiki](https://github.com/cheezy/page-object/wiki/page-object) is the first place to go to learn about how to use page-object.
|
66
|
+
|
67
|
+
The rdocs for this project can be found at [rubydoc.info](http://rubydoc.info/github/cheezy/page-object/master/frames).
|
68
|
+
|
69
|
+
If you wish to view the current tracker board you can view it on [Pivotal Tracker](https://www.pivotaltracker.com/projects/289099)
|
70
|
+
|
71
|
+
## Known Issues
|
72
|
+
|
73
|
+
See [http://github.com/cheezy/page-object/issues](http://github.com/cheezy/page-object/issues)
|
74
|
+
|
75
|
+
## Contribute
|
76
|
+
|
77
|
+
* Fork the project.
|
78
|
+
* Test drive your feature addition or bug fix. Adding specs is important and I will not accept a pull request that does not have tests.
|
79
|
+
* Make sure you describe your new feature with a cucumber scenario.
|
80
|
+
* Make sure you provide RDoc comments for any new public method you add. Remember, others will be using this gem.
|
81
|
+
* Commit, do not mess with rakefile, version, or history.
|
82
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
83
|
+
* Send me a pull request. Bonus points for topic branches.
|
84
|
+
|
85
|
+
## Copyright
|
86
|
+
|
87
|
+
Copyright (c) 2011 Jeffrey S. Morgan. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'cucumber'
|
5
|
+
require 'cucumber/rake/task'
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
10
|
+
spec.ruby_opts = "-I lib:spec"
|
11
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
12
|
+
end
|
13
|
+
task :spec
|
14
|
+
|
15
|
+
namespace :features do
|
16
|
+
Cucumber::Rake::Task.new(:watir, "Run features with Watir") do |t|
|
17
|
+
t.profile = "watir"
|
18
|
+
end
|
19
|
+
|
20
|
+
Cucumber::Rake::Task.new(:selenium, "Run features with Selenium") do |t|
|
21
|
+
t.profile = "selenium"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Run all features'
|
25
|
+
task :all => [:watir, :selenium]
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'Run all specs and cukes'
|
29
|
+
task :test => ['spec', 'features:all']
|
30
|
+
|
31
|
+
task :lib do
|
32
|
+
$LOAD_PATH.unshift(File.expand_path("lib", File.dirname(__FILE__)))
|
33
|
+
end
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'yard'
|
40
|
+
Rake::Task[:lib].invoke
|
41
|
+
require "yard/handlers/page-object"
|
42
|
+
YARD::Rake::YardocTask.new do |task|
|
43
|
+
task.options = %w[--debug] # this is pretty slow, so nice with some output
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
task :yard do
|
47
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
data/cucumber.yml
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
default: DRIVER=WATIR --no-source --color --format pretty --tags ~@selenium_only
|
2
|
+
watir: DRIVER=WATIR --no-source --color --format pretty --tags ~@selenium_only
|
3
|
+
selenium: DRIVER=SELENIUM --no-source --color --format pretty --tags ~@watir_only
|
4
|
+
autotest: DRIVER=WATIR --no-source --color --format pretty --tags ~@selenium_only
|
5
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Feature: Check Box
|
2
|
+
In order to interact with check boxes
|
3
|
+
Testers will need access and interrogation ability
|
4
|
+
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I am on the static elements page
|
8
|
+
|
9
|
+
Scenario: Selecting an element on the select list
|
10
|
+
When I select the First check box
|
11
|
+
Then the First check box should be selected
|
12
|
+
When I unselect the First check box
|
13
|
+
Then the First check box should not be selected
|
14
|
+
|
15
|
+
Scenario Outline: Locating check boxes on the page
|
16
|
+
When I search for the check box by "<search_by>"
|
17
|
+
Then I should be able to check the check box
|
18
|
+
|
19
|
+
Scenarios:
|
20
|
+
| search_by |
|
21
|
+
| id |
|
22
|
+
| class |
|
23
|
+
| name |
|
24
|
+
| xpath |
|
25
|
+
|
26
|
+
@watir_only
|
27
|
+
Scenario Outline: Locating check boxes on Watir only
|
28
|
+
When I search for the check box by "<search_by>"
|
29
|
+
Then I should be able to check the check box
|
30
|
+
|
31
|
+
Scenarios:
|
32
|
+
| search_by |
|
33
|
+
| index |
|
34
|
+
|
35
|
+
Scenario: Retrieve a CheckBox
|
36
|
+
When I retrieve a check box element
|
37
|
+
Then I should know it exists
|
38
|
+
And I should know it is visible
|
39
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Static Elements Page</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<h2>Static Elements Page</h2>
|
7
|
+
|
8
|
+
|
9
|
+
<h3>Text Field</h3>
|
10
|
+
<input id="text_field_id" name="text_field_name" class="text_field_class"
|
11
|
+
size="40" type="text" />
|
12
|
+
|
13
|
+
<h3>Select List</h3>
|
14
|
+
<select name="sel_list_name" id="sel_list_id", class="sel_list_class">
|
15
|
+
<option value="option1">Test 1</option>
|
16
|
+
<option value="option2">Test 2</option>
|
17
|
+
</select>
|
18
|
+
|
19
|
+
<h3>Button</h3>
|
20
|
+
<button id="test_button" onclick="javascript:window.location='http://www.google.com'">Click Me!!</button>
|
21
|
+
|
22
|
+
<h3>Link</h3>
|
23
|
+
<a href="http://www.google.com" id="link_id" name="link_name" class="link_class" >Google Search</a>
|
24
|
+
|
25
|
+
<h3>Check Boxes</h3>
|
26
|
+
<input id="cb_id" name="cb_name" class="cb_class" type="checkbox" value="1" />
|
27
|
+
|
28
|
+
<h3>Radio Buttons</h3>
|
29
|
+
<input type="radio" id="milk_id" name="milk_name" class="milk_class" value="Milk"> Milk <br />
|
30
|
+
<input type="radio" id="butter_id" name="butter_name" class="butter_class" value="Butter">Butter
|
31
|
+
</body>
|
32
|
+
</html>
|
33
|
+
|
34
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Feature: Links
|
2
|
+
In order to interact with links
|
3
|
+
Testers will need access and interrogation ability
|
4
|
+
|
5
|
+
Note:
|
6
|
+
Watir supports href
|
7
|
+
|
8
|
+
Background:
|
9
|
+
Given I am on the static elements page
|
10
|
+
|
11
|
+
Scenario: Selecting a link
|
12
|
+
When I select the link labeled "Google Search"
|
13
|
+
Then the page should contain the text "Google"
|
14
|
+
|
15
|
+
Scenario Outline: Locating links on the Page
|
16
|
+
When I search for the link by "<search_by>"
|
17
|
+
Then I should be able to select the link
|
18
|
+
|
19
|
+
Scenarios:
|
20
|
+
| search_by |
|
21
|
+
| id |
|
22
|
+
| class |
|
23
|
+
| name |
|
24
|
+
| xpath |
|
25
|
+
| link |
|
26
|
+
| link_text |
|
27
|
+
| text |
|
28
|
+
|
29
|
+
@watir_only
|
30
|
+
Scenario Outline: Locating links on Watir only
|
31
|
+
When I search for the link by "<search_by>"
|
32
|
+
Then I should be able to select the link
|
33
|
+
|
34
|
+
Scenarios:
|
35
|
+
| search_by |
|
36
|
+
| href |
|
37
|
+
| index |
|
38
|
+
|
39
|
+
Scenario: Retrieve a Link
|
40
|
+
When I retrieve a link element
|
41
|
+
Then I should know it exists
|
42
|
+
And I should know it is visible
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Page level actions
|
2
|
+
In order to act on pages from a web site
|
3
|
+
Testers will need to use the page object to encapsulate access
|
4
|
+
|
5
|
+
|
6
|
+
Scenario: Getting the text from a web page
|
7
|
+
Given I am on the static elements page
|
8
|
+
Then the page should contain the text "Static Elements Page"
|
9
|
+
|
10
|
+
Scenario: Getting the html from a web page
|
11
|
+
Given I am on the static elements page
|
12
|
+
Then the page should contain the html "<title>Static Elements Page</title>"
|
13
|
+
|
14
|
+
Scenario: Getting the title from a web page
|
15
|
+
Given I am on the static elements page
|
16
|
+
Then the page should have the title "Static Elements Page"
|
17
|
+
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Feature: Radio Buttons
|
2
|
+
In order to interact with radio buttons
|
3
|
+
Testers will need access and interrogation ability
|
4
|
+
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I am on the static elements page
|
8
|
+
|
9
|
+
Scenario: Selecting and clearing a radio button
|
10
|
+
When I select the "Milk" radio button
|
11
|
+
Then the "Milk" radio button should be selected
|
12
|
+
When I select the "Butter" radio button
|
13
|
+
Then the "Butter" radio button should be selected
|
14
|
+
|
15
|
+
Scenario Outline: Locating radio buttons on the Page
|
16
|
+
When I search for the radio button by "<search_by>"
|
17
|
+
And I select the radio button
|
18
|
+
Then the "Milk" radio button should be selected
|
19
|
+
|
20
|
+
Scenarios:
|
21
|
+
| search_by |
|
22
|
+
| id |
|
23
|
+
| class |
|
24
|
+
| name |
|
25
|
+
| xpath |
|
26
|
+
|
27
|
+
@watir_only
|
28
|
+
Scenario Outline: Locating radio buttons on Watir only
|
29
|
+
When I search for the radio button by "<search_by>"
|
30
|
+
And I select the radio button
|
31
|
+
Then the "Milk" radio button should be selected
|
32
|
+
|
33
|
+
Scenarios:
|
34
|
+
| search_by |
|
35
|
+
| index |
|
36
|
+
|
37
|
+
Scenario: Retrieve a radio button
|
38
|
+
When I retrieve a radio button
|
39
|
+
Then I should know it exists
|
40
|
+
And I should know it is visible
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Feature: Select List
|
2
|
+
In order to interact with select lists
|
3
|
+
Testers will need access and interrogation ability
|
4
|
+
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I am on the static elements page
|
8
|
+
|
9
|
+
Scenario: Selecting an element on the select list
|
10
|
+
When I select "Test 2" from the select list
|
11
|
+
Then the current item should be "option2"
|
12
|
+
|
13
|
+
Scenario Outline: Locating select lists on the Page
|
14
|
+
When I search for the select list by "<search_by>"
|
15
|
+
Then I should be able to select "Test 2"
|
16
|
+
And the value for the selected item should be "option2"
|
17
|
+
|
18
|
+
Scenarios:
|
19
|
+
| search_by |
|
20
|
+
| id |
|
21
|
+
| class |
|
22
|
+
| name |
|
23
|
+
| xpath |
|
24
|
+
|
25
|
+
@watir_only
|
26
|
+
Scenario Outline: Locating select lists on Watir only
|
27
|
+
When I search for the select list by "<search_by>"
|
28
|
+
Then I should be able to select "Test 2"
|
29
|
+
And the value for the selected item should be "option2"
|
30
|
+
|
31
|
+
Scenarios:
|
32
|
+
| search_by |
|
33
|
+
| index |
|
34
|
+
# | value |
|
35
|
+
# | text |
|
36
|
+
|
37
|
+
Scenario: Retrieve a select list
|
38
|
+
When I retrieve a select list
|
39
|
+
Then I should know it exists
|
40
|
+
And I should know it is visible
|
@@ -0,0 +1,88 @@
|
|
1
|
+
When /^I type "([^\"]*)" into the text field$/ do |text|
|
2
|
+
@page.text_field_id = text
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the text field should contain "([^\"]*)"$/ do |expected_text|
|
6
|
+
@page.text_field_id.should == expected_text
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I search for the text field by "([^\"]*)"$/ do |how|
|
10
|
+
@how = how
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^I should be able to type "([^\"]*)" into the field$/ do |value|
|
14
|
+
@page.send "text_field_#{@how}=".to_sym, value
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I select the link labeled "([^\"]*)"$/ do |text|
|
18
|
+
@page.google_search_id
|
19
|
+
end
|
20
|
+
|
21
|
+
When /^I search for the link by "([^\"]*)"$/ do |how|
|
22
|
+
@how = how
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^I should be able to select the link$/ do
|
26
|
+
@page.send "google_search_#{@how}".to_sym
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^I select "([^\"]*)" from the select list$/ do |text|
|
30
|
+
@page.sel_list_id = text
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^the current item should be "([^\"]*)"$/ do |expected_text|
|
34
|
+
@page.sel_list_id.should == expected_text
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^I search for the select list by "([^\"]*)"$/ do |how|
|
38
|
+
@how = how
|
39
|
+
end
|
40
|
+
|
41
|
+
Then /^I should be able to select "([^\"]*)"$/ do |value|
|
42
|
+
@page.send "sel_list_#{@how}=".to_sym, value
|
43
|
+
end
|
44
|
+
|
45
|
+
Then /^the value for the selected item should be "([^\"]*)"$/ do |value|
|
46
|
+
result = @page.send "sel_list_#{@how}".to_sym
|
47
|
+
result.should == value
|
48
|
+
end
|
49
|
+
|
50
|
+
When /^I select the First check box$/ do
|
51
|
+
@page.check_cb_id
|
52
|
+
end
|
53
|
+
|
54
|
+
Then /^the First check box should be selected$/ do
|
55
|
+
@page.cb_id_checked?.should be_true
|
56
|
+
end
|
57
|
+
|
58
|
+
When /^I unselect the First check box$/ do
|
59
|
+
@page.uncheck_cb_id
|
60
|
+
end
|
61
|
+
|
62
|
+
Then /^the First check box should not be selected$/ do
|
63
|
+
@page.cb_id_checked?.should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
When /^I search for the check box by "([^\"]*)"$/ do |how|
|
67
|
+
@how = how
|
68
|
+
end
|
69
|
+
|
70
|
+
Then /^I should be able to check the check box$/ do
|
71
|
+
@page.send "check_cb_#{@how}".to_sym
|
72
|
+
end
|
73
|
+
|
74
|
+
When /^I select the "([^\"]*)" radio button$/ do |how|
|
75
|
+
@page.send "select_#{how.downcase}_id".to_sym
|
76
|
+
end
|
77
|
+
|
78
|
+
Then /^the "([^\"]*)" radio button should be selected$/ do |how|
|
79
|
+
@page.send "#{how.downcase}_id_selected?".to_sym
|
80
|
+
end
|
81
|
+
|
82
|
+
When /^I search for the radio button by "([^\"]*)"$/ do |how|
|
83
|
+
@how = how
|
84
|
+
end
|
85
|
+
|
86
|
+
When /^I select the radio button$/ do
|
87
|
+
@page.send "select_milk_#{@how}".to_sym
|
88
|
+
end
|