site_prism 2.6 → 2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +124 -76
- data/lib/site_prism.rb +3 -3
- data/lib/site_prism/addressable_url_matcher.rb +136 -0
- data/lib/site_prism/element_checker.rb +6 -5
- data/lib/site_prism/element_container.rb +133 -126
- data/lib/site_prism/exceptions.rb +2 -1
- data/lib/site_prism/page.rb +70 -23
- data/lib/site_prism/section.rb +12 -17
- data/lib/site_prism/version.rb +1 -2
- data/lib/site_prism/waiter.rb +4 -8
- metadata +23 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cecd18603e2b752a61108228d5d0977ebbd8117
|
4
|
+
data.tar.gz: cdbd3e91b71ce10e2f1fa210c76f7e0abe47307a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf99da3a4830b9bda41b26f548dbd8694e05e14122464c72503790cc00ff32bfc20c29c8d118726df5a9e264bdcfff33345068141b9e982ff95064c879ddee8d
|
7
|
+
data.tar.gz: c21eca71f43629070428a85bf7e7b1661b6a1af2e7d426490ffc4e20dd61ff9355e633a80140795f3296aaad6e0994ad4ff586e28b3e26cad683f8b0355f8013
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ class SearchResults < SitePrism::Page
|
|
29
29
|
|
30
30
|
section :menu, MenuSection, "#gbx3"
|
31
31
|
sections :search_results, SearchResultSection, "#results li"
|
32
|
-
|
32
|
+
|
33
33
|
def search_result_links
|
34
34
|
search_results.map {|sr| sr.title['href']}
|
35
35
|
end
|
@@ -57,9 +57,9 @@ end
|
|
57
57
|
|
58
58
|
Then /^the home page should contain the menu and the search form$/ do
|
59
59
|
@home.wait_for_menu # menu loads after a second or 2, give it time to arrive
|
60
|
-
@home.
|
61
|
-
@home.
|
62
|
-
@home.
|
60
|
+
expect(@home).to have_menu
|
61
|
+
expect(@home).to have_search_field
|
62
|
+
expect(@home).to have_search_button
|
63
63
|
end
|
64
64
|
|
65
65
|
When /^I search for Sausages$/ do
|
@@ -69,17 +69,16 @@ end
|
|
69
69
|
|
70
70
|
Then /^the search results page is displayed$/ do
|
71
71
|
@results_page = SearchResults.new
|
72
|
-
@results_page.
|
72
|
+
expect(@results_page).to be_displayed
|
73
73
|
end
|
74
74
|
|
75
75
|
Then /^the search results page contains 10 individual search results$/ do
|
76
76
|
@results_page.wait_for_search_results
|
77
|
-
@results_page.
|
78
|
-
@results_page.search_results.size.should == 10
|
77
|
+
expect(@results_page).to have_search_results count: 10
|
79
78
|
end
|
80
79
|
|
81
80
|
Then /^the search results contain a link to the wikipedia sausages page$/ do
|
82
|
-
@results_page.search_result_links.
|
81
|
+
expect(@results_page.search_result_links).to include "http://en.wikipedia.org/wiki/Sausage"
|
83
82
|
end
|
84
83
|
```
|
85
84
|
|
@@ -238,61 +237,87 @@ See https://github.com/sporkmonger/addressable for more details on parameterized
|
|
238
237
|
### Verifying that a particular page is displayed
|
239
238
|
|
240
239
|
Automated tests often need to verify that a particular page is
|
241
|
-
displayed.
|
242
|
-
|
243
|
-
|
244
|
-
matches a regular expression. For example, though `account/1` and `account/2`
|
245
|
-
are the same page, their URLs are different. To deal with this,
|
246
|
-
SitePrism provides the ability to set a URL matcher.
|
240
|
+
displayed. SitePrism can automatically parse your URL template
|
241
|
+
and verify that whatever components your template specifies match the
|
242
|
+
currently viewed page. For example, with the following URL template:
|
247
243
|
|
248
244
|
```ruby
|
249
245
|
class Account < SitePrism::Page
|
250
|
-
|
246
|
+
set_url "/accounts/{id}{?query*}"
|
251
247
|
end
|
252
248
|
```
|
253
249
|
|
254
|
-
|
255
|
-
displayed:
|
250
|
+
The following test code would pass:
|
256
251
|
|
257
252
|
```ruby
|
258
253
|
@account_page = Account.new
|
259
|
-
|
260
|
-
|
254
|
+
@account_page.load(id: 22, query: { token: "ca2786616a4285bc" })
|
255
|
+
|
256
|
+
expect(@account_page.current_url).to end_with "/accounts/22?token=ca2786616a4285bc"
|
257
|
+
expect(@account_page).to be_displayed
|
261
258
|
```
|
262
259
|
|
263
260
|
Calling `#displayed?` will return true if the browser's current URL
|
264
|
-
matches the
|
265
|
-
in the above example (`account/1` and `account/2`), calling
|
266
|
-
`@account_page.displayed?` will return true for both examples.
|
261
|
+
matches the page's template and false if it doesn't.
|
267
262
|
|
268
|
-
####
|
263
|
+
#### Specifying parameter values for templated URLs
|
269
264
|
|
270
|
-
|
271
|
-
|
265
|
+
Sometimes you want to verify not just that the current URL matches the
|
266
|
+
template, but that you're looking at a specific page matching that
|
267
|
+
template.
|
268
|
+
|
269
|
+
Given the previous example, if you wanted to ensure that the browser had loaded
|
270
|
+
account number 22, you could assert the following:
|
272
271
|
|
273
272
|
```ruby
|
274
|
-
|
275
|
-
@account_page.should be_displayed
|
276
|
-
@some_other_page.should_not be_displayed
|
277
|
-
end
|
273
|
+
expect(@account_page).to be_displayed(id: 22)
|
278
274
|
```
|
279
275
|
|
280
|
-
|
281
|
-
|
282
|
-
|
276
|
+
You can even use regular expressions. If, as a contrived example, you wanted to
|
277
|
+
ensure that the browser was displaying an account with an id ending with 2, you could
|
278
|
+
say:
|
283
279
|
|
284
280
|
```ruby
|
285
|
-
|
286
|
-
|
287
|
-
|
281
|
+
expect(@account_page).to be_displayed(id: /2\z/)
|
282
|
+
```
|
283
|
+
|
284
|
+
#### Accessing specific matches from a templated URL in your tests
|
285
|
+
|
286
|
+
If passing options to `displayed?` isn't powerful enough to meet your
|
287
|
+
needs, you can directly access and assert on the `url_matches` found
|
288
|
+
when comparing your page's URL template to the current_url:
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
@account_page = Account.new
|
292
|
+
@account_page.load(id: 22, query: { token: "ca2786616a4285bc", color: 'irrelevant' })
|
293
|
+
|
294
|
+
expect(@account_page).to be_displayed(id: 22)
|
295
|
+
expect(@account_page.url_matches['query']['token']).to eq "ca2786616a4285bc"
|
296
|
+
```
|
297
|
+
|
298
|
+
#### Falling back to basic regexp matchers
|
299
|
+
|
300
|
+
If SitePrism's built-in URL matching is not sufficient for your needs
|
301
|
+
you can override and use SitePrism's previous support for regular expression-based
|
302
|
+
URL matchers by it by calling `set_url_matcher`:
|
303
|
+
|
304
|
+
```ruby
|
305
|
+
class Account < SitePrism::Page
|
306
|
+
set_url_matcher %r{/accounts/\d+}
|
288
307
|
end
|
289
308
|
```
|
290
309
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
310
|
+
#### Testing for Page display
|
311
|
+
|
312
|
+
SitePrism's `#displayed?` predicate method allows for semantic code in
|
313
|
+
your test:
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
Then /^the account page is displayed$/ do
|
317
|
+
expect(@account_page).to be_displayed
|
318
|
+
expect(@some_other_page).not_to be_displayed
|
319
|
+
end
|
320
|
+
```
|
296
321
|
|
297
322
|
### Getting the Current Page's URL
|
298
323
|
|
@@ -306,7 +331,7 @@ end
|
|
306
331
|
@account = Account.new
|
307
332
|
#...
|
308
333
|
@account.current_url #=> "http://www.example.com/account/123"
|
309
|
-
@account.current_url.
|
334
|
+
expect(@account.current_url).to include "example.com/account/"
|
310
335
|
```
|
311
336
|
|
312
337
|
### Page Title
|
@@ -336,7 +361,7 @@ end
|
|
336
361
|
@account = Account.new
|
337
362
|
#...
|
338
363
|
@account.secure? #=> true/false
|
339
|
-
@account.
|
364
|
+
expect(@account).to be_secure
|
340
365
|
```
|
341
366
|
|
342
367
|
## Elements
|
@@ -412,14 +437,14 @@ end
|
|
412
437
|
|
413
438
|
```ruby
|
414
439
|
Then /^the search field exists$/ do
|
415
|
-
@home.
|
440
|
+
expect(@home).to have_search_field
|
416
441
|
end
|
417
442
|
```
|
418
443
|
|
419
444
|
#### Testing that an element does not exist
|
420
445
|
|
421
446
|
To test that an element does not exist on the page, it is not possible to just call
|
422
|
-
`#
|
447
|
+
`#not_to have_search_field`. SitePrism supplies the `#has_no_<element>?` method
|
423
448
|
that should be used to test for non-existence. Using the above example:
|
424
449
|
|
425
450
|
```ruby
|
@@ -432,7 +457,7 @@ that should be used to test for non-existence. Using the above example:
|
|
432
457
|
|
433
458
|
```ruby
|
434
459
|
Then /^the search field exists$/ do
|
435
|
-
@home.
|
460
|
+
expect(@home).to have_no_search_field #NB: NOT => expect(@home).not_to_ have_search_field
|
436
461
|
end
|
437
462
|
```
|
438
463
|
|
@@ -575,9 +600,9 @@ arrays:
|
|
575
600
|
|
576
601
|
```ruby
|
577
602
|
@friends_page.names.each {|name| puts name.text}
|
578
|
-
@friends_page.names.map {|name| name.text}.
|
579
|
-
@friends_page.names.size.
|
580
|
-
@friends_page.
|
603
|
+
expect(@friends_page.names.map {|name| name.text}.to eq ["Alice", "Bob", "Fred"]
|
604
|
+
expect(@friends_page.names.size).to eq 3
|
605
|
+
expect(@friends_page).to have(3).names
|
581
606
|
```
|
582
607
|
|
583
608
|
#### Testing for the existence of the element collection
|
@@ -604,7 +629,7 @@ end
|
|
604
629
|
|
605
630
|
```ruby
|
606
631
|
Then /^there should be some names listed on the page$/ do
|
607
|
-
@friends_page.
|
632
|
+
expect(@friends_page).to have_names
|
608
633
|
end
|
609
634
|
```
|
610
635
|
|
@@ -641,7 +666,7 @@ to wait for:
|
|
641
666
|
Like the individual elements, calling the `elements` method will create
|
642
667
|
two methods: `wait_until_<elements_name>_visible` and
|
643
668
|
`wait_until_<elements_name>_invisible`. Calling these methods will cause
|
644
|
-
your test to wait for the elements to become visible or
|
669
|
+
your test to wait for the elements to become visible or invisible. Using
|
645
670
|
the above example:
|
646
671
|
|
647
672
|
```ruby
|
@@ -674,7 +699,7 @@ present in the browser, false if they're not all there.
|
|
674
699
|
# and...
|
675
700
|
|
676
701
|
Then /^the friends page contains all the expected elements$/ do
|
677
|
-
@friends_page.
|
702
|
+
expect(@friends_page).to be_all_there
|
678
703
|
end
|
679
704
|
|
680
705
|
```
|
@@ -760,7 +785,7 @@ selector that will be used to find the root element of the section; this
|
|
760
785
|
root node becomes the 'scope' of the section.
|
761
786
|
|
762
787
|
The following shows that though the same section can appear on multiple
|
763
|
-
pages, it can take a different root node:
|
788
|
+
pages, it can take a different root node:
|
764
789
|
|
765
790
|
```ruby
|
766
791
|
# define the section that appears on both pages
|
@@ -826,10 +851,10 @@ end
|
|
826
851
|
|
827
852
|
```ruby
|
828
853
|
Then /^the home page menu contains a link to the various search functions$/ do
|
829
|
-
@home.menu.
|
830
|
-
@home.menu.search['href'].
|
831
|
-
@home.menu.
|
832
|
-
@home.menu.
|
854
|
+
expect(@home.menu).to have_search
|
855
|
+
expect(@home.menu.search['href']).to include "google.com"
|
856
|
+
expect(@home.menu).to have_images
|
857
|
+
expect(@home.menu).to have_maps
|
833
858
|
end
|
834
859
|
```
|
835
860
|
|
@@ -917,8 +942,8 @@ end
|
|
917
942
|
Again, this allows pretty test code:
|
918
943
|
|
919
944
|
```ruby
|
920
|
-
@home.
|
921
|
-
@home.
|
945
|
+
expect(@home).to have_menu
|
946
|
+
expect(@home).not_to have_menu
|
922
947
|
```
|
923
948
|
|
924
949
|
#### Waiting for a section to exist
|
@@ -981,7 +1006,7 @@ sections within sections within sections within sections!
|
|
981
1006
|
|
982
1007
|
```ruby
|
983
1008
|
|
984
|
-
# define a page that contains an area that contains a section for both logging in and registration, then modelling each of the sub sections
|
1009
|
+
# define a page that contains an area that contains a section for both logging in and registration, then modelling each of the sub sections separately
|
985
1010
|
|
986
1011
|
class Login < SitePrism::Section
|
987
1012
|
element :username, "#username"
|
@@ -1010,8 +1035,8 @@ Then /^I sign in$/ do
|
|
1010
1035
|
@home = Home.new
|
1011
1036
|
@home.load
|
1012
1037
|
@home.wait_for_login_and_registration
|
1013
|
-
@home.
|
1014
|
-
@home.login_and_registration.
|
1038
|
+
expect(@home).to have_login_and_registration
|
1039
|
+
expect(@home.login_and_registration).to have_username
|
1015
1040
|
@home.login_and_registration.login.username.set "bob"
|
1016
1041
|
@home.login_and_registration.login.password.set "p4ssw0rd"
|
1017
1042
|
@home.login_and_registration.login.sign_in.click
|
@@ -1022,8 +1047,8 @@ end
|
|
1022
1047
|
When /^I enter my name into the home page's registration form$/ do
|
1023
1048
|
@home = Home.new
|
1024
1049
|
@home.load
|
1025
|
-
@home.login_and_registration.
|
1026
|
-
@home.login_and_registration.
|
1050
|
+
expect(@home.login_and_registration).to have_first_name
|
1051
|
+
expect(@home.login_and_registration).to have_last_name
|
1027
1052
|
@home.login_and_registration.first_name.set "Bob"
|
1028
1053
|
# ...
|
1029
1054
|
end
|
@@ -1049,7 +1074,7 @@ as an ordinary section:
|
|
1049
1074
|
|
1050
1075
|
```ruby
|
1051
1076
|
@home = Home.new
|
1052
|
-
@home.menu.
|
1077
|
+
expect(@home.menu).to have_title
|
1053
1078
|
```
|
1054
1079
|
|
1055
1080
|
### Section Collections
|
@@ -1097,10 +1122,10 @@ end
|
|
1097
1122
|
|
1098
1123
|
```ruby
|
1099
1124
|
Then /^there are lots of search_results$/ do
|
1100
|
-
@results_page.search_results.size.
|
1125
|
+
expect(@results_page.search_results.size).to eq 10
|
1101
1126
|
@results_page.search_results.each do |search_result|
|
1102
|
-
search_result.
|
1103
|
-
search_result.blurb.text.
|
1127
|
+
expect(search_result).to have_title
|
1128
|
+
expect(search_result.blurb.text).not_to be_nil
|
1104
1129
|
end
|
1105
1130
|
end
|
1106
1131
|
```
|
@@ -1121,7 +1146,7 @@ define a single anonymous section:
|
|
1121
1146
|
|
1122
1147
|
```ruby
|
1123
1148
|
class SearchResults < SitePrism::Page
|
1124
|
-
sections :search_results,
|
1149
|
+
sections :search_results, "#results li" do
|
1125
1150
|
element :title, "a.title"
|
1126
1151
|
element :blurb, "span.result-decription"
|
1127
1152
|
end
|
@@ -1159,7 +1184,7 @@ end
|
|
1159
1184
|
|
1160
1185
|
```ruby
|
1161
1186
|
Then /^there are search results on the page$/ do
|
1162
|
-
@results.page.
|
1187
|
+
expect(@results.page).to have_search_results
|
1163
1188
|
end
|
1164
1189
|
```
|
1165
1190
|
|
@@ -1217,7 +1242,7 @@ the page has not finished loading the element(s):
|
|
1217
1242
|
```ruby
|
1218
1243
|
@results_page = SearchResults.new
|
1219
1244
|
# ...
|
1220
|
-
@results_page.search_results.size.
|
1245
|
+
expect(@results_page.search_results.size).to == 25 # This may fail!
|
1221
1246
|
```
|
1222
1247
|
|
1223
1248
|
The above query can be rewritten to utilize the Capybara :count option when querying for
|
@@ -1239,7 +1264,7 @@ into our page and section classes:
|
|
1239
1264
|
|
1240
1265
|
```ruby
|
1241
1266
|
Then /^there are search results on the page$/ do
|
1242
|
-
@results.page.
|
1267
|
+
expect(@results.page).to have_search_results :count => 25
|
1243
1268
|
end
|
1244
1269
|
```
|
1245
1270
|
|
@@ -1267,6 +1292,30 @@ The following element methods allow Capybara options to be passed as arguments t
|
|
1267
1292
|
@results_page.wait_until_<element_or_section_name>_invisible :text => "Some ajaxy text disappears!"
|
1268
1293
|
```
|
1269
1294
|
|
1295
|
+
## Test views with Page objects
|
1296
|
+
|
1297
|
+
It's possible to use the same page objects of integration tests for view tests, too,
|
1298
|
+
just pass the rendered HTML to the ```load``` method:
|
1299
|
+
|
1300
|
+
```ruby
|
1301
|
+
require 'spec_helper'
|
1302
|
+
|
1303
|
+
describe 'admin/things/index' do
|
1304
|
+
let(:list_page) { AdminThingsListPage.new }
|
1305
|
+
let(:thing) { build(:thing, some_attribute: 'some attribute') }
|
1306
|
+
|
1307
|
+
it 'contains the things we expect' do
|
1308
|
+
assign(:things, [thing])
|
1309
|
+
|
1310
|
+
render template: 'admin/things/index'
|
1311
|
+
|
1312
|
+
list_page.load(rendered)
|
1313
|
+
|
1314
|
+
expect(list_page.rows.first.some_attribute).to have_text('some attribute')
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
```
|
1318
|
+
|
1270
1319
|
## IFrames
|
1271
1320
|
|
1272
1321
|
SitePrism allows you to interact with iframes. An iframe is declared as
|
@@ -1311,7 +1360,7 @@ the above example, here's how it's done:
|
|
1311
1360
|
@page = PageContainingIframe.new
|
1312
1361
|
# ...
|
1313
1362
|
@page.has_my_iframe? #=> true
|
1314
|
-
@page.
|
1363
|
+
expect(@page).to have_my_iframe
|
1315
1364
|
```
|
1316
1365
|
|
1317
1366
|
### Waiting for an iframe
|
@@ -1416,12 +1465,12 @@ all over the place. Here's an example of this common problem:
|
|
1416
1465
|
@home.search_field.set "Sausages"
|
1417
1466
|
@home.search_field.search_button.click
|
1418
1467
|
@results_page = SearchResults.new # <-- noise
|
1419
|
-
@results_page.
|
1468
|
+
expect(@results_page).to have_search_result_items
|
1420
1469
|
```
|
1421
1470
|
|
1422
1471
|
The annoyance (and, later, maintenance nightmare) is having to create
|
1423
1472
|
`@home` and `@results_page`. It would be better to not have to create
|
1424
|
-
instances of pages all over your tests.
|
1473
|
+
instances of pages all over your tests.
|
1425
1474
|
|
1426
1475
|
The way I've dealt with this problem is to create a class containing
|
1427
1476
|
methods that return instances of the pages. Eg:
|
@@ -1471,7 +1520,7 @@ When /^I search for Sausages$/ do
|
|
1471
1520
|
end
|
1472
1521
|
|
1473
1522
|
Then /^I am on the results page$/ do
|
1474
|
-
@app.results_page.
|
1523
|
+
expect(@app.results_page).to be_displayed
|
1475
1524
|
end
|
1476
1525
|
|
1477
1526
|
# etc...
|
@@ -1480,4 +1529,3 @@ end
|
|
1480
1529
|
The only thing that needs instantiating is the App class - from then on
|
1481
1530
|
pages don't need to be initialized, they are now returned by methods on
|
1482
1531
|
@app. Maintenance win!
|
1483
|
-
|
data/lib/site_prism.rb
CHANGED
@@ -7,7 +7,8 @@ module SitePrism
|
|
7
7
|
autoload :Page, 'site_prism/page'
|
8
8
|
autoload :Section, 'site_prism/section'
|
9
9
|
autoload :Waiter, 'site_prism/waiter'
|
10
|
-
|
10
|
+
autoload :AddressableUrlMatcher, 'site_prism/addressable_url_matcher'
|
11
|
+
|
11
12
|
class << self
|
12
13
|
attr_accessor :use_implicit_waits
|
13
14
|
|
@@ -18,6 +19,5 @@ module SitePrism
|
|
18
19
|
|
19
20
|
private
|
20
21
|
|
21
|
-
|
22
|
+
@use_implicit_waits = false
|
22
23
|
end
|
23
|
-
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module SitePrism
|
5
|
+
class AddressableUrlMatcher
|
6
|
+
COMPONENT_NAMES = %w(scheme user password host port path query fragment).map(&:to_sym).freeze
|
7
|
+
COMPONENT_PREFIXES = {
|
8
|
+
query: '?',
|
9
|
+
fragment: '#'
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
attr_reader :pattern
|
13
|
+
|
14
|
+
def initialize(pattern)
|
15
|
+
@pattern = pattern
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return the hash of extracted mappings from parsing the provided URL according to our pattern,
|
19
|
+
# or nil if the URL doesn't conform to the matcher template.
|
20
|
+
def mappings(url)
|
21
|
+
uri = Addressable::URI.parse(url)
|
22
|
+
result = {}
|
23
|
+
COMPONENT_NAMES.each do |component|
|
24
|
+
component_result = component_matches(component, uri)
|
25
|
+
result = component_result ? result.merge!(component_result) : nil
|
26
|
+
break unless result
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
# Determine whether URL matches our pattern, and optionally whether the extracted mappings match
|
32
|
+
# a hash of expected values. You can specify values as strings, numbers or regular expressions.
|
33
|
+
def matches?(url, expected_mappings = {})
|
34
|
+
actual_mappings = mappings(url)
|
35
|
+
if actual_mappings
|
36
|
+
expected_mappings.empty? ? true : all_expected_mappings_match?(expected_mappings, actual_mappings)
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def all_expected_mappings_match?(expected_mappings, actual_mappings)
|
45
|
+
expected_mappings.all? do |key, expected_value|
|
46
|
+
actual_value = actual_mappings[key.to_s]
|
47
|
+
case expected_value
|
48
|
+
when Numeric
|
49
|
+
actual_value == expected_value.to_s
|
50
|
+
when Regexp
|
51
|
+
actual_value.match(expected_value)
|
52
|
+
else
|
53
|
+
expected_value == actual_value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Memoizes the extracted component templates
|
59
|
+
def component_templates
|
60
|
+
@component_templates ||= extract_component_templates
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_component_templates
|
64
|
+
COMPONENT_NAMES.each_with_object({}) do |component, component_templates|
|
65
|
+
component_url = to_substituted_uri.public_send(component).to_s
|
66
|
+
|
67
|
+
next unless component_url && component_url != ''
|
68
|
+
|
69
|
+
reverse_substitutions.each_pair do |substituted_value, template_value|
|
70
|
+
component_url = component_url.sub(substituted_value, template_value)
|
71
|
+
end
|
72
|
+
|
73
|
+
component_templates[component] = Addressable::Template.new(component_url.to_s)
|
74
|
+
end.freeze
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns empty hash if the template omits the component, a set of substitutions if the
|
78
|
+
# provided URI component matches the template component, or nil if the match fails.
|
79
|
+
def component_matches(component, uri)
|
80
|
+
extracted_mappings = {}
|
81
|
+
component_template = component_templates[component]
|
82
|
+
if component_template
|
83
|
+
component_url = uri.public_send(component).to_s
|
84
|
+
unless (extracted_mappings = component_template.extract(component_url))
|
85
|
+
# to support Addressable's expansion of queries, ensure it's parsing the fragment as appropriate (e.g. {?params*})
|
86
|
+
prefix = COMPONENT_PREFIXES[component]
|
87
|
+
return nil unless prefix && (extracted_mappings = component_template.extract(prefix + component_url))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
extracted_mappings
|
91
|
+
end
|
92
|
+
|
93
|
+
# Convert the pattern into an Addressable URI by substituting the template slugs with nonsense strings.
|
94
|
+
def to_substituted_uri
|
95
|
+
url = pattern
|
96
|
+
substitutions.each_pair do |slug, value|
|
97
|
+
url = url.sub(slug, value)
|
98
|
+
end
|
99
|
+
begin
|
100
|
+
Addressable::URI.parse(url)
|
101
|
+
rescue Addressable::URI::InvalidURIError
|
102
|
+
raise SitePrism::InvalidUrlMatcher, 'Could not automatically match your URL. Note: templated port numbers are not currently supported.'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def substitutions
|
107
|
+
@substitutions ||= slugs.each_with_index.reduce({}) do |memo, slugindex|
|
108
|
+
slug, index = slugindex
|
109
|
+
memo.merge(slug => slug_prefix(slug) + substitution_value(index))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def reverse_substitutions
|
114
|
+
@reverse_substitutions ||= slugs.each_with_index.reduce({}) do |memo, slugindex|
|
115
|
+
slug, index = slugindex
|
116
|
+
memo.merge(slug_prefix(slug) + substitution_value(index) => slug, substitution_value(index) => slug)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def slugs
|
121
|
+
pattern.scan(/\{[^}]+\}/)
|
122
|
+
end
|
123
|
+
|
124
|
+
# If a slug begins with non-alpha characters, it may denote the start of a new component (e.g. query or fragment).
|
125
|
+
# We emit this prefix as part of the substituted slug so that Addressable's URI parser can see it as such.
|
126
|
+
def slug_prefix(slug)
|
127
|
+
matches = slug.match(/\A\{([^A-Za-z]+)/)
|
128
|
+
matches && matches[1] || ''
|
129
|
+
end
|
130
|
+
|
131
|
+
# Generate a repeatable 5 character uniform alphabetical nonsense string to allow parsing as a URI
|
132
|
+
def substitution_value(index)
|
133
|
+
Base64.urlsafe_encode64(Digest::SHA1.digest(index.to_s)).gsub(/[^A-Za-z]/, '')[0..5]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
module SitePrism
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module SitePrism
|
2
|
+
module ElementChecker
|
3
|
+
def all_there?
|
4
|
+
Capybara.using_wait_time(0) do
|
5
|
+
self.class.mapped_items.all? { |element| send "has_#{element}?" }
|
6
|
+
end
|
5
7
|
end
|
6
8
|
end
|
7
9
|
end
|
8
|
-
|
@@ -1,178 +1,185 @@
|
|
1
|
-
module SitePrism
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module SitePrism
|
2
|
+
module ElementContainer
|
3
|
+
attr_reader :mapped_items
|
4
|
+
|
5
|
+
def element(element_name, *find_args)
|
6
|
+
build element_name, *find_args do
|
7
|
+
define_method element_name.to_s do |*runtime_args, &element_block|
|
8
|
+
self.class.raise_if_block(self, element_name.to_s, !element_block.nil?)
|
9
|
+
find_first(*find_args, *runtime_args)
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
|
-
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def elements(collection_name, *find_args)
|
15
|
+
build collection_name, *find_args do
|
16
|
+
define_method collection_name.to_s do |*runtime_args, &element_block|
|
17
|
+
self.class.raise_if_block(self, collection_name.to_s, !element_block.nil?)
|
18
|
+
find_all(*find_args, *runtime_args)
|
19
|
+
end
|
15
20
|
end
|
16
21
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
alias_method :collection, :elements
|
23
|
+
|
24
|
+
def section(section_name, *args, &block)
|
25
|
+
section_class, find_args = extract_section_options args, &block
|
26
|
+
build section_name, *find_args do
|
27
|
+
define_method section_name do |*runtime_args, &element_block|
|
28
|
+
self.class.raise_if_block(self, section_name.to_s, !element_block.nil?)
|
29
|
+
section_class.new self, find_first(*find_args, *runtime_args)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
|
-
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
def sections(section_collection_name, *args, &block)
|
35
|
+
section_class, find_args = extract_section_options args, &block
|
36
|
+
build section_collection_name, *find_args do
|
37
|
+
define_method section_collection_name do |*runtime_args, &element_block|
|
38
|
+
self.class.raise_if_block(self, section_collection_name.to_s, !element_block.nil?)
|
39
|
+
find_all(*find_args, *runtime_args).map do |element|
|
40
|
+
section_class.new self, element
|
41
|
+
end
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
38
|
-
end
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
def iframe(iframe_name, iframe_page_class, selector)
|
47
|
+
element_selector = deduce_iframe_element_selector(selector)
|
48
|
+
scope_selector = deduce_iframe_scope_selector(selector)
|
49
|
+
add_to_mapped_items iframe_name
|
50
|
+
create_existence_checker iframe_name, element_selector
|
51
|
+
create_nonexistence_checker iframe_name, element_selector
|
52
|
+
create_waiter iframe_name, element_selector
|
53
|
+
define_method iframe_name do |&block|
|
54
|
+
within_frame scope_selector do
|
55
|
+
block.call iframe_page_class.new
|
56
|
+
end
|
50
57
|
end
|
51
58
|
end
|
52
|
-
end
|
53
59
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
def add_to_mapped_items(item)
|
61
|
+
@mapped_items ||= []
|
62
|
+
@mapped_items << item.to_s
|
63
|
+
end
|
58
64
|
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
def raise_if_block(obj, name, has_block)
|
66
|
+
return unless has_block
|
67
|
+
fail SitePrism::UnsupportedBlock, "#{obj.class}##{name} does not accept blocks, did you mean to define a (i)frame?"
|
68
|
+
end
|
62
69
|
|
63
|
-
|
70
|
+
private
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
def build(name, *find_args)
|
73
|
+
if find_args.empty?
|
74
|
+
create_no_selector name
|
75
|
+
else
|
76
|
+
add_to_mapped_items name
|
77
|
+
yield
|
78
|
+
end
|
79
|
+
add_helper_methods name, *find_args
|
71
80
|
end
|
72
|
-
add_helper_methods name, *find_args
|
73
|
-
end
|
74
81
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
+
def add_helper_methods(name, *find_args)
|
83
|
+
create_existence_checker name, *find_args
|
84
|
+
create_nonexistence_checker name, *find_args
|
85
|
+
create_waiter name, *find_args
|
86
|
+
create_visibility_waiter name, *find_args
|
87
|
+
create_invisibility_waiter name, *find_args
|
88
|
+
end
|
82
89
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
90
|
+
def create_helper_method(proposed_method_name, *find_args)
|
91
|
+
if find_args.empty?
|
92
|
+
create_no_selector proposed_method_name
|
93
|
+
else
|
94
|
+
yield
|
95
|
+
end
|
88
96
|
end
|
89
|
-
end
|
90
97
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
+
def create_existence_checker(element_name, *find_args)
|
99
|
+
method_name = "has_#{element_name}?"
|
100
|
+
create_helper_method method_name, *find_args do
|
101
|
+
define_method method_name do |*runtime_args|
|
102
|
+
wait_time = SitePrism.use_implicit_waits ? Capybara.default_wait_time : 0
|
103
|
+
Capybara.using_wait_time wait_time do
|
104
|
+
element_exists?(*find_args, *runtime_args)
|
105
|
+
end
|
98
106
|
end
|
99
107
|
end
|
100
108
|
end
|
101
|
-
end
|
102
109
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
def create_nonexistence_checker(element_name, *find_args)
|
111
|
+
method_name = "has_no_#{element_name}?"
|
112
|
+
create_helper_method method_name, *find_args do
|
113
|
+
define_method method_name do |*runtime_args|
|
114
|
+
wait_time = SitePrism.use_implicit_waits ? Capybara.default_wait_time : 0
|
115
|
+
Capybara.using_wait_time wait_time do
|
116
|
+
element_does_not_exist?(*find_args, *runtime_args)
|
117
|
+
end
|
110
118
|
end
|
111
119
|
end
|
112
120
|
end
|
113
|
-
end
|
114
121
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
+
def create_waiter(element_name, *find_args)
|
123
|
+
method_name = "wait_for_#{element_name}"
|
124
|
+
create_helper_method method_name, *find_args do
|
125
|
+
define_method method_name do |timeout = nil, *runtime_args|
|
126
|
+
timeout = timeout.nil? ? Capybara.default_wait_time : timeout
|
127
|
+
Capybara.using_wait_time timeout do
|
128
|
+
element_exists?(*find_args, *runtime_args)
|
129
|
+
end
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
125
|
-
end
|
126
133
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
+
def create_visibility_waiter(element_name, *find_args)
|
135
|
+
method_name = "wait_until_#{element_name}_visible"
|
136
|
+
create_helper_method method_name, *find_args do
|
137
|
+
define_method method_name do |timeout = Capybara.default_wait_time, *runtime_args|
|
138
|
+
Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementVisibility do
|
139
|
+
Capybara.using_wait_time 0 do
|
140
|
+
sleep 0.05 until element_exists?(*find_args, *runtime_args, visible: true)
|
141
|
+
end
|
134
142
|
end
|
135
143
|
end
|
136
144
|
end
|
137
145
|
end
|
138
|
-
end
|
139
146
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
+
def create_invisibility_waiter(element_name, *find_args)
|
148
|
+
method_name = "wait_until_#{element_name}_invisible"
|
149
|
+
create_helper_method method_name, *find_args do
|
150
|
+
define_method method_name do |timeout = Capybara.default_wait_time, *runtime_args|
|
151
|
+
Timeout.timeout timeout, SitePrism::TimeOutWaitingForElementInvisibility do
|
152
|
+
Capybara.using_wait_time 0 do
|
153
|
+
sleep 0.05 while element_exists?(*find_args, *runtime_args, visible: true)
|
154
|
+
end
|
147
155
|
end
|
148
156
|
end
|
149
157
|
end
|
150
158
|
end
|
151
|
-
end
|
152
159
|
|
153
|
-
|
154
|
-
|
155
|
-
|
160
|
+
def create_no_selector(method_name)
|
161
|
+
define_method method_name do
|
162
|
+
fail SitePrism::NoSelectorForElement.new, "#{self.class.name} => :#{method_name} needs a selector"
|
163
|
+
end
|
156
164
|
end
|
157
|
-
end
|
158
165
|
|
159
|
-
|
160
|
-
|
161
|
-
|
166
|
+
def deduce_iframe_scope_selector(selector)
|
167
|
+
selector.is_a?(Integer) ? selector : selector.split('#').last
|
168
|
+
end
|
162
169
|
|
163
|
-
|
164
|
-
|
165
|
-
|
170
|
+
def deduce_iframe_element_selector(selector)
|
171
|
+
selector.is_a?(Integer) ? "iframe:nth-of-type(#{selector + 1})" : selector
|
172
|
+
end
|
166
173
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
+
def extract_section_options(args, &block)
|
175
|
+
if args.first.is_a? Class
|
176
|
+
section_class = args.shift
|
177
|
+
elsif block_given?
|
178
|
+
section_class = Class.new SitePrism::Section, &block
|
179
|
+
else
|
180
|
+
fail ArgumentError, 'You should provide section class either as a block, or as the second argument'
|
181
|
+
end
|
182
|
+
return section_class, args
|
174
183
|
end
|
175
|
-
return section_class, args
|
176
184
|
end
|
177
185
|
end
|
178
|
-
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module SitePrism
|
2
2
|
class NoUrlForPage < StandardError; end
|
3
3
|
class NoUrlMatcherForPage < StandardError; end
|
4
|
+
class InvalidUrlMatcher < StandardError; end
|
4
5
|
class NoSelectorForElement < StandardError; end
|
5
6
|
class TimeoutException < StandardError; end
|
6
7
|
class TimeOutWaitingForElementVisibility < StandardError; end
|
7
8
|
class TimeOutWaitingForElementInvisibility < StandardError; end
|
9
|
+
class UnsupportedBlock < StandardError; end
|
8
10
|
end
|
9
|
-
|
data/lib/site_prism/page.rb
CHANGED
@@ -4,28 +4,54 @@ module SitePrism
|
|
4
4
|
include ElementChecker
|
5
5
|
extend ElementContainer
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
raise SitePrism::NoUrlForPage if expanded_url.nil?
|
10
|
-
visit expanded_url
|
7
|
+
def page
|
8
|
+
@page || Capybara.current_session
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
|
11
|
+
def load(expansion_or_html = {})
|
12
|
+
if expansion_or_html.is_a? String
|
13
|
+
@page = Capybara.string(expansion_or_html)
|
14
|
+
else
|
15
|
+
expanded_url = url(expansion_or_html)
|
16
|
+
fail SitePrism::NoUrlForPage if expanded_url.nil?
|
17
|
+
visit expanded_url
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def displayed?(*args)
|
22
|
+
expected_mappings = args.last.is_a?(::Hash) ? args.pop : {}
|
23
|
+
seconds = args.length > 0 ? args.first : Waiter.default_wait_time
|
24
|
+
fail SitePrism::NoUrlMatcherForPage if url_matcher.nil?
|
15
25
|
begin
|
16
|
-
Waiter.wait_until_true(seconds)
|
17
|
-
|
18
|
-
|
19
|
-
rescue SitePrism::TimeoutException=>e
|
20
|
-
return false
|
26
|
+
Waiter.wait_until_true(seconds) { url_matches?(expected_mappings) }
|
27
|
+
rescue SitePrism::TimeoutException
|
28
|
+
false
|
21
29
|
end
|
22
30
|
end
|
23
31
|
|
24
|
-
def
|
32
|
+
def url_matches(seconds = Waiter.default_wait_time)
|
33
|
+
return unless displayed?(seconds)
|
34
|
+
|
35
|
+
if url_matcher.is_a?(Regexp)
|
36
|
+
regexp_backed_matches
|
37
|
+
else
|
38
|
+
template_backed_matches
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def regexp_backed_matches
|
43
|
+
url_matcher.match(page.current_url)
|
44
|
+
end
|
45
|
+
|
46
|
+
def template_backed_matches
|
47
|
+
matcher_template.mappings(page.current_url)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.set_url(page_url)
|
25
51
|
@url = page_url.to_s
|
26
52
|
end
|
27
53
|
|
28
|
-
def self.set_url_matcher
|
54
|
+
def self.set_url_matcher(page_url_matcher)
|
29
55
|
@url_matcher = page_url_matcher
|
30
56
|
end
|
31
57
|
|
@@ -34,7 +60,7 @@ module SitePrism
|
|
34
60
|
end
|
35
61
|
|
36
62
|
def self.url_matcher
|
37
|
-
@url_matcher
|
63
|
+
@url_matcher || url
|
38
64
|
end
|
39
65
|
|
40
66
|
def url(expansion = {})
|
@@ -52,21 +78,42 @@ module SitePrism
|
|
52
78
|
|
53
79
|
private
|
54
80
|
|
55
|
-
def find_first
|
56
|
-
find
|
81
|
+
def find_first(*find_args)
|
82
|
+
find(*find_args)
|
57
83
|
end
|
58
84
|
|
59
|
-
def find_all
|
60
|
-
all
|
85
|
+
def find_all(*find_args)
|
86
|
+
all(*find_args)
|
61
87
|
end
|
62
88
|
|
63
|
-
def element_exists?
|
64
|
-
has_selector?
|
89
|
+
def element_exists?(*find_args)
|
90
|
+
has_selector?(*find_args)
|
65
91
|
end
|
66
92
|
|
67
|
-
def element_does_not_exist?
|
68
|
-
has_no_selector?
|
93
|
+
def element_does_not_exist?(*find_args)
|
94
|
+
has_no_selector?(*find_args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def url_matches?(expected_mappings = {})
|
98
|
+
if url_matcher.is_a?(Regexp)
|
99
|
+
url_matches_by_regexp?
|
100
|
+
elsif url_matcher.respond_to?(:to_str)
|
101
|
+
url_matches_by_template?(expected_mappings)
|
102
|
+
else
|
103
|
+
fail SitePrism::InvalidUrlMatcher
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def url_matches_by_regexp?
|
108
|
+
!regexp_backed_matches.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
def url_matches_by_template?(expected_mappings)
|
112
|
+
matcher_template.matches?(page.current_url, expected_mappings)
|
113
|
+
end
|
114
|
+
|
115
|
+
def matcher_template
|
116
|
+
@addressable_url_matcher ||= AddressableUrlMatcher.new(url_matcher)
|
69
117
|
end
|
70
118
|
end
|
71
119
|
end
|
72
|
-
|
data/lib/site_prism/section.rb
CHANGED
@@ -6,7 +6,7 @@ module SitePrism
|
|
6
6
|
|
7
7
|
attr_reader :root_element, :parent
|
8
8
|
|
9
|
-
def initialize
|
9
|
+
def initialize(parent, root_element)
|
10
10
|
@parent, @root_element = parent, root_element
|
11
11
|
end
|
12
12
|
|
@@ -14,16 +14,16 @@ module SitePrism
|
|
14
14
|
root_element.visible?
|
15
15
|
end
|
16
16
|
|
17
|
-
def execute_script
|
17
|
+
def execute_script(input)
|
18
18
|
Capybara.current_session.execute_script input
|
19
19
|
end
|
20
20
|
|
21
|
-
def evaluate_script
|
21
|
+
def evaluate_script(input)
|
22
22
|
Capybara.current_session.evaluate_script input
|
23
23
|
end
|
24
24
|
|
25
25
|
def parent_page
|
26
|
-
candidate_page =
|
26
|
+
candidate_page = parent
|
27
27
|
until candidate_page.is_a?(SitePrism::Page)
|
28
28
|
candidate_page = candidate_page.parent
|
29
29
|
end
|
@@ -32,25 +32,20 @@ module SitePrism
|
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
def find_first
|
36
|
-
root_element.find
|
35
|
+
def find_first(*find_args)
|
36
|
+
root_element.find(*find_args)
|
37
37
|
end
|
38
38
|
|
39
|
-
def find_all
|
40
|
-
root_element.all
|
39
|
+
def find_all(*find_args)
|
40
|
+
root_element.all(*find_args)
|
41
41
|
end
|
42
42
|
|
43
|
-
def element_exists?
|
44
|
-
unless root_element.nil?
|
45
|
-
root_element.has_selector? *find_args
|
46
|
-
end
|
43
|
+
def element_exists?(*find_args)
|
44
|
+
root_element.has_selector?(*find_args) unless root_element.nil?
|
47
45
|
end
|
48
46
|
|
49
|
-
def element_does_not_exist?
|
50
|
-
unless root_element.nil?
|
51
|
-
root_element.has_no_selector? *find_args
|
52
|
-
end
|
47
|
+
def element_does_not_exist?(*find_args)
|
48
|
+
root_element.has_no_selector?(*find_args) unless root_element.nil?
|
53
49
|
end
|
54
50
|
end
|
55
51
|
end
|
56
|
-
|
data/lib/site_prism/version.rb
CHANGED
data/lib/site_prism/waiter.rb
CHANGED
@@ -1,21 +1,17 @@
|
|
1
1
|
module SitePrism
|
2
2
|
class Waiter
|
3
|
-
def self.wait_until_true(wait_time_seconds=default_wait_time)
|
3
|
+
def self.wait_until_true(wait_time_seconds = default_wait_time)
|
4
4
|
start_time = Time.now
|
5
5
|
loop do
|
6
6
|
return true if yield
|
7
7
|
break unless Time.now - start_time <= wait_time_seconds
|
8
8
|
sleep(0.05)
|
9
9
|
end
|
10
|
-
|
10
|
+
fail SitePrism::TimeoutException, 'Timed out while waiting for block to return true'
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.default_wait_time
|
14
|
-
|
14
|
+
Capybara.default_wait_time
|
15
15
|
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
@@default_wait_time = Capybara.default_wait_time
|
20
16
|
end
|
21
|
-
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,61 +1,67 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: site_prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.7'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nat Ritmeyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2.1'
|
20
|
-
- - <
|
20
|
+
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '3.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '2.1'
|
30
|
-
- - <
|
30
|
+
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '3.0'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: addressable
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- -
|
37
|
+
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: 2.3.3
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '3.0'
|
40
43
|
type: :runtime
|
41
44
|
prerelease: false
|
42
45
|
version_requirements: !ruby/object:Gem::Requirement
|
43
46
|
requirements:
|
44
|
-
- -
|
47
|
+
- - ">="
|
45
48
|
- !ruby/object:Gem::Version
|
46
49
|
version: 2.3.3
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '3.0'
|
47
53
|
- !ruby/object:Gem::Dependency
|
48
54
|
name: rspec
|
49
55
|
requirement: !ruby/object:Gem::Requirement
|
50
56
|
requirements:
|
51
|
-
- - <
|
57
|
+
- - "<"
|
52
58
|
- !ruby/object:Gem::Version
|
53
59
|
version: '4.0'
|
54
60
|
type: :development
|
55
61
|
prerelease: false
|
56
62
|
version_requirements: !ruby/object:Gem::Requirement
|
57
63
|
requirements:
|
58
|
-
- - <
|
64
|
+
- - "<"
|
59
65
|
- !ruby/object:Gem::Version
|
60
66
|
version: '4.0'
|
61
67
|
description: SitePrism gives you a simple, clean and semantic DSL for describing your
|
@@ -65,6 +71,10 @@ executables: []
|
|
65
71
|
extensions: []
|
66
72
|
extra_rdoc_files: []
|
67
73
|
files:
|
74
|
+
- LICENSE
|
75
|
+
- README.md
|
76
|
+
- lib/site_prism.rb
|
77
|
+
- lib/site_prism/addressable_url_matcher.rb
|
68
78
|
- lib/site_prism/element_checker.rb
|
69
79
|
- lib/site_prism/element_container.rb
|
70
80
|
- lib/site_prism/exceptions.rb
|
@@ -72,9 +82,6 @@ files:
|
|
72
82
|
- lib/site_prism/section.rb
|
73
83
|
- lib/site_prism/version.rb
|
74
84
|
- lib/site_prism/waiter.rb
|
75
|
-
- lib/site_prism.rb
|
76
|
-
- LICENSE
|
77
|
-
- README.md
|
78
85
|
homepage: http://github.com/natritmeyer/site_prism
|
79
86
|
licenses:
|
80
87
|
- BSD3
|
@@ -85,17 +92,17 @@ require_paths:
|
|
85
92
|
- lib
|
86
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
87
94
|
requirements:
|
88
|
-
- -
|
95
|
+
- - ">="
|
89
96
|
- !ruby/object:Gem::Version
|
90
97
|
version: 1.9.3
|
91
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
99
|
requirements:
|
93
|
-
- -
|
100
|
+
- - ">="
|
94
101
|
- !ruby/object:Gem::Version
|
95
102
|
version: '0'
|
96
103
|
requirements: []
|
97
104
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
105
|
+
rubygems_version: 2.4.5
|
99
106
|
signing_key:
|
100
107
|
specification_version: 4
|
101
108
|
summary: A Page Object Model DSL for Capybara
|