capybara_page_object 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/capybara_page_object.gemspec +26 -0
- data/cucumber.yml +10 -0
- data/lib/capybara_page_object/class_methods.rb +252 -0
- data/lib/capybara_page_object/element_class_methods.rb +255 -0
- data/lib/capybara_page_object/elements/button_element.rb +13 -0
- data/lib/capybara_page_object/elements/element.rb +85 -0
- data/lib/capybara_page_object/elements/form_element.rb +11 -0
- data/lib/capybara_page_object/elements/list_element.rb +14 -0
- data/lib/capybara_page_object/elements/media_element.rb +47 -0
- data/lib/capybara_page_object/elements/select_list_element.rb +38 -0
- data/lib/capybara_page_object/elements/table_element.rb +50 -0
- data/lib/capybara_page_object/elements/table_row_element.rb +66 -0
- data/lib/capybara_page_object/elements/text_area_element.rb +10 -0
- data/lib/capybara_page_object/elements/text_field_element.rb +14 -0
- data/lib/capybara_page_object/page_factory.rb +54 -0
- data/lib/capybara_page_object/page_object.rb +72 -0
- data/lib/capybara_page_object/version.rb +3 -0
- data/lib/capybara_page_object.rb +11 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1b46c4f3b30e45f161b40fdba0269df229bc881f
|
4
|
+
data.tar.gz: d83d6348573ee3ec0476f6377f511a54dbdfa1f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 72c2e7c49d8e4dd1012210284dddbfb5ade11dc92e8ce39ebacd573258f5ed0ad2735f592b39c0c7ae1edf66e9c30e4ff5d532ad6f10032066c51e1143039d80
|
7
|
+
data.tar.gz: bb15be36933ebf78cd04ad19584e2cd1e953806b544de8a828032224aae35c93e57b1d70f41062fe367eb8f7cf5e1129405906acc0504d78b358f37bb7560ce8
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ryan Stawarz
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# CapybaraPageObject
|
2
|
+
|
3
|
+
This is a partial port of the [`page_object` gem](https://github.com/cheezy/page-object) to use Capybara
|
4
|
+
instead of directly relying upon the Selenium or Waitr drivers.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'capybara_page_object'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install capybara_page_object
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
TODO: Write usage instructions here
|
25
|
+
|
26
|
+
## Development
|
27
|
+
|
28
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
29
|
+
|
30
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
31
|
+
|
32
|
+
## Contributing
|
33
|
+
|
34
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/capybara_page_object. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
35
|
+
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
40
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "capybara/page_object"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'capybara_page_object/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "capybara_page_object"
|
8
|
+
spec.version = CapybaraPageObject::VERSION
|
9
|
+
spec.authors = ["Ryan Stawarz"]
|
10
|
+
spec.email = ["ryan@stawarz.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A Page Object Model to be used with capybara}
|
13
|
+
spec.description = %q{A simple library to abstract out page details from cucumber and browser tests}
|
14
|
+
spec.homepage = "http://github.com/rstawarz/capybara_page_object"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "capybara"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
<%
|
2
|
+
std_opts = "--no-source --color --format pretty" # Cucumber::Formatter::Fuubar"
|
3
|
+
%>
|
4
|
+
|
5
|
+
default: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only
|
6
|
+
watir_webdriver: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only
|
7
|
+
selenium_webdriver: DRIVER=SELENIUM <%= std_opts %> --tags ~@watir_only
|
8
|
+
focus: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only --tags @focus
|
9
|
+
#focus: DRIVER=SELENIUM <%= std_opts %> --tags ~@watir_only --tags @focus
|
10
|
+
|
@@ -0,0 +1,252 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
module ClassMethods
|
3
|
+
#
|
4
|
+
# Set some values that can be used within the class. This is
|
5
|
+
# typically used to provide values that help build dynamic urls in
|
6
|
+
# the page_url method
|
7
|
+
#
|
8
|
+
# @param [Hash] the value to set the params
|
9
|
+
#
|
10
|
+
def params=(the_params)
|
11
|
+
@params = the_params
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Return the params that exist on this page class
|
16
|
+
#
|
17
|
+
def params
|
18
|
+
@params ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Specify the url for the page. A call to this method will generate a
|
23
|
+
# 'goto' method to take you to the page.
|
24
|
+
#
|
25
|
+
# @param [String] the url for the page.
|
26
|
+
# @param [Symbol] a method name to call to get the url
|
27
|
+
#
|
28
|
+
def page_url(url)
|
29
|
+
define_method("goto") do
|
30
|
+
visit self.page_url_value
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method('page_url_value') do
|
34
|
+
url
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Creates a method that compares the expected_title of a page against the actual.
|
40
|
+
# @param [String] expected_title the literal expected title for the page
|
41
|
+
# @param [Regexp] expected_title the expected title pattern for the page
|
42
|
+
# @return [boolean]
|
43
|
+
# @raise An exception if expected_title does not match actual title
|
44
|
+
#
|
45
|
+
# @example Specify 'Google' as the expected title of a page
|
46
|
+
# expected_title "Google"
|
47
|
+
# page.has_expected_title?
|
48
|
+
#
|
49
|
+
def expected_title(expected_title)
|
50
|
+
define_method("has_expected_title?") do
|
51
|
+
page.has_title?(expected_title)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Creates a method that provides a way to initialize a page based upon an expected element.
|
57
|
+
# This is useful for pages that load dynamic content.
|
58
|
+
# @param [Symbol] the name given to the element in the declaration
|
59
|
+
# @param [optional, Integer] timeout default value is 5 seconds
|
60
|
+
# @return [boolean]
|
61
|
+
#
|
62
|
+
# @example Specify a text box named :address expected on the page within 10 seconds
|
63
|
+
# expected_element(:address, 10)
|
64
|
+
# page.has_expected_element?
|
65
|
+
#
|
66
|
+
def expected_element(element_name)
|
67
|
+
define_method("has_expected_element?") do
|
68
|
+
args = self.send("#{element_name}_selector")
|
69
|
+
page.assert_selector(*args)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Creates a method that provides a way to initialize a page based upon an expected element to become visible.
|
76
|
+
# This is useful for pages that load dynamic content and might have hidden elements that are not shown.
|
77
|
+
# @param [Symbol] the name given to the element in the declaration
|
78
|
+
# @param [optional, Integer] timeout default value is 5 seconds
|
79
|
+
# @param [optional, boolean] also check that element to be visible if set to true
|
80
|
+
# @return [boolean]
|
81
|
+
#
|
82
|
+
# @example Specify a text box named :address expected on the page within 10 seconds
|
83
|
+
# expected_element_visible(:address, 10)
|
84
|
+
# page.has_expected_element_visible?
|
85
|
+
#
|
86
|
+
def expected_element_visible(element_name, timeout=Capybara.default_wait_time)
|
87
|
+
define_method("has_expected_element_visible?") do
|
88
|
+
expect(self.send("#{element_name}_element")).to be_visible
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# adds a method to return a collection of generic Element objects
|
94
|
+
# for a specific tag.
|
95
|
+
#
|
96
|
+
#def elements(name, tag=:element, identifier={:index => 0}, &block)
|
97
|
+
## default tag to :element
|
98
|
+
##
|
99
|
+
## elements 'button', css: 'some css'
|
100
|
+
##
|
101
|
+
## is the same as
|
102
|
+
##
|
103
|
+
## elements 'button', :element, css: 'some css'
|
104
|
+
##
|
105
|
+
#if tag.is_a?(Hash)
|
106
|
+
#identifier = tag
|
107
|
+
#tag = :element
|
108
|
+
#end
|
109
|
+
|
110
|
+
#define_method("#{name}_elements") do
|
111
|
+
#return call_block(&block) if block_given?
|
112
|
+
#platform.elements_for(tag, identifier.clone)
|
113
|
+
#end
|
114
|
+
#end
|
115
|
+
|
116
|
+
#
|
117
|
+
# adds a method to return a page object rooted at an element
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
|
121
|
+
# # will generate 'navigation_bar' and 'navigation_bar?'
|
122
|
+
#
|
123
|
+
#def page_section(name, section_class, identifier)
|
124
|
+
#define_method(name) do
|
125
|
+
#platform.page_for(identifier, section_class)
|
126
|
+
#end
|
127
|
+
#end
|
128
|
+
|
129
|
+
#
|
130
|
+
# adds a method to return a collection of page objects rooted at elements
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# page_sections(:articles, Article, :class => 'article')
|
134
|
+
# # will generate 'articles'
|
135
|
+
#
|
136
|
+
#def page_sections(name, section_class, identifier)
|
137
|
+
#define_method(name) do
|
138
|
+
#platform.pages_for(identifier, section_class)
|
139
|
+
#end
|
140
|
+
#end
|
141
|
+
|
142
|
+
#
|
143
|
+
# adds a method that will return an indexed property. The property will respond to
|
144
|
+
# the [] method with an object that has a set of normal page_object properties that
|
145
|
+
# correspond to the definitions included in the identifier_list parameter, with the
|
146
|
+
# "what" of the "how and what" substituted based on the index provided to the []
|
147
|
+
# method.
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# indexed_property(:title, [
|
151
|
+
# [:text_field, :field_1, :id => 'table[%s].field_1'],
|
152
|
+
# [:button, :button_1, :id => 'table[%s].button_1'],
|
153
|
+
# [:text_field, :field_2, :name => 'table[%s].field_2']
|
154
|
+
# ])
|
155
|
+
# # will generate a title method that responds to []. title['foo'] will return an object
|
156
|
+
# # that responds to the normal methods expected for two text_fields and a button with the
|
157
|
+
# # given names, using the given how and what with 'foo' substituted for the %s. title[123]
|
158
|
+
# # will do the same, using the integer 123 instead.
|
159
|
+
#
|
160
|
+
#
|
161
|
+
#def indexed_property (name, identifier_list)
|
162
|
+
#define_method("#{name}") do
|
163
|
+
#IndexedProperties::TableOfElements.new(@browser, identifier_list)
|
164
|
+
#end
|
165
|
+
#end
|
166
|
+
|
167
|
+
def add_element_accessor_method(name, element_klass, finder_options)
|
168
|
+
finder_options = finder_options.dup
|
169
|
+
finder_args = extract_finder_args(finder_options)
|
170
|
+
element_klass ||= CapybaraPageObject::Element
|
171
|
+
define_method("#{name}_element") do
|
172
|
+
e = find(*finder_args)
|
173
|
+
element_klass.new(e, self)
|
174
|
+
end
|
175
|
+
define_method("#{name}_selector") do |options={}|
|
176
|
+
[finder_args.first,
|
177
|
+
finder_args[1],
|
178
|
+
finder_args[2].merge(options)]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_element_query_method(name, finder_options)
|
183
|
+
finder_options = finder_options.dup
|
184
|
+
finder_args = extract_finder_args(finder_options)
|
185
|
+
define_method("has_#{name}?") do |options = {}|
|
186
|
+
args = self.send("#{name}_selector", options)
|
187
|
+
has_selector?(*args)
|
188
|
+
end
|
189
|
+
define_method("has_no_#{name}?") do |options = {}|
|
190
|
+
args = self.send("#{name}_selector", options)
|
191
|
+
has_no_selector?(*args)
|
192
|
+
end
|
193
|
+
define_method("assert_has_#{name}") do |options = {}|
|
194
|
+
args = self.send("#{name}_selector", options)
|
195
|
+
assert_selector(*args)
|
196
|
+
end
|
197
|
+
define_method("assert_has_no_#{name}") do |options = {}|
|
198
|
+
args = self.send("#{name}_selector", options)
|
199
|
+
assert_no_selector(*args)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_value_accessor_method(name)
|
204
|
+
define_method(name) do
|
205
|
+
self.send("#{name}_element").value
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def add_text_accessor_method(name)
|
210
|
+
define_method(name) do
|
211
|
+
self.send("#{name}_element").text
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def add_value_mutator_method(name)
|
216
|
+
define_method("#{name}=") do |value|
|
217
|
+
self.send("#{name}_element").set(value)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def add_click_method(name)
|
222
|
+
define_method(name) do
|
223
|
+
self.send("#{name}_element").click
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def extract_finder_args(finder_options={})
|
228
|
+
finder_type, finder_param = extract_finder_type!(finder_options, :class, :css, :id, :xpath)
|
229
|
+
finder_options.delete(finder_type)
|
230
|
+
case finder_type
|
231
|
+
when :class
|
232
|
+
[:css, ".{finder_param}", finder_options]
|
233
|
+
when :id
|
234
|
+
[:css, "##{finder_param}", finder_options]
|
235
|
+
when :css
|
236
|
+
[finder_type, finder_param, finder_options]
|
237
|
+
when :xpath
|
238
|
+
[finder_type, finder_param, finder_options]
|
239
|
+
else
|
240
|
+
raise "oops"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def extract_finder_type!(options, *types)
|
245
|
+
found_keys = options.select{|k,v| types.include?(k)}
|
246
|
+
unless found_keys.length == 1
|
247
|
+
raise "Incorrect finder type specified '#{found_keys.keys.join(', ')}' - only one of #{types.join(', ')} can be specified at a time."
|
248
|
+
end
|
249
|
+
found_keys.to_a.first
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
module ElementClassMethods
|
3
|
+
|
4
|
+
def self.define_element_methods(element_name, options = {})
|
5
|
+
aliases = options.delete(:aliases) || []
|
6
|
+
aliases.each {|name| define_element_methods(name, options) }
|
7
|
+
element_klass = options.fetch(:element_class, CapybaraPageObject::Element)
|
8
|
+
define_method(element_name) do |name, finder_options|
|
9
|
+
add_element_accessor_method(name, element_klass, finder_options)
|
10
|
+
add_element_query_method(name, finder_options)
|
11
|
+
case options[:default]
|
12
|
+
when :text
|
13
|
+
add_text_accessor_method(name)
|
14
|
+
when :value
|
15
|
+
add_value_accessor_method(name)
|
16
|
+
when :click
|
17
|
+
add_click_method(name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
define_element_methods(:a, default: :click)
|
23
|
+
define_element_methods(:area, default: :click)
|
24
|
+
define_element_methods(:audio, element_class: CapybaraPageObject::MediaElement)
|
25
|
+
define_element_methods(:b, default: :text)
|
26
|
+
define_element_methods(:button, element_class: CapybaraPageObject::ButtonElement,
|
27
|
+
default: :click)
|
28
|
+
define_element_methods(:canvas)
|
29
|
+
define_element_methods(:div, default: :text)
|
30
|
+
define_element_methods(:element, default: :text)
|
31
|
+
define_element_methods(:form, element_class: CapybaraPageObject::FormElement)
|
32
|
+
define_element_methods(:h1, default: :text)
|
33
|
+
define_element_methods(:h2, default: :text)
|
34
|
+
define_element_methods(:h3, default: :text)
|
35
|
+
define_element_methods(:h4, default: :text)
|
36
|
+
define_element_methods(:h5, default: :text)
|
37
|
+
define_element_methods(:h6, default: :text)
|
38
|
+
define_element_methods(:hidden, default: :value,
|
39
|
+
aliases: [:hidden_field])
|
40
|
+
define_element_methods(:image, aliases: [:img])
|
41
|
+
define_element_methods(:label, default: :text)
|
42
|
+
define_element_methods(:link, default: :click)
|
43
|
+
define_element_methods(:list_item, default: :text)
|
44
|
+
define_element_methods(:list_item, default: :text, aliases: [:li])
|
45
|
+
define_element_methods(:ordered_list, default: :text,
|
46
|
+
element_class: ListElement,
|
47
|
+
aliases: [:ol])
|
48
|
+
define_element_methods(:paragraph, default: :text,
|
49
|
+
aliases: [:p])
|
50
|
+
define_element_methods(:span, default: :text)
|
51
|
+
define_element_methods(:svg, default: :text)
|
52
|
+
define_element_methods(:table, element_class: CapybaraPageObject::TableElement,
|
53
|
+
default: :text)
|
54
|
+
define_element_methods(:td, default: :text, aliases: [:cell])
|
55
|
+
define_element_methods(:row, element_class: CapybaraPageObject::TableRowElement,
|
56
|
+
default: :text)
|
57
|
+
define_element_methods(:video, element_class: CapybaraPageObject::MediaElement)
|
58
|
+
define_element_methods(:ul, default: :text,
|
59
|
+
element_class: CapybaraPageObject::ListElement,
|
60
|
+
aliases: [:unordered_list])
|
61
|
+
|
62
|
+
#
|
63
|
+
# adds five methods - one to check, another to uncheck, another
|
64
|
+
# to return the state of a checkbox, another to return
|
65
|
+
# an element representing the checkbox, and
|
66
|
+
# a final method to check the checkbox's existence.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# checkbox(:active, :name => "is_active")
|
70
|
+
# # will generate
|
71
|
+
# # * 'check_active',
|
72
|
+
# # * 'uncheck_active',
|
73
|
+
# # * 'active_checked?',
|
74
|
+
# # * 'active_element',
|
75
|
+
# # * 'active?'
|
76
|
+
#
|
77
|
+
def checkbox(name, finder_options)
|
78
|
+
add_element_accessor_method(name, CapybaraPageObject::Element, finder_options)
|
79
|
+
add_element_query_method(name, finder_options)
|
80
|
+
element_name = "#{name}_element"
|
81
|
+
define_method("check_#{name}") do
|
82
|
+
self.send(element_name).set(true)
|
83
|
+
end
|
84
|
+
define_method("uncheck_#{name}") do
|
85
|
+
self.send(element_name).set(false)
|
86
|
+
end
|
87
|
+
define_method("#{name}_checked?") do
|
88
|
+
self.send(element_name).checked? == true ||
|
89
|
+
self.send(element_name).checked? == 'checked'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# adds three methods - one to set the file for a file field, another to retrieve
|
95
|
+
# the file field element, and another to check it's existence.
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# file_field(:the_file, :css, '#file_to_upload')
|
99
|
+
# # will generate
|
100
|
+
# # * 'the_file=',
|
101
|
+
# # * 'the_file_element',
|
102
|
+
# # * 'the_file?'
|
103
|
+
#
|
104
|
+
def file_field(name, finder_options)
|
105
|
+
add_element_accessor_method(name, CapybaraPageObject::Element, finder_options)
|
106
|
+
add_element_query_method(name, finder_options)
|
107
|
+
define_method("#{name}=") do |value|
|
108
|
+
self.send("#{name}_element").set(value)
|
109
|
+
end
|
110
|
+
define_method("#{name}") do
|
111
|
+
self.send("#{name}_element").value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#
|
116
|
+
# adds four methods - one to select, another to return if a radio button
|
117
|
+
# is selected, another method to return a PageObject::Elements::RadioButton
|
118
|
+
# object representing the radio button element, and another to check
|
119
|
+
# the radio button's existence.
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# radio_button(:north, :css, "#north")
|
123
|
+
# # * will generate
|
124
|
+
# # * 'select_north',
|
125
|
+
# # * 'north_selected?',
|
126
|
+
# # * 'north_element',
|
127
|
+
# # * 'north?' methods
|
128
|
+
#
|
129
|
+
def radio_button(name, finder_options)
|
130
|
+
add_element_accessor_method(name, CapybaraPageObject::Element, finder_options)
|
131
|
+
add_element_query_method(name, finder_options)
|
132
|
+
define_method("select_#{name}") do
|
133
|
+
self.send("#{name}_element").set(true)
|
134
|
+
end
|
135
|
+
define_method("#{name}_selected?") do
|
136
|
+
self.send("#{name}_element").selected?
|
137
|
+
end
|
138
|
+
end
|
139
|
+
alias_method :radio, :radio_button
|
140
|
+
|
141
|
+
#
|
142
|
+
# adds five methods to help interact with a radio button group -
|
143
|
+
# a method to select a radio button in the group by given value/text,
|
144
|
+
# a method to return the values of all radio buttons in the group, a method
|
145
|
+
# to return if a radio button in the group is selected (will return
|
146
|
+
# the text of the selected radio button, if true), a method to return
|
147
|
+
# an array of PageObject::Elements::RadioButton objects representing
|
148
|
+
# the radio button group, and finally a method to check the existence
|
149
|
+
# of the radio button group.
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
# radio_button_group(:color, :css, "input[name='color']")
|
153
|
+
# will generate
|
154
|
+
# * 'select_color',
|
155
|
+
# * 'color_values',
|
156
|
+
# * 'color_selected?',
|
157
|
+
# * 'color_elements',
|
158
|
+
# * 'color?' methods
|
159
|
+
#
|
160
|
+
def radio_button_group(name, finder_options)
|
161
|
+
finder_options = finder_options.dup
|
162
|
+
finder_args = extract_finder_args(finder_options)
|
163
|
+
|
164
|
+
define_method("select_#{name}") do |value|
|
165
|
+
elements = self.send("#{name}_elements")
|
166
|
+
elements.find {|e| e.value == value }.set(true)
|
167
|
+
end
|
168
|
+
define_method("#{name}_values") do
|
169
|
+
self.send("#{name}_elements").map(&:value)
|
170
|
+
end
|
171
|
+
define_method("#{name}_selected?") do
|
172
|
+
elements = self.send("#{name}_elements")
|
173
|
+
selected = elements.select {|e| e.checked? }
|
174
|
+
selected.first ? selected.first.value : false
|
175
|
+
end
|
176
|
+
define_method("#{name}_elements") do
|
177
|
+
all(*finder_args)
|
178
|
+
end
|
179
|
+
define_method("#{name}?") do
|
180
|
+
assert_selector(*finder_args)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
alias_method :radio_group, :radio_button_group
|
184
|
+
|
185
|
+
|
186
|
+
#
|
187
|
+
# adds five methods - one to select an item in a drop-down,
|
188
|
+
# another to fetch the currently selected item text, another
|
189
|
+
# to retrieve the select list element, another to check the
|
190
|
+
# drop down's existence and another to get all the available options
|
191
|
+
# to select from.
|
192
|
+
#
|
193
|
+
# @example
|
194
|
+
# select_list(:state, :css, "#state")
|
195
|
+
# # will generate 'state', 'state=', 'state_element', 'state?', "state_options" methods
|
196
|
+
#
|
197
|
+
def select_list(name, finder_options)
|
198
|
+
add_element_accessor_method(name, CapybaraPageObject::SelectListElement, finder_options)
|
199
|
+
add_element_query_method(name, finder_options)
|
200
|
+
|
201
|
+
element_name = "#{name}_element"
|
202
|
+
define_method(name) do
|
203
|
+
self.send(element_name).value
|
204
|
+
end
|
205
|
+
define_method("selected_#{name}") do
|
206
|
+
within(self.send(element_name)) do
|
207
|
+
find('option[selected]')
|
208
|
+
end
|
209
|
+
end
|
210
|
+
define_method("#{name}=") do |value|
|
211
|
+
element = self.send(element_name)
|
212
|
+
within(element) do
|
213
|
+
find(:option, value).select_option
|
214
|
+
end
|
215
|
+
end
|
216
|
+
define_method("#{name}_options") do
|
217
|
+
element = self.send(element_name)
|
218
|
+
within(element) do
|
219
|
+
all(:css, 'option')
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
alias_method :select, :select_list
|
224
|
+
|
225
|
+
# adds four methods to the page object - one to set text in a text area,
|
226
|
+
# another to retrieve text from a text area, another to return the text
|
227
|
+
# area element, and another to check the text area's existence.
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# text_area(:address, :css, "#address")
|
231
|
+
# # will generate
|
232
|
+
# # * 'address',
|
233
|
+
# # * 'address=',
|
234
|
+
# # * 'address_element',
|
235
|
+
# # * 'address?'
|
236
|
+
#
|
237
|
+
#
|
238
|
+
def text_area(name, finder_options)
|
239
|
+
add_element_accessor_method(name, CapybaraPageObject::TextAreaElement, finder_options)
|
240
|
+
add_element_query_method(name, finder_options)
|
241
|
+
add_value_accessor_method(name)
|
242
|
+
add_value_mutator_method(name)
|
243
|
+
end
|
244
|
+
alias_method :textarea, :text_area
|
245
|
+
|
246
|
+
def text_field(name, finder_options)
|
247
|
+
add_element_accessor_method(name, CapybaraPageObject::TextFieldElement, finder_options)
|
248
|
+
add_element_query_method(name, finder_options)
|
249
|
+
add_value_accessor_method(name)
|
250
|
+
add_value_mutator_method(name)
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class Element
|
3
|
+
attr_accessor :element,
|
4
|
+
:page
|
5
|
+
|
6
|
+
def initialize(element, page)
|
7
|
+
@element = element
|
8
|
+
@page = page
|
9
|
+
end
|
10
|
+
|
11
|
+
def attribute(name)
|
12
|
+
element[name.to_s]
|
13
|
+
end
|
14
|
+
|
15
|
+
def enabled?
|
16
|
+
!element.disabled?
|
17
|
+
end
|
18
|
+
|
19
|
+
def class
|
20
|
+
attribute('class')
|
21
|
+
end
|
22
|
+
alias_method :class_name, :class
|
23
|
+
|
24
|
+
def focus
|
25
|
+
bridge.executeScript("return arguments[0].focus()", native)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parent
|
29
|
+
raise Capybara::NotSupportedByDriverError unless javascript_enabled?
|
30
|
+
element.parent
|
31
|
+
end
|
32
|
+
|
33
|
+
def html
|
34
|
+
case native.class.to_s
|
35
|
+
when /Nokogiri/
|
36
|
+
native.to_html
|
37
|
+
when /Selenium/
|
38
|
+
native['outerHTML']
|
39
|
+
else
|
40
|
+
raise "This driver is not supported for retrieving the html of an element"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def native
|
45
|
+
element.native
|
46
|
+
end
|
47
|
+
|
48
|
+
def scroll_into_view
|
49
|
+
unless element.native.respond_to?(:location_once_scrolled_into_view)
|
50
|
+
raise "Selenium javascript driver required to use 'scroll_into_view'"
|
51
|
+
end
|
52
|
+
element.native.location_once_scrolled_into_view
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method_name, *arguments, &block)
|
56
|
+
if element.respond_to?(method_name, true)
|
57
|
+
element.send(method_name, *arguments, &block)
|
58
|
+
elsif value = element[method_name.to_s]
|
59
|
+
value
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def respond_to_missing?(method_name, include_private = false)
|
66
|
+
element.respond_to?(method_name, include_private) ||
|
67
|
+
element[method_name.to_s] != nil ||
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def within(&block)
|
72
|
+
page.within(element, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def bridge
|
78
|
+
native.instance_variable_get(:@bridge)
|
79
|
+
end
|
80
|
+
|
81
|
+
def javascript_enabled?
|
82
|
+
Capybara.current_driver == Capybara.javascript_driver
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class MediaElement < Element
|
3
|
+
|
4
|
+
def autoplay?
|
5
|
+
true?(attribute(:autoplay))
|
6
|
+
end
|
7
|
+
|
8
|
+
def has_controls?
|
9
|
+
true?(attribute(:controls))
|
10
|
+
end
|
11
|
+
|
12
|
+
def paused?
|
13
|
+
true?(attribute(:paused))
|
14
|
+
end
|
15
|
+
|
16
|
+
def duration
|
17
|
+
duration = attribute(:duration)
|
18
|
+
return duration.to_f if duration
|
19
|
+
end
|
20
|
+
|
21
|
+
def volume
|
22
|
+
volume = attribute(:volume)
|
23
|
+
return volume.to_i if volume
|
24
|
+
end
|
25
|
+
|
26
|
+
def ended?
|
27
|
+
true?(attribute(:ended))
|
28
|
+
end
|
29
|
+
|
30
|
+
def seeking?
|
31
|
+
true?(attribute(:seeking))
|
32
|
+
end
|
33
|
+
|
34
|
+
def loop?
|
35
|
+
true?(attribute(:loop))
|
36
|
+
end
|
37
|
+
|
38
|
+
def muted?
|
39
|
+
true?(attribute(:muted))
|
40
|
+
end
|
41
|
+
|
42
|
+
def true?(value)
|
43
|
+
value == true || value == 'true'
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class SelectListElement < Element
|
3
|
+
|
4
|
+
def selected?(value_or_text)
|
5
|
+
option = selected_option
|
6
|
+
option.value == value_or_text ||
|
7
|
+
option.text == value_or_text
|
8
|
+
end
|
9
|
+
|
10
|
+
def selected_option
|
11
|
+
within do
|
12
|
+
first('option[selected]')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear
|
17
|
+
selected_options.each(&:unselect_option)
|
18
|
+
end
|
19
|
+
|
20
|
+
def selected_options
|
21
|
+
within do
|
22
|
+
all('option[selected]')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def select_value(value)
|
27
|
+
within do
|
28
|
+
all(:css, "option[@value=#{value}]").each(&:select_option)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def selected_values
|
33
|
+
selected_options.map(&:value)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class TableElement < Element
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def each
|
6
|
+
for index in 1..self.rows.length do
|
7
|
+
yield self[index-1]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](row_index)
|
12
|
+
if row_index.kind_of?(String)
|
13
|
+
rows.find do |row|
|
14
|
+
row.columns.any? {|col| col.text.include?(row_index) }
|
15
|
+
end
|
16
|
+
else
|
17
|
+
rows[row_index]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def as_hashes
|
22
|
+
rows[1..-1].map do |row|
|
23
|
+
Hash[headers.zip(row.map(&:text))]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def rows
|
29
|
+
within do
|
30
|
+
all(:xpath, ".//child::tr").map do |row|
|
31
|
+
TableRowElement.new(row, page, self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def last_row
|
37
|
+
the_rows = rows
|
38
|
+
the_rows[the_rows.length - 1]
|
39
|
+
end
|
40
|
+
|
41
|
+
def first_row
|
42
|
+
rows[0]
|
43
|
+
end
|
44
|
+
|
45
|
+
def headers
|
46
|
+
rows[0].columns.map(&:text)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class TableRowElement < Element
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :parent_table
|
6
|
+
|
7
|
+
def initialize(element, page, parent_table = nil)
|
8
|
+
super(element, page)
|
9
|
+
@parent_table = parent_table || find_parent_table
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
for index in 1..self.columns.length do
|
14
|
+
yield self[index-1]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](column_index)
|
19
|
+
if column_index.kind_of?(String)
|
20
|
+
column_index = lookup_index_by_name(column_index)
|
21
|
+
end
|
22
|
+
|
23
|
+
return nil if column_index == nil
|
24
|
+
columns[column_index]
|
25
|
+
end
|
26
|
+
|
27
|
+
def columns
|
28
|
+
within do
|
29
|
+
all(:xpath, ".//child::td|th")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def lookup_index_by_name(column_name)
|
36
|
+
parent_table.headers.find_index{|header_name| header_name.include?(column_name) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Find the parent table based on the current nodes xpath expression
|
40
|
+
# e.g.
|
41
|
+
# irb > path = "/html/body/table[1]/tbody/tr[1]"
|
42
|
+
# irb> paths = path.split("/")
|
43
|
+
# => ["", "html", "body", "table[1]", "tbody", "tr[1]"]
|
44
|
+
# irb> paths.reverse!
|
45
|
+
# => ["tr[1]", "tbody", "table[1]", "body", "html", ""]
|
46
|
+
# irb> index = paths.find_index{|s| s.include?('table') }
|
47
|
+
# => 2
|
48
|
+
# irb> paths = paths[index..-1]
|
49
|
+
# => ["table[1]", "body", "html", ""]
|
50
|
+
# irb> paths.reverse!
|
51
|
+
# => ["", "html", "body", "table[1]"]
|
52
|
+
# irb> paths.join("/")
|
53
|
+
# => "/html/body/table[1]"
|
54
|
+
#
|
55
|
+
def find_parent_table
|
56
|
+
path = element.path
|
57
|
+
paths = path.split("/")
|
58
|
+
paths.reverse!
|
59
|
+
index = paths.find_index{|s| s.include?('table') }
|
60
|
+
paths = paths[index..-1]
|
61
|
+
paths.reverse!
|
62
|
+
page.first(:xpath, paths.join("/"))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
#
|
3
|
+
# @example Making the PageFactory available to your step definitions
|
4
|
+
# World(CapybaraPageObject::PageFactory)
|
5
|
+
#
|
6
|
+
# @example Visiting a page for the first time in a Scenario
|
7
|
+
# goto_page MyPage do |page|
|
8
|
+
# ...
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @example using a page that has already been visited in a Scenario
|
12
|
+
# on_page MyPage do |page|
|
13
|
+
# ....
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
#
|
17
|
+
module PageFactory
|
18
|
+
#
|
19
|
+
# Create and navigate to a page object. The navigation will only work if the
|
20
|
+
# 'page_url' method was set on the page object.
|
21
|
+
#
|
22
|
+
# @param [PageObject, String] a class that has included the
|
23
|
+
# PageObject module or a string containing the name of the class
|
24
|
+
# @param Hash values that is pass through to page class a
|
25
|
+
# available in the @params instance variable.
|
26
|
+
# @param an optional block to be called
|
27
|
+
# @return [PageObject] the newly created page object
|
28
|
+
#
|
29
|
+
def goto_page(page_class, params={:using_params => {}}, &block)
|
30
|
+
new_page(page_class, params, true, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Create a page object.
|
35
|
+
#
|
36
|
+
def new_page(page_class, params={:using_params => {}}, visit=false, &block)
|
37
|
+
page_class = class_from_string(page_class) if page_class.is_a? String
|
38
|
+
merged = page_class.params.merge(params[:using_params])
|
39
|
+
page_class.instance_variable_set("@merged_params", merged) unless merged.empty?
|
40
|
+
@current_page = page_class.new(visit)
|
41
|
+
block.call @current_page if block
|
42
|
+
@current_page
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def class_from_string(str)
|
48
|
+
str.split('::').inject(Object) do |mod, class_name|
|
49
|
+
mod.const_get(class_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
# Module that when included adds functionality to a page object. This module
|
3
|
+
# will add numerous class and instance methods that you use to define and
|
4
|
+
# interact with web pages.
|
5
|
+
#
|
6
|
+
# If we have a login page with a username and password textfield and a login
|
7
|
+
# button we might define our page like the one below. We can then interact with
|
8
|
+
# the object using the generated methods.
|
9
|
+
#
|
10
|
+
# @example Login page example
|
11
|
+
# class LoginPage
|
12
|
+
# include PageObject
|
13
|
+
#
|
14
|
+
# text_field(:username, :id => 'user')
|
15
|
+
# text_field(:password, :id => 'pass')
|
16
|
+
# button(:login, :value => 'Login')
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# login_page = LoginPage.new
|
20
|
+
# login_page.username = 'ryan'
|
21
|
+
# login_page.password = 'starwars'
|
22
|
+
# login_page.login
|
23
|
+
#
|
24
|
+
# @see PageObject::ClassMethods to see what class level methods are added to this module at runtime.
|
25
|
+
#
|
26
|
+
module PageObject
|
27
|
+
include Capybara::DSL
|
28
|
+
|
29
|
+
alias_method :navigate_to, :visit
|
30
|
+
#
|
31
|
+
# Construct a new page object. Prior to browser initialization it will call
|
32
|
+
# a method named initialize_accessors if it exists. Upon initialization of
|
33
|
+
# the page it will call a method named initialize_page if it exists.
|
34
|
+
#
|
35
|
+
#
|
36
|
+
def initialize(visit=false)
|
37
|
+
initialize_accessors if respond_to?(:initialize_accessors)
|
38
|
+
if visit
|
39
|
+
raise "Page must specify `page_url` to use visit functionality" unless respond_to?(:goto)
|
40
|
+
goto
|
41
|
+
end
|
42
|
+
initialize_page if respond_to?(:initialize_page)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.included(base)
|
46
|
+
base.extend(CapybaraPageObject::ClassMethods)
|
47
|
+
base.extend(CapybaraPageObject::ElementClassMethods)
|
48
|
+
end
|
49
|
+
|
50
|
+
def within(element, &block)
|
51
|
+
if element.kind_of?(CapybaraPageObject::Element)
|
52
|
+
super(element.element, &block)
|
53
|
+
else
|
54
|
+
super(element, &block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def go_back
|
59
|
+
page.evaluate_script('window.history.back()')
|
60
|
+
end
|
61
|
+
|
62
|
+
def go_forward
|
63
|
+
page.evaluate_script('window.history.forward()')
|
64
|
+
end
|
65
|
+
|
66
|
+
def reload_page
|
67
|
+
url = [ current_path, page.driver.request.env['QUERY_STRING'] ].reject{|s| s.nil? || s == '' }.join('?')
|
68
|
+
page.visit url
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require "capybara_page_object/version"
|
3
|
+
|
4
|
+
base = File.join(File.dirname(__FILE__), 'capybara_page_object')
|
5
|
+
require File.join(base, 'elements', 'element.rb')
|
6
|
+
Dir.glob(File.join(base, 'elements', '**', '*.rb'), &method(:require))
|
7
|
+
|
8
|
+
require 'capybara_page_object/class_methods'
|
9
|
+
require 'capybara_page_object/element_class_methods'
|
10
|
+
require 'capybara_page_object/page_object'
|
11
|
+
require 'capybara_page_object/page_factory'
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capybara_page_object
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Stawarz
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capybara
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: A simple library to abstract out page details from cucumber and browser
|
70
|
+
tests
|
71
|
+
email:
|
72
|
+
- ryan@stawarz.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- CODE_OF_CONDUCT.md
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- bin/console
|
86
|
+
- bin/setup
|
87
|
+
- capybara_page_object.gemspec
|
88
|
+
- cucumber.yml
|
89
|
+
- lib/capybara_page_object.rb
|
90
|
+
- lib/capybara_page_object/class_methods.rb
|
91
|
+
- lib/capybara_page_object/element_class_methods.rb
|
92
|
+
- lib/capybara_page_object/elements/button_element.rb
|
93
|
+
- lib/capybara_page_object/elements/element.rb
|
94
|
+
- lib/capybara_page_object/elements/form_element.rb
|
95
|
+
- lib/capybara_page_object/elements/list_element.rb
|
96
|
+
- lib/capybara_page_object/elements/media_element.rb
|
97
|
+
- lib/capybara_page_object/elements/select_list_element.rb
|
98
|
+
- lib/capybara_page_object/elements/table_element.rb
|
99
|
+
- lib/capybara_page_object/elements/table_row_element.rb
|
100
|
+
- lib/capybara_page_object/elements/text_area_element.rb
|
101
|
+
- lib/capybara_page_object/elements/text_field_element.rb
|
102
|
+
- lib/capybara_page_object/page_factory.rb
|
103
|
+
- lib/capybara_page_object/page_object.rb
|
104
|
+
- lib/capybara_page_object/version.rb
|
105
|
+
homepage: http://github.com/rstawarz/capybara_page_object
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.2.2
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: A Page Object Model to be used with capybara
|
129
|
+
test_files: []
|