site_prism 2.4 → 2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|