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 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