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 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 < SitePris::Page
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 < SitePris::Page
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 < SitePris::Page
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 < SitePris::Page
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
- #home.has_menu? #=> returns true or false
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, :login_area, Login, "#login_and_registration"
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 'site_prism/element_container'
5
- require 'site_prism/element_checker'
6
- require 'site_prism/page'
7
- require 'site_prism/section'
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, iframe_id)
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, iframe_id
41
- create_nonexistence_checker iframe_name, iframe_id
42
- create_waiter iframe_name, iframe_id
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 iframe_id.split("#").last do
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.using_wait_time 0 do
92
- element_exists? *find_args
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.using_wait_time 0 do
103
- element_does_not_exist? *find_args
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
- Capybara.using_wait_time timeout do
114
- element_exists? *find_args
115
- end
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
- Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementVisibility do
125
- Capybara.using_wait_time 0 do
126
- sleep 0.05 while not element_exists? *find_args, visible: true
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
- Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementInvisibility do
138
- Capybara.using_wait_time 0 do
139
- sleep 0.05 while element_exists? *find_args, visible: true
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
@@ -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
- !(page.current_url =~ url_matcher).nil?
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
@@ -1,4 +1,4 @@
1
1
  module SitePrism
2
- VERSION = "2.4"
2
+ VERSION = "2.5"
3
3
  end
4
4
 
@@ -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'
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-05-18 00:00:00.000000000 Z
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