site_prism 2.4 → 2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +126 -8
- data/lib/site_prism.rb +21 -6
- data/lib/site_prism/element_container.rb +46 -33
- data/lib/site_prism/exceptions.rb +1 -0
- data/lib/site_prism/page.rb +9 -3
- data/lib/site_prism/version.rb +1 -1
- data/lib/site_prism/waiter.rb +21 -0
- metadata +4 -3
data/README.md
CHANGED
@@ -101,7 +101,6 @@ If you are using cucumber, here's what needs requiring:
|
|
101
101
|
|
102
102
|
```ruby
|
103
103
|
require 'capybara'
|
104
|
-
require 'capybara/dsl'
|
105
104
|
require 'capybara/cucumber'
|
106
105
|
require 'selenium-webdriver'
|
107
106
|
require 'site_prism'
|
@@ -113,7 +112,6 @@ If you're using rspec instead, here's what needs requiring:
|
|
113
112
|
|
114
113
|
```ruby
|
115
114
|
require 'capybara'
|
116
|
-
require 'capybara/dsl'
|
117
115
|
require 'capybara/rspec'
|
118
116
|
require 'selenium-webdriver'
|
119
117
|
require 'site_prism'
|
@@ -181,7 +179,7 @@ SitePrism uses the Addressable gem and therefore allows for parameterized URLs.
|
|
181
179
|
a simple example:
|
182
180
|
|
183
181
|
```ruby
|
184
|
-
class UserProfile <
|
182
|
+
class UserProfile < SitePrism::Page
|
185
183
|
set_url "/users{/username}"
|
186
184
|
end
|
187
185
|
```
|
@@ -189,7 +187,7 @@ end
|
|
189
187
|
...and a more complex example:
|
190
188
|
|
191
189
|
```ruby
|
192
|
-
class Search <
|
190
|
+
class Search < SitePrism::Page
|
193
191
|
set_url "/search{?query*}"
|
194
192
|
end
|
195
193
|
```
|
@@ -211,7 +209,7 @@ to the page using `#load`:
|
|
211
209
|
The `#load` method takes parameters and will apply them to the URL. Using the examples above:
|
212
210
|
|
213
211
|
```ruby
|
214
|
-
class UserProfile <
|
212
|
+
class UserProfile < SitePrism::Page
|
215
213
|
set_url "/users{/username}"
|
216
214
|
end
|
217
215
|
|
@@ -223,7 +221,7 @@ end
|
|
223
221
|
...and...
|
224
222
|
|
225
223
|
```ruby
|
226
|
-
class Search <
|
224
|
+
class Search < SitePrism::Page
|
227
225
|
set_url "/search{?query*}"
|
228
226
|
end
|
229
227
|
|
@@ -913,7 +911,7 @@ end
|
|
913
911
|
```ruby
|
914
912
|
@home = Home.new
|
915
913
|
#...
|
916
|
-
|
914
|
+
@home.has_menu? #=> returns true or false
|
917
915
|
```
|
918
916
|
|
919
917
|
Again, this allows pretty test code:
|
@@ -1155,6 +1153,83 @@ end
|
|
1155
1153
|
@results_page.wait_for_search_results(10) #=> waits for 10 seconds instead of the default capybara timeout
|
1156
1154
|
```
|
1157
1155
|
|
1156
|
+
## Using Capybara Query Options
|
1157
|
+
|
1158
|
+
When querying an element, section or a collection of elements or sections, you may
|
1159
|
+
supply Capybara query options as arguments to the element and section methods in order
|
1160
|
+
to refine the results of the query and enable Capybara to wait for all of the conditions
|
1161
|
+
necessary to properly fulfill your request.
|
1162
|
+
|
1163
|
+
Given the following sample page and elements:
|
1164
|
+
|
1165
|
+
```ruby
|
1166
|
+
class SearchResultSection < SitePrism::Section
|
1167
|
+
element :title, "a.title"
|
1168
|
+
element :blurb, "span.result-decription"
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
class SearchResults < SitePrism::Page
|
1172
|
+
element :footer, ".footer"
|
1173
|
+
sections :search_results, SearchResultSection, "#results li"
|
1174
|
+
end
|
1175
|
+
```
|
1176
|
+
|
1177
|
+
Asserting the attributes of an element or section returned by any method may fail if
|
1178
|
+
the page has not finished loading the element(s):
|
1179
|
+
|
1180
|
+
```ruby
|
1181
|
+
@results_page = SearchResults.new
|
1182
|
+
# ...
|
1183
|
+
@results_page.search_results.size.should == 25 # This may fail!
|
1184
|
+
```
|
1185
|
+
|
1186
|
+
The above query can be rewritten to utilize the Capybara :count option when querying for
|
1187
|
+
the collection, which in turn causes Capybara to expect some number of results to be returned.
|
1188
|
+
The method calls below will succeed, provided the elements appear on the page within the timeout:
|
1189
|
+
|
1190
|
+
```ruby
|
1191
|
+
@results_page = SearchResults.new
|
1192
|
+
# ...
|
1193
|
+
@results_page.has_search_results? :count => 25
|
1194
|
+
# OR
|
1195
|
+
@results_page.search_results :count => 25
|
1196
|
+
# OR
|
1197
|
+
@results_page.wait_for_search_results nil, :count => 25 # wait_for_<element_name> expects a timeout value to be passed as the first parameter or nil to use the default timeout value.
|
1198
|
+
```
|
1199
|
+
|
1200
|
+
Now we can write pretty, non-failing tests without hard coding these options
|
1201
|
+
into our page and section classes:
|
1202
|
+
|
1203
|
+
```ruby
|
1204
|
+
Then /^there are search results on the page$/ do
|
1205
|
+
@results.page.should have_search_results :count => 25
|
1206
|
+
end
|
1207
|
+
```
|
1208
|
+
|
1209
|
+
This is supported for all of the Capybara options including, but not limited to :count, :text,
|
1210
|
+
:wait, etc. This can also be used when defining page objects. Eg:
|
1211
|
+
|
1212
|
+
```ruby
|
1213
|
+
class SearchResults < SitePrism::Page
|
1214
|
+
element :footer, ".footer"
|
1215
|
+
element :view_more, "li", text: "View More"
|
1216
|
+
sections :search_results, SearchResultSection, "#results li"
|
1217
|
+
end
|
1218
|
+
```
|
1219
|
+
|
1220
|
+
### Methods Supporting Capybara Options
|
1221
|
+
|
1222
|
+
The following element methods allow Capybara options to be passed as arguments to the method:
|
1223
|
+
|
1224
|
+
```ruby
|
1225
|
+
@results_page.<element_or_section_name> :text => "Welcome!"
|
1226
|
+
@results_page.has_<element_or_section_name>? :count => 25
|
1227
|
+
@results_page.has_no_<element_or_section_name>? :text => "Logout"
|
1228
|
+
@results_page.wait_for_<element_or_section_name> :count => 25
|
1229
|
+
@results_page.wait_until_<element_or_section_name>_visible :text => "Some ajaxy text appears!"
|
1230
|
+
@results_page.wait_until_<element_or_section_name>_invisible :text => "Some ajaxy text disappears!"
|
1231
|
+
```
|
1232
|
+
|
1158
1233
|
## IFrames
|
1159
1234
|
|
1160
1235
|
SitePrism allows you to interact with iframes. An iframe is declared as
|
@@ -1232,7 +1307,7 @@ end
|
|
1232
1307
|
class Home < SitePrism::Page
|
1233
1308
|
set_url "http://www.example.com"
|
1234
1309
|
|
1235
|
-
iframe
|
1310
|
+
iframe :login_area, Login, "#login_and_registration"
|
1236
1311
|
end
|
1237
1312
|
|
1238
1313
|
# cucumber step that performs login
|
@@ -1248,6 +1323,49 @@ When /^I log in$/ do
|
|
1248
1323
|
end
|
1249
1324
|
```
|
1250
1325
|
|
1326
|
+
## SitePrism Configuration
|
1327
|
+
|
1328
|
+
SitePrism can be configured to change its behaviour.
|
1329
|
+
|
1330
|
+
### Using Capybara Implicit Waits
|
1331
|
+
|
1332
|
+
By default, SitePrism element and section methods do not utilize
|
1333
|
+
Capybara's implicit wait methodology and will return immediately if
|
1334
|
+
the element or section requested is not found on the page. Add the
|
1335
|
+
following code to your spec_helper file to enable Capybara's implicit
|
1336
|
+
wait methodology to pass through:
|
1337
|
+
|
1338
|
+
```ruby
|
1339
|
+
SitePrism.configure do |config|
|
1340
|
+
config.use_implicit_waits = true
|
1341
|
+
end
|
1342
|
+
```
|
1343
|
+
|
1344
|
+
This enables you to replace this:
|
1345
|
+
|
1346
|
+
```ruby
|
1347
|
+
# wait_until methods always wait for the element to be present on the page:
|
1348
|
+
@search_page.wait_for_search_results
|
1349
|
+
|
1350
|
+
# Element and section methods do not:
|
1351
|
+
@search_page.search_results
|
1352
|
+
```
|
1353
|
+
|
1354
|
+
with this:
|
1355
|
+
|
1356
|
+
```ruby
|
1357
|
+
# With implicit waits enabled, use of wait_until methods is no longer required. This method will
|
1358
|
+
# wait for the element to be found on the page until the Capybara default timeout is reached.
|
1359
|
+
@search_page.search_results
|
1360
|
+
```
|
1361
|
+
|
1362
|
+
## Using SitePrism with VCR
|
1363
|
+
|
1364
|
+
There's a SitePrism plugin called `site_prism.vcr` that lets you use
|
1365
|
+
SitePrism with the VCR gem. Check it out here:
|
1366
|
+
|
1367
|
+
* https://github.com/nestd/site_prism.vcr
|
1368
|
+
|
1251
1369
|
# Epilogue
|
1252
1370
|
|
1253
1371
|
So, we've seen how to use SitePrism to put together page objects made up
|
data/lib/site_prism.rb
CHANGED
@@ -1,8 +1,23 @@
|
|
1
|
-
require 'addressable/template'
|
2
|
-
require 'site_prism/version'
|
3
1
|
require 'site_prism/exceptions'
|
4
|
-
require '
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
require 'addressable/template'
|
3
|
+
|
4
|
+
module SitePrism
|
5
|
+
autoload :ElementContainer, 'site_prism/element_container'
|
6
|
+
autoload :ElementChecker, 'site_prism/element_checker'
|
7
|
+
autoload :Page, 'site_prism/page'
|
8
|
+
autoload :Section, 'site_prism/section'
|
9
|
+
autoload :Waiter, 'site_prism/waiter'
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :use_implicit_waits
|
13
|
+
|
14
|
+
def configure
|
15
|
+
yield self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
@@use_implicit_waits = false
|
22
|
+
end
|
8
23
|
|
@@ -2,16 +2,16 @@ module SitePrism::ElementContainer
|
|
2
2
|
|
3
3
|
def element(element_name, *find_args)
|
4
4
|
build element_name, *find_args do
|
5
|
-
define_method element_name.to_s do
|
6
|
-
find_first *find_args
|
5
|
+
define_method element_name.to_s do |*runtime_args|
|
6
|
+
find_first *find_args, *runtime_args
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
def elements(collection_name, *find_args)
|
12
12
|
build collection_name, *find_args do
|
13
|
-
define_method collection_name.to_s do
|
14
|
-
find_all *find_args
|
13
|
+
define_method collection_name.to_s do |*runtime_args|
|
14
|
+
find_all *find_args, *runtime_args
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -19,29 +19,32 @@ module SitePrism::ElementContainer
|
|
19
19
|
|
20
20
|
def section(section_name, section_class, *find_args)
|
21
21
|
build section_name, *find_args do
|
22
|
-
define_method section_name do
|
23
|
-
section_class.new self, find_first(*find_args)
|
22
|
+
define_method section_name do | *runtime_args |
|
23
|
+
section_class.new self, find_first(*find_args, *runtime_args)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def sections(section_collection_name, section_class, *find_args)
|
29
29
|
build section_collection_name, *find_args do
|
30
|
-
define_method section_collection_name do
|
31
|
-
find_all(*find_args).collect do |element|
|
30
|
+
define_method section_collection_name do |*runtime_args|
|
31
|
+
find_all(*find_args, *runtime_args).collect do |element|
|
32
32
|
section_class.new self, element
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def iframe(iframe_name, iframe_page_class,
|
38
|
+
def iframe(iframe_name, iframe_page_class, selector)
|
39
|
+
element_selector = deduce_iframe_element_selector(selector)
|
40
|
+
scope_selector = deduce_iframe_scope_selector(selector)
|
41
|
+
|
39
42
|
add_to_mapped_items iframe_name
|
40
|
-
create_existence_checker iframe_name,
|
41
|
-
create_nonexistence_checker iframe_name,
|
42
|
-
create_waiter iframe_name,
|
43
|
+
create_existence_checker iframe_name, element_selector
|
44
|
+
create_nonexistence_checker iframe_name, element_selector
|
45
|
+
create_waiter iframe_name, element_selector
|
43
46
|
define_method iframe_name do |&block|
|
44
|
-
within_frame
|
47
|
+
within_frame scope_selector do
|
45
48
|
block.call iframe_page_class.new
|
46
49
|
end
|
47
50
|
end
|
@@ -87,9 +90,10 @@ module SitePrism::ElementContainer
|
|
87
90
|
def create_existence_checker(element_name, *find_args)
|
88
91
|
method_name = "has_#{element_name.to_s}?"
|
89
92
|
create_helper_method method_name, *find_args do
|
90
|
-
define_method method_name do
|
91
|
-
Capybara.
|
92
|
-
|
93
|
+
define_method method_name do |*runtime_args|
|
94
|
+
wait_time = SitePrism.use_implicit_waits ? Capybara.default_wait_time : 0
|
95
|
+
Capybara.using_wait_time wait_time do
|
96
|
+
element_exists? *find_args, *runtime_args
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
@@ -98,9 +102,10 @@ module SitePrism::ElementContainer
|
|
98
102
|
def create_nonexistence_checker(element_name, *find_args)
|
99
103
|
method_name = "has_no_#{element_name.to_s}?"
|
100
104
|
create_helper_method method_name, *find_args do
|
101
|
-
define_method method_name do
|
102
|
-
Capybara.
|
103
|
-
|
105
|
+
define_method method_name do |*runtime_args|
|
106
|
+
wait_time = SitePrism.use_implicit_waits ? Capybara.default_wait_time : 0
|
107
|
+
Capybara.using_wait_time wait_time do
|
108
|
+
element_does_not_exist? *find_args, *runtime_args
|
104
109
|
end
|
105
110
|
end
|
106
111
|
end
|
@@ -109,10 +114,10 @@ module SitePrism::ElementContainer
|
|
109
114
|
def create_waiter(element_name, *find_args)
|
110
115
|
method_name = "wait_for_#{element_name.to_s}"
|
111
116
|
create_helper_method method_name, *find_args do
|
112
|
-
define_method method_name do |timeout = Capybara.default_wait_time|
|
113
|
-
|
114
|
-
|
115
|
-
|
117
|
+
define_method method_name do |timeout = Capybara.default_wait_time, *runtime_args|
|
118
|
+
Capybara.using_wait_time timeout do
|
119
|
+
element_exists? *find_args, *runtime_args
|
120
|
+
end
|
116
121
|
end
|
117
122
|
end
|
118
123
|
end
|
@@ -120,26 +125,26 @@ module SitePrism::ElementContainer
|
|
120
125
|
def create_visibility_waiter(element_name, *find_args)
|
121
126
|
method_name = "wait_until_#{element_name.to_s}_visible"
|
122
127
|
create_helper_method method_name, *find_args do
|
123
|
-
define_method method_name do |timeout = Capybara.default_wait_time|
|
124
|
-
|
125
|
-
|
126
|
-
|
128
|
+
define_method method_name do |timeout = Capybara.default_wait_time, *runtime_args|
|
129
|
+
Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementVisibility do
|
130
|
+
Capybara.using_wait_time 0 do
|
131
|
+
sleep 0.05 while not element_exists? *find_args, *runtime_args, visible: true
|
132
|
+
end
|
127
133
|
end
|
128
134
|
end
|
129
|
-
end
|
130
135
|
end
|
131
136
|
end
|
132
137
|
|
133
138
|
def create_invisibility_waiter(element_name, *find_args)
|
134
139
|
method_name = "wait_until_#{element_name.to_s}_invisible"
|
135
140
|
create_helper_method method_name, *find_args do
|
136
|
-
define_method method_name do |timeout = Capybara.default_wait_time|
|
137
|
-
|
138
|
-
|
139
|
-
|
141
|
+
define_method method_name do |timeout = Capybara.default_wait_time, *runtime_args|
|
142
|
+
Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementInvisibility do
|
143
|
+
Capybara.using_wait_time 0 do
|
144
|
+
sleep 0.05 while element_exists? *find_args, *runtime_args, visible: true
|
145
|
+
end
|
140
146
|
end
|
141
147
|
end
|
142
|
-
end
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
@@ -148,5 +153,13 @@ module SitePrism::ElementContainer
|
|
148
153
|
raise SitePrism::NoSelectorForElement.new("#{self.class.name} => :#{method_name} needs a selector")
|
149
154
|
end
|
150
155
|
end
|
156
|
+
|
157
|
+
def deduce_iframe_scope_selector(selector)
|
158
|
+
selector.is_a?(Integer) ? selector : selector.split("#").last
|
159
|
+
end
|
160
|
+
|
161
|
+
def deduce_iframe_element_selector(selector)
|
162
|
+
selector.is_a?(Integer) ? "iframe:nth-of-type(#{selector + 1})" : selector
|
163
|
+
end
|
151
164
|
end
|
152
165
|
|
@@ -2,6 +2,7 @@ module SitePrism
|
|
2
2
|
class NoUrlForPage < StandardError; end
|
3
3
|
class NoUrlMatcherForPage < StandardError; end
|
4
4
|
class NoSelectorForElement < StandardError; end
|
5
|
+
class TimeoutException < StandardError; end
|
5
6
|
class TimeOutWaitingForElementVisibility < StandardError; end
|
6
7
|
class TimeOutWaitingForElementInvisibility < StandardError; end
|
7
8
|
end
|
data/lib/site_prism/page.rb
CHANGED
@@ -10,13 +10,19 @@ module SitePrism
|
|
10
10
|
visit expanded_url
|
11
11
|
end
|
12
12
|
|
13
|
-
def displayed?
|
13
|
+
def displayed?(seconds = Waiter.default_wait_time)
|
14
14
|
raise SitePrism::NoUrlMatcherForPage if url_matcher.nil?
|
15
|
-
|
15
|
+
begin
|
16
|
+
Waiter.wait_until_true(seconds) do
|
17
|
+
!(page.current_url =~ url_matcher).nil?
|
18
|
+
end
|
19
|
+
rescue SitePrism::TimeoutException=>e
|
20
|
+
return false
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
def self.set_url page_url
|
19
|
-
@url = page_url
|
25
|
+
@url = page_url.to_s
|
20
26
|
end
|
21
27
|
|
22
28
|
def self.set_url_matcher page_url_matcher
|
data/lib/site_prism/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module SitePrism
|
2
|
+
class Waiter
|
3
|
+
def self.wait_until_true(wait_time_seconds=default_wait_time)
|
4
|
+
start_time = Time.now
|
5
|
+
loop do
|
6
|
+
return true if yield
|
7
|
+
break unless Time.now - start_time <= wait_time_seconds
|
8
|
+
sleep(0.05)
|
9
|
+
end
|
10
|
+
raise SitePrism::TimeoutException.new, "Timed out while waiting for block to return true."
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.default_wait_time
|
14
|
+
@@default_wait_time
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
@@default_wait_time = Capybara.default_wait_time
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: site_prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.5'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capybara
|
@@ -78,12 +78,13 @@ files:
|
|
78
78
|
- lib/site_prism/page.rb
|
79
79
|
- lib/site_prism/section.rb
|
80
80
|
- lib/site_prism/version.rb
|
81
|
+
- lib/site_prism/waiter.rb
|
81
82
|
- lib/site_prism.rb
|
82
83
|
- LICENSE
|
83
84
|
- README.md
|
84
85
|
homepage: http://github.com/natritmeyer/site_prism
|
85
86
|
licenses: []
|
86
|
-
post_install_message:
|
87
|
+
post_install_message: Make sure to add your project/company to https://github.com/natritmeyer/site_prism/wiki/Who-is-using-SitePrism
|
87
88
|
rdoc_options: []
|
88
89
|
require_paths:
|
89
90
|
- lib
|