page-object 2.2.3 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -1
- data/.gitignore +8 -8
- data/.rspec +2 -2
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +17 -17
- data/ChangeLog +928 -899
- data/Gemfile +13 -13
- data/Guardfile +20 -20
- data/LICENSE +20 -20
- data/README.md +114 -114
- data/Rakefile +29 -29
- data/cucumber.yml +8 -8
- data/lib/page-object.rb +431 -420
- data/lib/page-object/accessors.rb +1201 -1175
- data/lib/page-object/element_locators.rb +21 -21
- data/lib/page-object/elements.rb +62 -61
- data/lib/page-object/elements/area.rb +9 -9
- data/lib/page-object/elements/audio.rb +9 -9
- data/lib/page-object/elements/bold.rb +9 -9
- data/lib/page-object/elements/button.rb +12 -12
- data/lib/page-object/elements/canvas.rb +10 -10
- data/lib/page-object/elements/check_box.rb +9 -9
- data/lib/page-object/elements/date_field.rb +10 -0
- data/lib/page-object/elements/div.rb +9 -9
- data/lib/page-object/elements/element.rb +212 -216
- data/lib/page-object/elements/file_field.rb +9 -9
- data/lib/page-object/elements/form.rb +9 -9
- data/lib/page-object/elements/heading.rb +14 -14
- data/lib/page-object/elements/hidden_field.rb +9 -9
- data/lib/page-object/elements/image.rb +10 -10
- data/lib/page-object/elements/italic.rb +9 -9
- data/lib/page-object/elements/label.rb +9 -9
- data/lib/page-object/elements/link.rb +9 -9
- data/lib/page-object/elements/list_item.rb +9 -9
- data/lib/page-object/elements/media.rb +11 -11
- data/lib/page-object/elements/option.rb +9 -9
- data/lib/page-object/elements/ordered_list.rb +43 -43
- data/lib/page-object/elements/paragraph.rb +9 -9
- data/lib/page-object/elements/radio_button.rb +9 -9
- data/lib/page-object/elements/select_list.rb +42 -42
- data/lib/page-object/elements/span.rb +9 -9
- data/lib/page-object/elements/table.rb +85 -68
- data/lib/page-object/elements/table_cell.rb +10 -10
- data/lib/page-object/elements/table_row.rb +52 -52
- data/lib/page-object/elements/text_area.rb +9 -9
- data/lib/page-object/elements/text_field.rb +10 -10
- data/lib/page-object/elements/unordered_list.rb +42 -42
- data/lib/page-object/elements/video.rb +9 -9
- data/lib/page-object/indexed_properties.rb +41 -41
- data/lib/page-object/javascript/angularjs.rb +14 -14
- data/lib/page-object/javascript/jquery.rb +14 -14
- data/lib/page-object/javascript/prototype.rb +14 -14
- data/lib/page-object/javascript/yui.rb +18 -18
- data/lib/page-object/javascript_framework_facade.rb +80 -80
- data/lib/page-object/locator_generator.rb +183 -182
- data/lib/page-object/nested_elements.rb +17 -17
- data/lib/page-object/page_factory.rb +108 -108
- data/lib/page-object/page_populator.rb +105 -93
- data/lib/page-object/platforms/watir.rb +50 -50
- data/lib/page-object/platforms/watir/page_object.rb +1155 -1124
- data/lib/page-object/section_collection.rb +16 -16
- data/lib/page-object/version.rb +4 -4
- data/lib/page-object/widgets.rb +98 -98
- data/page-object.gemspec +31 -32
- metadata +12 -26
data/Gemfile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
# adding rake so travis-ci will build properly
|
4
|
-
gem 'rake'
|
5
|
-
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
6
|
-
gem 'growl'
|
7
|
-
gem 'guard-rspec'
|
8
|
-
gem 'listen', '3.0.8' #Last version that supports ruby 2.0
|
9
|
-
gem 'guard-cucumber'
|
10
|
-
gem 'coveralls', require: false
|
11
|
-
|
12
|
-
|
13
|
-
gemspec
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# adding rake so travis-ci will build properly
|
4
|
+
gem 'rake'
|
5
|
+
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
6
|
+
gem 'growl'
|
7
|
+
gem 'guard-rspec'
|
8
|
+
gem 'listen', '3.0.8' #Last version that supports ruby 2.0
|
9
|
+
gem 'guard-cucumber'
|
10
|
+
gem 'coveralls', require: false
|
11
|
+
|
12
|
+
|
13
|
+
gemspec
|
data/Guardfile
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
# A sample Guardfile
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
3
|
-
|
4
|
-
|
5
|
-
guard :rspec, cmd: 'rspec --color --format documentation' do
|
6
|
-
watch(%r{^spec/.+_spec\.rb$})
|
7
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
8
|
-
watch(%r{^lib/page-object/platforms/(.+)/.+\.rb$}) do |m|
|
9
|
-
["spec/page-object/platforms/#{m[1]}/", "spec/page-object/page-object_spec.rb"]
|
10
|
-
end
|
11
|
-
watch('spec/spec_helper.rb') { "spec" }
|
12
|
-
end
|
13
|
-
|
14
|
-
guard 'cucumber', notification: true, all_after_pass: false, cli: '--profile focus' do
|
15
|
-
watch(%r{^features/.+\.feature$})
|
16
|
-
watch(%r{^features/support/.+$}) { "features" }
|
17
|
-
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
18
|
-
watch(%r{^lib/.+\.rb$}) { "features" }
|
19
|
-
watch(%r{^cucumber.yml$}) { "features" }
|
20
|
-
end
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
|
5
|
+
guard :rspec, cmd: 'rspec --color --format documentation' do
|
6
|
+
watch(%r{^spec/.+_spec\.rb$})
|
7
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
8
|
+
watch(%r{^lib/page-object/platforms/(.+)/.+\.rb$}) do |m|
|
9
|
+
["spec/page-object/platforms/#{m[1]}/", "spec/page-object/page-object_spec.rb"]
|
10
|
+
end
|
11
|
+
watch('spec/spec_helper.rb') { "spec" }
|
12
|
+
end
|
13
|
+
|
14
|
+
guard 'cucumber', notification: true, all_after_pass: false, cli: '--profile focus' do
|
15
|
+
watch(%r{^features/.+\.feature$})
|
16
|
+
watch(%r{^features/support/.+$}) { "features" }
|
17
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
18
|
+
watch(%r{^lib/.+\.rb$}) { "features" }
|
19
|
+
watch(%r{^cucumber.yml$}) { "features" }
|
20
|
+
end
|
data/LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2011-2012 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.
|
1
|
+
Copyright (c) 2011-2012 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
CHANGED
@@ -1,114 +1,114 @@
|
|
1
|
-
# page-object
|
2
|
-
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/page-object.svg)](https://rubygems.org/gems/page-object)
|
4
|
-
[![Build Status](https://travis-ci.org/cheezy/page-object.svg)](https://travis-ci.org/cheezy/page-object)
|
5
|
-
[![Coverage Status](https://coveralls.io/repos/cheezy/page-object/badge.svg?nocache)](https://coveralls.io/r/cheezy/page-object)
|
6
|
-
|
7
|
-
|
8
|
-
A simple gem that assists in creating flexible page objects for testing browser based applications. 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 and selenium-webdriver.
|
9
|
-
|
10
|
-
## Documentation
|
11
|
-
|
12
|
-
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.
|
13
|
-
|
14
|
-
The rdocs for this project can be found at [rubydoc.info](http://rubydoc.info/gems/page-object/frames).
|
15
|
-
|
16
|
-
To see the changes from release to release please look at the [ChangeLog](https://raw.github.com/cheezy/page-object/master/ChangeLog)
|
17
|
-
|
18
|
-
To read about the motivation for this gem please read this [blog entry](http://www.cheezyworld.com/2010/11/19/ui-tests-introducing-a-simple-dsl/)
|
19
|
-
|
20
|
-
There is a book that describes in detail how to use this gem and others to create a complete view of testing web and other types of applications. The book is named [Cucumber & Cheese](http://leanpub.com/cucumber_and_cheese)
|
21
|
-
|
22
|
-
## Support
|
23
|
-
|
24
|
-
If you need help using the page-object gem please ask your questions on [Stack Overflow](http://stackoverflow.com). Please be sure to use the [page-object-gem](http://stackoverflow.com/questions/tagged/page-object-gem) tag. If you wish to report an issue or request a new feature use the [github issue tracking page](http://github.com/cheezy/page-object/issues).
|
25
|
-
|
26
|
-
## Basic Usage
|
27
|
-
|
28
|
-
### Defining your page object
|
29
|
-
|
30
|
-
You define a new page object by including the PageObject module:
|
31
|
-
|
32
|
-
````ruby
|
33
|
-
class LoginPage
|
34
|
-
include PageObject
|
35
|
-
end
|
36
|
-
````
|
37
|
-
|
38
|
-
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:
|
39
|
-
|
40
|
-
````ruby
|
41
|
-
class LoginPage
|
42
|
-
include PageObject
|
43
|
-
|
44
|
-
text_field(:username, :id => 'username')
|
45
|
-
text_field(:password, :id => 'password')
|
46
|
-
button(:login, :id => 'login')
|
47
|
-
end
|
48
|
-
````
|
49
|
-
|
50
|
-
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:
|
51
|
-
|
52
|
-
````ruby
|
53
|
-
login_page.username = 'cheezy'
|
54
|
-
login_page.password = 'secret'
|
55
|
-
login_page.login
|
56
|
-
````
|
57
|
-
|
58
|
-
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:
|
59
|
-
|
60
|
-
````ruby
|
61
|
-
class LoginPage
|
62
|
-
include PageObject
|
63
|
-
|
64
|
-
text_field(:username, :id => 'username')
|
65
|
-
text_field(:password, :id => 'password')
|
66
|
-
button(:login, :id => 'login')
|
67
|
-
|
68
|
-
def login_with(username, password)
|
69
|
-
self.username = username
|
70
|
-
self.password = password
|
71
|
-
login
|
72
|
-
end
|
73
|
-
end
|
74
|
-
````
|
75
|
-
|
76
|
-
and your usage of the page would become:
|
77
|
-
|
78
|
-
````ruby
|
79
|
-
login_page.login_with 'cheezy', 'secret'
|
80
|
-
````
|
81
|
-
|
82
|
-
### Creating your page object
|
83
|
-
page-object supports both [watir](https://github.com/watir/watir) 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 created like this:
|
84
|
-
|
85
|
-
````ruby
|
86
|
-
browser = Watir::Browser.new :firefox
|
87
|
-
my_page_object = MyPageObject.new(browser)
|
88
|
-
````
|
89
|
-
|
90
|
-
or
|
91
|
-
|
92
|
-
````ruby
|
93
|
-
browser = Selenium::WebDriver.for :firefox
|
94
|
-
my_page_object = MyPageObject.new(browser)
|
95
|
-
````
|
96
|
-
|
97
|
-
|
98
|
-
## Known Issues
|
99
|
-
|
100
|
-
See [http://github.com/cheezy/page-object/issues](http://github.com/cheezy/page-object/issues)
|
101
|
-
|
102
|
-
## Contribute
|
103
|
-
|
104
|
-
* Fork the project.
|
105
|
-
* 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.
|
106
|
-
* Make sure you describe your new feature with a cucumber scenario.
|
107
|
-
* Make sure you provide RDoc comments for any new public method you add. Remember, others will be using this gem.
|
108
|
-
* Commit, do not mess with Rakefile, version, or ChangeLog.
|
109
|
-
(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)
|
110
|
-
* Send me a pull request. Bonus points for topic branches.
|
111
|
-
|
112
|
-
## Copyright
|
113
|
-
|
114
|
-
Copyright (c) 2011-2012 Jeffrey S. Morgan. See LICENSE for details.
|
1
|
+
# page-object
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/page-object.svg)](https://rubygems.org/gems/page-object)
|
4
|
+
[![Build Status](https://travis-ci.org/cheezy/page-object.svg)](https://travis-ci.org/cheezy/page-object)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/cheezy/page-object/badge.svg?nocache)](https://coveralls.io/r/cheezy/page-object)
|
6
|
+
|
7
|
+
|
8
|
+
A simple gem that assists in creating flexible page objects for testing browser based applications. 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 and selenium-webdriver.
|
9
|
+
|
10
|
+
## Documentation
|
11
|
+
|
12
|
+
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.
|
13
|
+
|
14
|
+
The rdocs for this project can be found at [rubydoc.info](http://rubydoc.info/gems/page-object/frames).
|
15
|
+
|
16
|
+
To see the changes from release to release please look at the [ChangeLog](https://raw.github.com/cheezy/page-object/master/ChangeLog)
|
17
|
+
|
18
|
+
To read about the motivation for this gem please read this [blog entry](http://www.cheezyworld.com/2010/11/19/ui-tests-introducing-a-simple-dsl/)
|
19
|
+
|
20
|
+
There is a book that describes in detail how to use this gem and others to create a complete view of testing web and other types of applications. The book is named [Cucumber & Cheese](http://leanpub.com/cucumber_and_cheese)
|
21
|
+
|
22
|
+
## Support
|
23
|
+
|
24
|
+
If you need help using the page-object gem please ask your questions on [Stack Overflow](http://stackoverflow.com). Please be sure to use the [page-object-gem](http://stackoverflow.com/questions/tagged/page-object-gem) tag. If you wish to report an issue or request a new feature use the [github issue tracking page](http://github.com/cheezy/page-object/issues).
|
25
|
+
|
26
|
+
## Basic Usage
|
27
|
+
|
28
|
+
### Defining your page object
|
29
|
+
|
30
|
+
You define a new page object by including the PageObject module:
|
31
|
+
|
32
|
+
````ruby
|
33
|
+
class LoginPage
|
34
|
+
include PageObject
|
35
|
+
end
|
36
|
+
````
|
37
|
+
|
38
|
+
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:
|
39
|
+
|
40
|
+
````ruby
|
41
|
+
class LoginPage
|
42
|
+
include PageObject
|
43
|
+
|
44
|
+
text_field(:username, :id => 'username')
|
45
|
+
text_field(:password, :id => 'password')
|
46
|
+
button(:login, :id => 'login')
|
47
|
+
end
|
48
|
+
````
|
49
|
+
|
50
|
+
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:
|
51
|
+
|
52
|
+
````ruby
|
53
|
+
login_page.username = 'cheezy'
|
54
|
+
login_page.password = 'secret'
|
55
|
+
login_page.login
|
56
|
+
````
|
57
|
+
|
58
|
+
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:
|
59
|
+
|
60
|
+
````ruby
|
61
|
+
class LoginPage
|
62
|
+
include PageObject
|
63
|
+
|
64
|
+
text_field(:username, :id => 'username')
|
65
|
+
text_field(:password, :id => 'password')
|
66
|
+
button(:login, :id => 'login')
|
67
|
+
|
68
|
+
def login_with(username, password)
|
69
|
+
self.username = username
|
70
|
+
self.password = password
|
71
|
+
login
|
72
|
+
end
|
73
|
+
end
|
74
|
+
````
|
75
|
+
|
76
|
+
and your usage of the page would become:
|
77
|
+
|
78
|
+
````ruby
|
79
|
+
login_page.login_with 'cheezy', 'secret'
|
80
|
+
````
|
81
|
+
|
82
|
+
### Creating your page object
|
83
|
+
page-object supports both [watir](https://github.com/watir/watir) 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 created like this:
|
84
|
+
|
85
|
+
````ruby
|
86
|
+
browser = Watir::Browser.new :firefox
|
87
|
+
my_page_object = MyPageObject.new(browser)
|
88
|
+
````
|
89
|
+
|
90
|
+
or
|
91
|
+
|
92
|
+
````ruby
|
93
|
+
browser = Selenium::WebDriver.for :firefox
|
94
|
+
my_page_object = MyPageObject.new(browser)
|
95
|
+
````
|
96
|
+
|
97
|
+
|
98
|
+
## Known Issues
|
99
|
+
|
100
|
+
See [http://github.com/cheezy/page-object/issues](http://github.com/cheezy/page-object/issues)
|
101
|
+
|
102
|
+
## Contribute
|
103
|
+
|
104
|
+
* Fork the project.
|
105
|
+
* 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.
|
106
|
+
* Make sure you describe your new feature with a cucumber scenario.
|
107
|
+
* Make sure you provide RDoc comments for any new public method you add. Remember, others will be using this gem.
|
108
|
+
* Commit, do not mess with Rakefile, version, or ChangeLog.
|
109
|
+
(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)
|
110
|
+
* Send me a pull request. Bonus points for topic branches.
|
111
|
+
|
112
|
+
## Copyright
|
113
|
+
|
114
|
+
Copyright (c) 2011-2012 Jeffrey S. Morgan. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
require 'rspec/core/rake_task'
|
4
|
-
require 'cucumber'
|
5
|
-
require 'cucumber/rake/task'
|
6
|
-
require 'coveralls/rake/task'
|
7
|
-
|
8
|
-
Coveralls::RakeTask.new
|
9
|
-
Bundler::GemHelper.install_tasks
|
10
|
-
|
11
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
12
|
-
spec.ruby_opts = "-I lib:spec"
|
13
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
14
|
-
end
|
15
|
-
task :spec
|
16
|
-
|
17
|
-
Cucumber::Rake::Task.new(:features, "Run the cucumber features")
|
18
|
-
|
19
|
-
|
20
|
-
desc 'Run all specs and cukes'
|
21
|
-
task :test => ['spec', 'features']
|
22
|
-
|
23
|
-
task :lib do
|
24
|
-
$LOAD_PATH.unshift(File.expand_path("lib", File.dirname(__FILE__)))
|
25
|
-
end
|
26
|
-
|
27
|
-
task :test_with_coveralls => [:test, 'coveralls:push']
|
28
|
-
|
29
|
-
task :default => :test_with_coveralls
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'cucumber'
|
5
|
+
require 'cucumber/rake/task'
|
6
|
+
require 'coveralls/rake/task'
|
7
|
+
|
8
|
+
Coveralls::RakeTask.new
|
9
|
+
Bundler::GemHelper.install_tasks
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
12
|
+
spec.ruby_opts = "-I lib:spec"
|
13
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
14
|
+
end
|
15
|
+
task :spec
|
16
|
+
|
17
|
+
Cucumber::Rake::Task.new(:features, "Run the cucumber features")
|
18
|
+
|
19
|
+
|
20
|
+
desc 'Run all specs and cukes'
|
21
|
+
task :test => ['spec', 'features']
|
22
|
+
|
23
|
+
task :lib do
|
24
|
+
$LOAD_PATH.unshift(File.expand_path("lib", File.dirname(__FILE__)))
|
25
|
+
end
|
26
|
+
|
27
|
+
task :test_with_coveralls => [:test, 'coveralls:push']
|
28
|
+
|
29
|
+
task :default => :test_with_coveralls
|
data/cucumber.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
<%
|
2
|
-
std_opts = "--no-source --color --format pretty" # Cucumber::Formatter::Fuubar"
|
3
|
-
%>
|
4
|
-
|
5
|
-
default: DRIVER=WATIR <%= std_opts %>
|
6
|
-
selenium: DRIVER=SELENIUM <%= std_opts %>
|
7
|
-
focus: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only --tags @focus
|
8
|
-
|
1
|
+
<%
|
2
|
+
std_opts = "--no-source --color --format pretty" # Cucumber::Formatter::Fuubar"
|
3
|
+
%>
|
4
|
+
|
5
|
+
default: DRIVER=WATIR <%= std_opts %>
|
6
|
+
selenium: DRIVER=SELENIUM <%= std_opts %>
|
7
|
+
focus: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only --tags @focus
|
8
|
+
|
data/lib/page-object.rb
CHANGED
@@ -1,420 +1,431 @@
|
|
1
|
-
require 'watir'
|
2
|
-
require 'page-object/version'
|
3
|
-
require 'page-object/accessors'
|
4
|
-
require 'page-object/element_locators'
|
5
|
-
require 'page-object/nested_elements'
|
6
|
-
require 'page-object/page_factory'
|
7
|
-
require 'page-object/page_populator'
|
8
|
-
require 'page-object/javascript_framework_facade'
|
9
|
-
require 'page-object/indexed_properties'
|
10
|
-
require 'page-object/section_collection'
|
11
|
-
require 'page-object/widgets'
|
12
|
-
|
13
|
-
require 'page-object/platforms/watir'
|
14
|
-
require 'page-object/platforms/watir/page_object'
|
15
|
-
|
16
|
-
#
|
17
|
-
# Module that when included adds functionality to a page object. This module
|
18
|
-
# will add numerous class and instance methods that you use to define and
|
19
|
-
# interact with web pages.
|
20
|
-
#
|
21
|
-
# If we have a login page with a username and password textfield and a login
|
22
|
-
# button we might define our page like the one below. We can then interact with
|
23
|
-
# the object using the generated methods.
|
24
|
-
#
|
25
|
-
# @example Login page example
|
26
|
-
# class LoginPage
|
27
|
-
# include PageObject
|
28
|
-
#
|
29
|
-
# text_field(:username, :id => 'user')
|
30
|
-
# text_field(:password, :id => 'pass')
|
31
|
-
# button(:login, :value => 'Login')
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# ...
|
35
|
-
#
|
36
|
-
# browser = Watir::Browser.new :firefox
|
37
|
-
# login_page = LoginPage.new(browser)
|
38
|
-
# login_page.username = 'cheezy'
|
39
|
-
# login_page.password = 'secret'
|
40
|
-
# login_page.login
|
41
|
-
#
|
42
|
-
# @see PageObject::Accessors to see what class level methods are added to this module at runtime.
|
43
|
-
#
|
44
|
-
module PageObject
|
45
|
-
include ElementLocators
|
46
|
-
include PagePopulator
|
47
|
-
|
48
|
-
def method_missing(method, *args, &block)
|
49
|
-
@root_element.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
#
|
197
|
-
#
|
198
|
-
# the
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
# @
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
# @
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
#
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
251
|
-
# @
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
268
|
-
#
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
#
|
279
|
-
#
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
283
|
-
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
#
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
#
|
301
|
-
#
|
302
|
-
#
|
303
|
-
#
|
304
|
-
#
|
305
|
-
#
|
306
|
-
#
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
#
|
322
|
-
#
|
323
|
-
#
|
324
|
-
#
|
325
|
-
#
|
326
|
-
#
|
327
|
-
#
|
328
|
-
#
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
#
|
347
|
-
#
|
348
|
-
#
|
349
|
-
#
|
350
|
-
#
|
351
|
-
#
|
352
|
-
#
|
353
|
-
#
|
354
|
-
#
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
def
|
408
|
-
|
409
|
-
end
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
end
|
1
|
+
require 'watir'
|
2
|
+
require 'page-object/version'
|
3
|
+
require 'page-object/accessors'
|
4
|
+
require 'page-object/element_locators'
|
5
|
+
require 'page-object/nested_elements'
|
6
|
+
require 'page-object/page_factory'
|
7
|
+
require 'page-object/page_populator'
|
8
|
+
require 'page-object/javascript_framework_facade'
|
9
|
+
require 'page-object/indexed_properties'
|
10
|
+
require 'page-object/section_collection'
|
11
|
+
require 'page-object/widgets'
|
12
|
+
|
13
|
+
require 'page-object/platforms/watir'
|
14
|
+
require 'page-object/platforms/watir/page_object'
|
15
|
+
|
16
|
+
#
|
17
|
+
# Module that when included adds functionality to a page object. This module
|
18
|
+
# will add numerous class and instance methods that you use to define and
|
19
|
+
# interact with web pages.
|
20
|
+
#
|
21
|
+
# If we have a login page with a username and password textfield and a login
|
22
|
+
# button we might define our page like the one below. We can then interact with
|
23
|
+
# the object using the generated methods.
|
24
|
+
#
|
25
|
+
# @example Login page example
|
26
|
+
# class LoginPage
|
27
|
+
# include PageObject
|
28
|
+
#
|
29
|
+
# text_field(:username, :id => 'user')
|
30
|
+
# text_field(:password, :id => 'pass')
|
31
|
+
# button(:login, :value => 'Login')
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# ...
|
35
|
+
#
|
36
|
+
# browser = Watir::Browser.new :firefox
|
37
|
+
# login_page = LoginPage.new(browser)
|
38
|
+
# login_page.username = 'cheezy'
|
39
|
+
# login_page.password = 'secret'
|
40
|
+
# login_page.login
|
41
|
+
#
|
42
|
+
# @see PageObject::Accessors to see what class level methods are added to this module at runtime.
|
43
|
+
#
|
44
|
+
module PageObject
|
45
|
+
include ElementLocators
|
46
|
+
include PagePopulator
|
47
|
+
|
48
|
+
def method_missing(method, *args, &block)
|
49
|
+
if @root_element.respond_to?(method)
|
50
|
+
@root_element.send(method, *args, &block)
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def respond_to_missing?(method, include_all = false)
|
57
|
+
@root_element && @root_element.respond_to?(method) || super
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return the platform browser passed to the constructor
|
61
|
+
attr_reader :browser
|
62
|
+
# @return [PageObject::WatirPageObject] the platform page object
|
63
|
+
attr_reader :platform
|
64
|
+
|
65
|
+
#
|
66
|
+
# Construct a new page object. Prior to browser initialization it will call
|
67
|
+
# a method named initialize_accessors if it exists. Upon initialization of
|
68
|
+
# the page it will call a method named initialize_page if it exists.
|
69
|
+
#
|
70
|
+
# @param [Watir::Browser, Watir::HTMLElement or Selenium::WebDriver::Driver, Selenium::WebDriver::Element] the platform browser/element to use
|
71
|
+
# @param [bool] open the page if page_url is set
|
72
|
+
#
|
73
|
+
def initialize(root, visit=false)
|
74
|
+
initialize_accessors if respond_to?(:initialize_accessors)
|
75
|
+
initialize_browser(root)
|
76
|
+
goto if visit && self.class.instance_methods(false).include?(:goto)
|
77
|
+
initialize_page if respond_to?(:initialize_page)
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize_browser(root)
|
81
|
+
@root_element = PageObject::Platforms::Watir.root_element_for root
|
82
|
+
@browser = root
|
83
|
+
@platform = PageObject::Platforms::Watir.create_page_object @browser
|
84
|
+
end
|
85
|
+
|
86
|
+
# @private
|
87
|
+
def self.included(cls)
|
88
|
+
cls.extend PageObject::Accessors
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Set the default timeout for page level waits
|
93
|
+
#
|
94
|
+
def self.default_page_wait=(timeout)
|
95
|
+
@page_wait = timeout
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Returns the default timeout for page lavel waits
|
100
|
+
#
|
101
|
+
def self.default_page_wait
|
102
|
+
@page_wait ||= 30
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Sets the default timeout for element level waits
|
107
|
+
#
|
108
|
+
def self.default_element_wait=(timeout)
|
109
|
+
@element_wait = timeout
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Returns the default timeout for element level waits
|
114
|
+
#
|
115
|
+
def self.default_element_wait
|
116
|
+
@element_wait ||= 5
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Set the javascript framework to use when determining number of
|
121
|
+
# ajax requests. Valid frameworks are :jquery, :prototype, :yui,
|
122
|
+
# and :angularjs
|
123
|
+
#
|
124
|
+
def self.javascript_framework=(framework)
|
125
|
+
PageObject::JavascriptFrameworkFacade.framework = framework
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Add a new javascript framework to page-object. The module passed
|
130
|
+
# in must adhere to the same prototype as the JQuery and Prototype
|
131
|
+
# modules.
|
132
|
+
#
|
133
|
+
# @param [Symbol] the name used to reference the framework in
|
134
|
+
# subsequent calls
|
135
|
+
# @param [Module] a module that has the necessary methods to perform
|
136
|
+
# the required actions.
|
137
|
+
#
|
138
|
+
def self.add_framework(key, framework)
|
139
|
+
PageObject::JavascriptFrameworkFacade.add_framework(key, framework)
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# get the current page url
|
144
|
+
#
|
145
|
+
def current_url
|
146
|
+
platform.current_url
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# navigate to the provided url
|
151
|
+
#
|
152
|
+
# @param [String] the full url to navigate to
|
153
|
+
#
|
154
|
+
def navigate_to(url)
|
155
|
+
platform.navigate_to(url)
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Returns the text of the current page
|
160
|
+
#
|
161
|
+
def text
|
162
|
+
platform.text
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Returns the html of the current page
|
167
|
+
#
|
168
|
+
def html
|
169
|
+
platform.html
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# Returns the title of the current page
|
174
|
+
#
|
175
|
+
def title
|
176
|
+
platform.title
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Wait until the block returns true or times out
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# @page.wait_until(5, 'Success not found on page') do
|
184
|
+
# @page.text.include? 'Success'
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# @param [Numeric] the amount of time to wait for the block to return true.
|
188
|
+
# @param [String] the message to include with the error if we exceed the timeout duration.
|
189
|
+
# @param block the block to execute. It should return true when successful.
|
190
|
+
#
|
191
|
+
def wait_until(timeout = PageObject.default_page_wait, message = nil, &block)
|
192
|
+
platform.wait_until(timeout, message, &block)
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
#
|
197
|
+
# Wait until there are no pending ajax requests. This requires you
|
198
|
+
# to set the javascript framework in advance.
|
199
|
+
#
|
200
|
+
# @param [Numeric] the amount of time to wait for the block to return true.
|
201
|
+
# @param [String] the message to include with the error if we exceed
|
202
|
+
# the timeout duration.
|
203
|
+
#
|
204
|
+
def wait_for_ajax(timeout = 30, message = nil)
|
205
|
+
end_time = ::Time.now + timeout
|
206
|
+
until ::Time.now > end_time
|
207
|
+
return if browser.execute_script(::PageObject::JavascriptFrameworkFacade.pending_requests) == 0
|
208
|
+
sleep 0.5
|
209
|
+
end
|
210
|
+
message = "Timed out waiting for ajax requests to complete" unless message
|
211
|
+
raise message
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# Override the normal alert popup so it does not occur.
|
216
|
+
#
|
217
|
+
# @example
|
218
|
+
# message = @page.alert do
|
219
|
+
# @page.button_that_causes_alert
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
# @param frame optional parameter used when alert is nested within a frame
|
223
|
+
# @param block a block that has the call that will cause the alert to display
|
224
|
+
# @return [String] the message that was contained in the alert
|
225
|
+
#
|
226
|
+
def alert(frame=nil, &block)
|
227
|
+
platform.alert(frame, &block)
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Override the normal confirm popup so it does not occur.
|
232
|
+
#
|
233
|
+
# @example
|
234
|
+
# message = @popup.confirm(true) do
|
235
|
+
# @page.button_that_causes_confirm
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# @param [bool] what response you want to return back from the confirm popup
|
239
|
+
# @param frame optional parameter used when the confirm is nested within a frame
|
240
|
+
# @param block a block that has the call that will cause the confirm to display
|
241
|
+
# @return [String] the message that was prompted in the confirm
|
242
|
+
#
|
243
|
+
def confirm(response, frame=nil, &block)
|
244
|
+
platform.confirm(response, frame, &block)
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# Override the normal prompt popup so it does not occur.
|
249
|
+
#
|
250
|
+
# @example
|
251
|
+
# message = @popup.prompt("Some Value") do
|
252
|
+
# @page.button_that_causes_prompt
|
253
|
+
# end
|
254
|
+
#
|
255
|
+
# @param [string] the value returned to the caller of the prompt
|
256
|
+
# @param frame optional parameter used with the prompt is nested within a frame
|
257
|
+
# @param block a block that has the call that will cause the prompt to display
|
258
|
+
# @return [Hash] A has containing two keys - :message contains the prompt message and
|
259
|
+
# :default_value contains the default value for the prompt if provided
|
260
|
+
#
|
261
|
+
def prompt(answer, frame=nil, &block)
|
262
|
+
platform.prompt(answer, frame, &block)
|
263
|
+
end
|
264
|
+
|
265
|
+
#
|
266
|
+
# Execute javascript on the browser
|
267
|
+
#
|
268
|
+
# @example Get inner HTML of element
|
269
|
+
# span = @page.span_element
|
270
|
+
# @page.execute_script "return arguments[0].innerHTML", span
|
271
|
+
# #=> "Span innerHTML"
|
272
|
+
#
|
273
|
+
def execute_script(script, *args)
|
274
|
+
args.map! { |e| e.kind_of?(PageObject::Elements::Element) ? e.element : e }
|
275
|
+
platform.execute_script(script, *args)
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# Identify an element as existing within a frame. A frame parameter
|
280
|
+
# is passed to the block and must be passed to the other calls to PageObject.
|
281
|
+
# You can nest calls to in_frame by passing the frame to the next level.
|
282
|
+
#
|
283
|
+
# @example
|
284
|
+
# in_frame(:id => 'frame_id') do |frame|
|
285
|
+
# text_field_element(:id => 'fname', :frame => frame)
|
286
|
+
# end
|
287
|
+
#
|
288
|
+
# @param [Hash] identifier how we find the frame. The valid keys are:
|
289
|
+
# * :id
|
290
|
+
# * :index
|
291
|
+
# * :name
|
292
|
+
# * :class
|
293
|
+
# @param frame passed from a previous call to in_frame. Used to nest calls
|
294
|
+
# @param block that contains the calls to elements that exist inside the frame.
|
295
|
+
#
|
296
|
+
def in_frame(identifier, frame=nil, &block)
|
297
|
+
platform.in_frame(identifier, frame, &block)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Identify an element as existing within an iframe. A frame parameter
|
301
|
+
# is passed to the block and must be passed to the other calls to PageObject.
|
302
|
+
# You can nest calls to in_iframe by passing the frame to the next level.
|
303
|
+
#
|
304
|
+
# @example
|
305
|
+
# in_iframe(:id => 'iframe_id') do |iframe|
|
306
|
+
# text_field_element(:id => 'ifname', :frame => iframe)
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# @param [Hash] identifier how we find the iframe. The valid keys are:
|
310
|
+
# * :id
|
311
|
+
# * :index
|
312
|
+
# * :name
|
313
|
+
# * :class
|
314
|
+
# @param frame passed from a previous call to in_iframe. Used to nest calls
|
315
|
+
# @param block that contains the calls to elements that exist inside the iframe.
|
316
|
+
#
|
317
|
+
def in_iframe(identifier, frame=nil, &block)
|
318
|
+
platform.in_iframe(identifier, frame, &block)
|
319
|
+
end
|
320
|
+
|
321
|
+
#
|
322
|
+
# Override the normal showModalDialog call is it opens a window instead
|
323
|
+
# of a dialog. You will need to attach to the new window in order to
|
324
|
+
# continue.
|
325
|
+
#
|
326
|
+
# @example
|
327
|
+
# @page.modal_dialog do
|
328
|
+
# @page.action_that_spawns_the_modal
|
329
|
+
# end
|
330
|
+
#
|
331
|
+
# @param block a block that contains the call that will cause the modal dialog.
|
332
|
+
#
|
333
|
+
def modal_dialog(&block)
|
334
|
+
script =
|
335
|
+
%Q{
|
336
|
+
window.showModalDialog = function(sURL, vArguments, sFeatures) {
|
337
|
+
window.dialogArguments = vArguments;
|
338
|
+
modalWin = window.open(sURL, 'modal', sFeatures);
|
339
|
+
return modalWin;
|
340
|
+
}
|
341
|
+
}
|
342
|
+
browser.execute_script script
|
343
|
+
yield if block_given?
|
344
|
+
end
|
345
|
+
|
346
|
+
#
|
347
|
+
# Attach to a running window. You can locate the window using either
|
348
|
+
# the window's title or url. If it fails to connect to a window it will
|
349
|
+
# pause for 1 second and try again.
|
350
|
+
#
|
351
|
+
# @example
|
352
|
+
# page.attach_to_window(:title => "other window's title")
|
353
|
+
#
|
354
|
+
# @param [Hash] either :title or :url of the other window. The url does not need to
|
355
|
+
# be the entire url - it can just be the page name like index.html
|
356
|
+
# @param block if present the block is executed and then execution is returned to the
|
357
|
+
# calling window
|
358
|
+
#
|
359
|
+
def attach_to_window(identifier, &block)
|
360
|
+
begin
|
361
|
+
platform.attach_to_window(identifier, &block)
|
362
|
+
rescue
|
363
|
+
sleep 1
|
364
|
+
platform.attach_to_window(identifier, &block)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
#
|
369
|
+
# Find the element that has focus on the page
|
370
|
+
#
|
371
|
+
def element_with_focus
|
372
|
+
platform.element_with_focus
|
373
|
+
end
|
374
|
+
|
375
|
+
#
|
376
|
+
# Refresh to current page
|
377
|
+
#
|
378
|
+
def refresh
|
379
|
+
platform.refresh
|
380
|
+
end
|
381
|
+
|
382
|
+
#
|
383
|
+
# Go back to the previous page
|
384
|
+
#
|
385
|
+
def back
|
386
|
+
platform.back
|
387
|
+
end
|
388
|
+
|
389
|
+
#
|
390
|
+
# Go forward to the next page
|
391
|
+
#
|
392
|
+
def forward
|
393
|
+
platform.forward
|
394
|
+
end
|
395
|
+
|
396
|
+
#
|
397
|
+
# Clear the cookies from the browser
|
398
|
+
#
|
399
|
+
def clear_cookies
|
400
|
+
platform.clear_cookies
|
401
|
+
end
|
402
|
+
|
403
|
+
#
|
404
|
+
# Save the current screenshot to the provided url. File
|
405
|
+
# is saved as a png file.
|
406
|
+
#
|
407
|
+
def save_screenshot(file_name)
|
408
|
+
platform.save_screenshot file_name
|
409
|
+
end
|
410
|
+
|
411
|
+
#
|
412
|
+
# Check if root element exists and is visible
|
413
|
+
#
|
414
|
+
def present?
|
415
|
+
root.present?
|
416
|
+
end
|
417
|
+
|
418
|
+
def self.register_widget(widget_tag, widget_class, base_element_tag)
|
419
|
+
Widgets.register_widget(widget_tag, widget_class, base_element_tag)
|
420
|
+
end
|
421
|
+
|
422
|
+
private
|
423
|
+
|
424
|
+
def root
|
425
|
+
@root_element || PageObject::Platforms::Watir.browser_root_for(browser)
|
426
|
+
end
|
427
|
+
|
428
|
+
def call_block(&block)
|
429
|
+
block.arity == 1 ? block.call(self) : self.instance_eval(&block)
|
430
|
+
end
|
431
|
+
end
|