site_prism 2.10 → 2.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +107 -87
- data/lib/site_prism/addressable_url_matcher.rb +21 -18
- data/lib/site_prism/element_checker.rb +9 -1
- data/lib/site_prism/element_container.rb +7 -3
- data/lib/site_prism/exceptions.rb +7 -1
- data/lib/site_prism/version.rb +1 -1
- metadata +30 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e194be3ee7349ee99bb8704a35acca0d4bf963d9
|
4
|
+
data.tar.gz: 584fc98753ee4abfd4bbd1e220b537dfd2a10280
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a6eb96791b4c5be970baa67ed782a14744066284ca8053fd0832ddf78325dc95aaedf5c97a488ef1e041b999d28e91b048c5be226d89a2c6308de15ec561d66
|
7
|
+
data.tar.gz: bad1b3076a2ca4a4b40430228d806dfc1e22a127f23451c46f2976c89fed03e8f9a804357dc6cb2244e4d158022edd3687b1efef180542317c631145f556f264
|
data/README.md
CHANGED
@@ -9,6 +9,14 @@ Find the pretty documentation here: http://rdoc.info/gems/site_prism/frames
|
|
9
9
|
|
10
10
|
Make sure to add your project/company to https://github.com/natritmeyer/site_prism/wiki/Who-is-using-SitePrism
|
11
11
|
|
12
|
+
## Supported Rubies / Browsers
|
13
|
+
|
14
|
+
SitePrism is built and tested to work on Ruby 2.0 - 2.4. There is also some limited support for the Ruby 1.9 series.
|
15
|
+
|
16
|
+
SitePrism should run on all major browsers. The gem's integration tests are ran on the latest version of Firefox.
|
17
|
+
|
18
|
+
If you find your browser isn't working correctly with SitePrism, please open an [issue request](https://github.com/natritmeyer/site_prism/issues/new)
|
19
|
+
|
12
20
|
## Synopsis
|
13
21
|
|
14
22
|
Here's an overview of how SitePrism is designed to be used:
|
@@ -17,20 +25,20 @@ Here's an overview of how SitePrism is designed to be used:
|
|
17
25
|
# define our site's pages
|
18
26
|
|
19
27
|
class Home < SitePrism::Page
|
20
|
-
set_url
|
28
|
+
set_url '/index.htm'
|
21
29
|
set_url_matcher /google.com\/?/
|
22
30
|
|
23
|
-
element :search_field,
|
31
|
+
element :search_field, 'input[name="q"]'
|
24
32
|
element :search_button, "button[name='btnK']"
|
25
|
-
elements :footer_links,
|
26
|
-
section :menu, MenuSection,
|
33
|
+
elements :footer_links, '#footer a'
|
34
|
+
section :menu, MenuSection, '#gbx3'
|
27
35
|
end
|
28
36
|
|
29
37
|
class SearchResults < SitePrism::Page
|
30
38
|
set_url_matcher /google.com\/results\?.*/
|
31
39
|
|
32
|
-
section :menu, MenuSection,
|
33
|
-
sections :search_results, SearchResultSection,
|
40
|
+
section :menu, MenuSection, '#gbx3'
|
41
|
+
sections :search_results, SearchResultSection, '#results li'
|
34
42
|
|
35
43
|
def search_result_links
|
36
44
|
search_results.map {|sr| sr.title['href']}
|
@@ -40,14 +48,14 @@ end
|
|
40
48
|
# define sections used on multiple pages or multiple times on one page
|
41
49
|
|
42
50
|
class MenuSection < SitePrism::Section
|
43
|
-
element :search,
|
44
|
-
element :images,
|
45
|
-
element :maps,
|
51
|
+
element :search, 'a.search'
|
52
|
+
element :images, 'a.image-search'
|
53
|
+
element :maps, 'a.map-search'
|
46
54
|
end
|
47
55
|
|
48
56
|
class SearchResultSection < SitePrism::Section
|
49
|
-
element :title,
|
50
|
-
element :blurb,
|
57
|
+
element :title, 'a.title'
|
58
|
+
element :blurb, 'span.result-description'
|
51
59
|
end
|
52
60
|
|
53
61
|
# now for some tests
|
@@ -174,7 +182,7 @@ Note that setting a URL is optional - you only need to set a url if you want to
|
|
174
182
|
directly to that page. It makes sense to set the URL for a page model of a home
|
175
183
|
page or a login page, but probably not a search results page.
|
176
184
|
|
177
|
-
####
|
185
|
+
#### Parametrized URLs
|
178
186
|
|
179
187
|
SitePrism uses the Addressable gem and therefore allows for parameterized URLs. Here is
|
180
188
|
a simple example:
|
@@ -333,7 +341,7 @@ end
|
|
333
341
|
@account = Account.new
|
334
342
|
#...
|
335
343
|
@account.current_url #=> "http://www.example.com/account/123"
|
336
|
-
expect(@account.current_url).to include
|
344
|
+
expect(@account.current_url).to include 'example.com/account/'
|
337
345
|
```
|
338
346
|
|
339
347
|
### Page Title
|
@@ -381,7 +389,7 @@ the relevant page. SitePrism makes this easy:
|
|
381
389
|
|
382
390
|
```ruby
|
383
391
|
class Home < SitePrism::Page
|
384
|
-
element :search_field,
|
392
|
+
element :search_field, 'input[name="q"]'
|
385
393
|
end
|
386
394
|
```
|
387
395
|
|
@@ -397,9 +405,9 @@ element. So using the following example:
|
|
397
405
|
|
398
406
|
```ruby
|
399
407
|
class Home < SitePrism::Page
|
400
|
-
set_url
|
408
|
+
set_url 'http://www.google.com'
|
401
409
|
|
402
|
-
element :search_field,
|
410
|
+
element :search_field, 'input[name="q"]'
|
403
411
|
end
|
404
412
|
```
|
405
413
|
|
@@ -410,7 +418,7 @@ end
|
|
410
418
|
@home.load
|
411
419
|
|
412
420
|
@home.search_field #=> will return the capybara element found using the selector
|
413
|
-
@home.search_field.set
|
421
|
+
@home.search_field.set 'the search string' #=> since search_field returns a capybara element, you can use the capybara API to deal with it
|
414
422
|
@home.search_field.text #=> standard method on a capybara element; returns a string
|
415
423
|
```
|
416
424
|
|
@@ -421,9 +429,9 @@ Another method added to the Page class by the `element` method is the
|
|
421
429
|
|
422
430
|
```ruby
|
423
431
|
class Home < SitePrism::Page
|
424
|
-
set_url
|
432
|
+
set_url 'http://www.google.com'
|
425
433
|
|
426
|
-
element :search_field,
|
434
|
+
element :search_field, 'input[name="q"]'
|
427
435
|
end
|
428
436
|
```
|
429
437
|
|
@@ -472,9 +480,9 @@ custom amount of time to wait. Using the same example as above:
|
|
472
480
|
|
473
481
|
```ruby
|
474
482
|
class Home < SitePrism::Page
|
475
|
-
set_url
|
483
|
+
set_url 'http://www.google.com'
|
476
484
|
|
477
|
-
element :search_field,
|
485
|
+
element :search_field, 'input[name="q"]'
|
478
486
|
end
|
479
487
|
```
|
480
488
|
|
@@ -526,10 +534,10 @@ can use a CSS selector, you can use an XPath expression. An example:
|
|
526
534
|
```ruby
|
527
535
|
class Home < SitePrism::Page
|
528
536
|
# CSS Selector:
|
529
|
-
element :first_name,
|
537
|
+
element :first_name, 'div#signup input[name="first-name"]'
|
530
538
|
|
531
539
|
#same thing as an XPath expression:
|
532
|
-
element :first_name, :xpath,
|
540
|
+
element :first_name, :xpath, '//div[@id="signup"]//input[@name="first-name"]'
|
533
541
|
end
|
534
542
|
```
|
535
543
|
|
@@ -539,7 +547,7 @@ Given:
|
|
539
547
|
|
540
548
|
```ruby
|
541
549
|
class Home < SitePrism::Page
|
542
|
-
element :search_field,
|
550
|
+
element :search_field, 'input[name="q"]'
|
543
551
|
end
|
544
552
|
```
|
545
553
|
|
@@ -567,7 +575,7 @@ Here's how it works:
|
|
567
575
|
|
568
576
|
```ruby
|
569
577
|
class Friends < SitePrism::Page
|
570
|
-
elements :names,
|
578
|
+
elements :names, 'ul#names li a'
|
571
579
|
end
|
572
580
|
```
|
573
581
|
|
@@ -584,7 +592,7 @@ css selector. Using the example above:
|
|
584
592
|
|
585
593
|
```ruby
|
586
594
|
class Friends < SitePrism::Page
|
587
|
-
elements :names,
|
595
|
+
elements :names, 'ul#names li a'
|
588
596
|
end
|
589
597
|
```
|
590
598
|
|
@@ -607,7 +615,7 @@ arrays:
|
|
607
615
|
Or even run some tests...
|
608
616
|
|
609
617
|
```ruby
|
610
|
-
expect(@friends_page.names.map { |name| name.text }).to eq([
|
618
|
+
expect(@friends_page.names.map { |name| name.text }).to eq(['Alice', 'Bob', 'Fred'])
|
611
619
|
expect(@friends_page.names.size).to eq(3)
|
612
620
|
expect(@friends_page).to have(3).names
|
613
621
|
```
|
@@ -650,7 +658,7 @@ matches the selector. For example, with the following page:
|
|
650
658
|
|
651
659
|
```ruby
|
652
660
|
class Friends < SitePrism::Page
|
653
|
-
elements :names,
|
661
|
+
elements :names, 'ul#names li a'
|
654
662
|
end
|
655
663
|
|
656
664
|
```
|
@@ -711,6 +719,18 @@ end
|
|
711
719
|
|
712
720
|
```
|
713
721
|
|
722
|
+
You may wish to have elements declared in a page object class that are not always guaranteed to be present (success or error messages, etc.). If you'd still like to test such a page with `all_there?` you can declare `expected_elements` on your page object class that narrows the elements included in `all_there?` check to those that definitely should be present.
|
723
|
+
|
724
|
+
```ruby
|
725
|
+
class TestPage < SitePrism::Page
|
726
|
+
element :name_field, '#name'
|
727
|
+
element :address_field, '#address'
|
728
|
+
element :success_msg, 'span.alert-success'
|
729
|
+
|
730
|
+
expected_elements :name_field, :address_field
|
731
|
+
end
|
732
|
+
```
|
733
|
+
|
714
734
|
## Sections
|
715
735
|
|
716
736
|
SitePrism allows you to model sections of a page that appear on multiple
|
@@ -745,7 +765,7 @@ includes the above `MenuSection` section:
|
|
745
765
|
|
746
766
|
```ruby
|
747
767
|
class Home < SitePrism::Page
|
748
|
-
section :menu, MenuSection,
|
768
|
+
section :menu, MenuSection, '#gbx3'
|
749
769
|
end
|
750
770
|
```
|
751
771
|
|
@@ -776,7 +796,7 @@ end
|
|
776
796
|
# the page that includes the section:
|
777
797
|
|
778
798
|
class Home < SitePrism::Page
|
779
|
-
section :menu, MenuSection,
|
799
|
+
section :menu, MenuSection, '#gbx3'
|
780
800
|
end
|
781
801
|
|
782
802
|
# the page and section in action:
|
@@ -803,11 +823,11 @@ end
|
|
803
823
|
# define 2 pages, each containing the same section
|
804
824
|
|
805
825
|
class Home < SitePrism::Page
|
806
|
-
section :menu, MenuSection,
|
826
|
+
section :menu, MenuSection, '#gbx3'
|
807
827
|
end
|
808
828
|
|
809
829
|
class SearchResults < SitePrism::Page
|
810
|
-
section :menu, MenuSection,
|
830
|
+
section :menu, MenuSection, '#gbx48'
|
811
831
|
end
|
812
832
|
```
|
813
833
|
|
@@ -822,9 +842,9 @@ This works just the same as adding elements to a page:
|
|
822
842
|
|
823
843
|
```ruby
|
824
844
|
class MenuSection < SitePrism::Section
|
825
|
-
element :search,
|
826
|
-
element :images,
|
827
|
-
element :maps,
|
845
|
+
element :search, 'a.search'
|
846
|
+
element :images, 'a.image-search'
|
847
|
+
element :maps, 'a.map-search'
|
828
848
|
end
|
829
849
|
```
|
830
850
|
|
@@ -836,7 +856,7 @@ When the section is added to a page...
|
|
836
856
|
|
837
857
|
```ruby
|
838
858
|
class Home < SitePrism::Page
|
839
|
-
section :menu, MenuSection,
|
859
|
+
section :menu, MenuSection, '#gbx3'
|
840
860
|
end
|
841
861
|
```
|
842
862
|
|
@@ -888,15 +908,15 @@ section is a subsection). For example, given the following setup:
|
|
888
908
|
|
889
909
|
```ruby
|
890
910
|
class MySubSection < SitePrism::Section
|
891
|
-
element :some_element,
|
911
|
+
element :some_element, 'abc'
|
892
912
|
end
|
893
913
|
|
894
914
|
class MySection < SitePrism::Section
|
895
|
-
section :my_subsection, MySubSection,
|
915
|
+
section :my_subsection, MySubSection, 'def'
|
896
916
|
end
|
897
917
|
|
898
918
|
class MyPage < SitePrism::Page
|
899
|
-
section :my_section, MySection,
|
919
|
+
section :my_section, MySection, 'ghi'
|
900
920
|
end
|
901
921
|
```
|
902
922
|
|
@@ -917,13 +937,13 @@ given the following setup:
|
|
917
937
|
|
918
938
|
```ruby
|
919
939
|
class MenuSection < SitePrism::Section
|
920
|
-
element :search,
|
921
|
-
element :images,
|
922
|
-
element :maps,
|
940
|
+
element :search, 'a.search'
|
941
|
+
element :images, 'a.image-search'
|
942
|
+
element :maps, 'a.map-search'
|
923
943
|
end
|
924
944
|
|
925
945
|
class Home < SitePrism::Page
|
926
|
-
section :menu, MenuSection,
|
946
|
+
section :menu, MenuSection, '#gbx3'
|
927
947
|
end
|
928
948
|
```
|
929
949
|
|
@@ -944,13 +964,13 @@ to the page or section it's been added to - same idea as what the
|
|
944
964
|
|
945
965
|
```ruby
|
946
966
|
class MenuSection < SitePrism::Section
|
947
|
-
element :search,
|
948
|
-
element :images,
|
949
|
-
element :maps,
|
967
|
+
element :search, 'a.search'
|
968
|
+
element :images, 'a.image-search'
|
969
|
+
element :maps, 'a.map-search'
|
950
970
|
end
|
951
971
|
|
952
972
|
class Home < SitePrism::Page
|
953
|
-
section :menu, MenuSection,
|
973
|
+
section :menu, MenuSection, '#gbx3'
|
954
974
|
end
|
955
975
|
```
|
956
976
|
|
@@ -979,13 +999,13 @@ page/section that our section was added to. Given the following setup:
|
|
979
999
|
|
980
1000
|
```ruby
|
981
1001
|
class MenuSection < SitePrism::Section
|
982
|
-
element :search,
|
983
|
-
element :images,
|
984
|
-
element :maps,
|
1002
|
+
element :search, 'a.search'
|
1003
|
+
element :images, 'a.image-search'
|
1004
|
+
element :maps, 'a.map-search'
|
985
1005
|
end
|
986
1006
|
|
987
1007
|
class Home < SitePrism::Page
|
988
|
-
section :menu, MenuSection,
|
1008
|
+
section :menu, MenuSection, '#gbx3'
|
989
1009
|
end
|
990
1010
|
```
|
991
1011
|
|
@@ -1032,24 +1052,24 @@ sections within sections within sections within sections!
|
|
1032
1052
|
# 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
|
1033
1053
|
|
1034
1054
|
class Login < SitePrism::Section
|
1035
|
-
element :username,
|
1036
|
-
element :password,
|
1037
|
-
element :sign_in,
|
1055
|
+
element :username, '#username'
|
1056
|
+
element :password, '#password'
|
1057
|
+
element :sign_in, 'button'
|
1038
1058
|
end
|
1039
1059
|
|
1040
1060
|
class Registration < SitePrism::Section
|
1041
|
-
element :first_name,
|
1042
|
-
element :last_name,
|
1043
|
-
element :next_step,
|
1061
|
+
element :first_name, '#first_name'
|
1062
|
+
element :last_name, '#last_name'
|
1063
|
+
element :next_step, 'button.next-reg-step'
|
1044
1064
|
end
|
1045
1065
|
|
1046
1066
|
class LoginRegistrationForm < SitePrism::Section
|
1047
|
-
section :login, Login,
|
1048
|
-
section :registration, Registration,
|
1067
|
+
section :login, Login, 'div.login-area'
|
1068
|
+
section :registration, Registration, 'div.reg-area'
|
1049
1069
|
end
|
1050
1070
|
|
1051
1071
|
class Home < SitePrism::Page
|
1052
|
-
section :login_and_registration, LoginRegistrationForm,
|
1072
|
+
section :login_and_registration, LoginRegistrationForm, 'div.login-registration'
|
1053
1073
|
end
|
1054
1074
|
|
1055
1075
|
# how to login (fatuous, but demonstrates the point):
|
@@ -1122,12 +1142,12 @@ Given the following setup:
|
|
1122
1142
|
|
1123
1143
|
```ruby
|
1124
1144
|
class SearchResultSection < SitePrism::Section
|
1125
|
-
element :title,
|
1126
|
-
element :blurb,
|
1145
|
+
element :title, 'a.title'
|
1146
|
+
element :blurb, 'span.result-decription'
|
1127
1147
|
end
|
1128
1148
|
|
1129
1149
|
class SearchResults < SitePrism::Page
|
1130
|
-
sections :search_results, SearchResultSection,
|
1150
|
+
sections :search_results, SearchResultSection, '#results li'
|
1131
1151
|
end
|
1132
1152
|
```
|
1133
1153
|
|
@@ -1169,9 +1189,9 @@ define a single anonymous section:
|
|
1169
1189
|
|
1170
1190
|
```ruby
|
1171
1191
|
class SearchResults < SitePrism::Page
|
1172
|
-
sections :search_results,
|
1173
|
-
element :title,
|
1174
|
-
element :blurb,
|
1192
|
+
sections :search_results, '#results li' do
|
1193
|
+
element :title, 'a.title'
|
1194
|
+
element :blurb, 'span.result-decription'
|
1175
1195
|
end
|
1176
1196
|
end
|
1177
1197
|
```
|
@@ -1186,12 +1206,12 @@ following example:
|
|
1186
1206
|
|
1187
1207
|
```ruby
|
1188
1208
|
class SearchResultSection < SitePrism::Section
|
1189
|
-
element :title,
|
1190
|
-
element :blurb,
|
1209
|
+
element :title, 'a.title'
|
1210
|
+
element :blurb, 'span.result-decription'
|
1191
1211
|
end
|
1192
1212
|
|
1193
1213
|
class SearchResults < SitePrism::Page
|
1194
|
-
sections :search_results, SearchResultSection,
|
1214
|
+
sections :search_results, SearchResultSection, '#results li'
|
1195
1215
|
end
|
1196
1216
|
```
|
1197
1217
|
|
@@ -1220,12 +1240,12 @@ the section in the array of sections. For example:
|
|
1220
1240
|
|
1221
1241
|
```ruby
|
1222
1242
|
class SearchResultSection < SitePrism::Section
|
1223
|
-
element :title,
|
1224
|
-
element :blurb,
|
1243
|
+
element :title, 'a.title'
|
1244
|
+
element :blurb, 'span.result-decription'
|
1225
1245
|
end
|
1226
1246
|
|
1227
1247
|
class SearchResults < SitePrism::Page
|
1228
|
-
sections :search_results, SearchResultSection,
|
1248
|
+
sections :search_results, SearchResultSection, '#results li'
|
1229
1249
|
end
|
1230
1250
|
```
|
1231
1251
|
|
@@ -1386,13 +1406,13 @@ Given the following sample page and elements:
|
|
1386
1406
|
|
1387
1407
|
```ruby
|
1388
1408
|
class SearchResultSection < SitePrism::Section
|
1389
|
-
element :title,
|
1390
|
-
element :blurb,
|
1409
|
+
element :title, 'a.title'
|
1410
|
+
element :blurb, 'span.result-decription'
|
1391
1411
|
end
|
1392
1412
|
|
1393
1413
|
class SearchResults < SitePrism::Page
|
1394
|
-
element :footer,
|
1395
|
-
sections :search_results, SearchResultSection,
|
1414
|
+
element :footer, '.footer'
|
1415
|
+
sections :search_results, SearchResultSection, '#results li'
|
1396
1416
|
end
|
1397
1417
|
```
|
1398
1418
|
|
@@ -1433,9 +1453,9 @@ This is supported for all of the Capybara options including, but not limited to
|
|
1433
1453
|
|
1434
1454
|
```ruby
|
1435
1455
|
class SearchResults < SitePrism::Page
|
1436
|
-
element :footer,
|
1437
|
-
element :view_more,
|
1438
|
-
sections :search_results, SearchResultSection,
|
1456
|
+
element :footer, '.footer'
|
1457
|
+
element :view_more, 'li', text: 'View More'
|
1458
|
+
sections :search_results, SearchResultSection, '#results li'
|
1439
1459
|
end
|
1440
1460
|
```
|
1441
1461
|
|
@@ -1490,7 +1510,7 @@ An iframe is declared in the same way as a Page:
|
|
1490
1510
|
|
1491
1511
|
```ruby
|
1492
1512
|
class MyIframe < SitePrism::Page
|
1493
|
-
element :some_text_field,
|
1513
|
+
element :some_text_field, 'input.username'
|
1494
1514
|
end
|
1495
1515
|
```
|
1496
1516
|
|
@@ -1501,7 +1521,7 @@ iframe, and an ID or class by which you can locate the iframe. For example:
|
|
1501
1521
|
|
1502
1522
|
```ruby
|
1503
1523
|
class PageContainingIframe < SitePrism::Page
|
1504
|
-
iframe :my_iframe, MyIframe,
|
1524
|
+
iframe :my_iframe, MyIframe, '#my_iframe_id'
|
1505
1525
|
end
|
1506
1526
|
```
|
1507
1527
|
|
@@ -1543,15 +1563,15 @@ SitePrism::Page that represents the iframe's contents. For example:
|
|
1543
1563
|
```ruby
|
1544
1564
|
# SitePrism::Page representing the iframe
|
1545
1565
|
class Login < SitePrism::Page
|
1546
|
-
element :username,
|
1547
|
-
element :password,
|
1566
|
+
element :username, 'input.username'
|
1567
|
+
element :password, 'input.password'
|
1548
1568
|
end
|
1549
1569
|
|
1550
1570
|
# SitePrism::Page representing the page that contains the iframe
|
1551
1571
|
class Home < SitePrism::Page
|
1552
|
-
set_url
|
1572
|
+
set_url 'http://www.example.com'
|
1553
1573
|
|
1554
|
-
iframe :login_area, Login,
|
1574
|
+
iframe :login_area, Login, '#login_and_registration'
|
1555
1575
|
end
|
1556
1576
|
|
1557
1577
|
# cucumber step that performs login
|
@@ -1561,8 +1581,8 @@ When /^I log in$/ do
|
|
1561
1581
|
|
1562
1582
|
@home.login_area do |frame|
|
1563
1583
|
#`frame` is an instance of the `Login` class
|
1564
|
-
frame.username.set
|
1565
|
-
frame.password.set
|
1584
|
+
frame.username.set 'admin'
|
1585
|
+
frame.password.set 'p4ssword'
|
1566
1586
|
end
|
1567
1587
|
end
|
1568
1588
|
```
|
@@ -5,7 +5,7 @@ require 'base64'
|
|
5
5
|
|
6
6
|
module SitePrism
|
7
7
|
class AddressableUrlMatcher
|
8
|
-
COMPONENT_NAMES = %
|
8
|
+
COMPONENT_NAMES = %i[scheme user password host port path query fragment].freeze
|
9
9
|
COMPONENT_PREFIXES = {
|
10
10
|
query: '?',
|
11
11
|
fragment: '#'
|
@@ -24,8 +24,9 @@ module SitePrism
|
|
24
24
|
result = {}
|
25
25
|
COMPONENT_NAMES.each do |component|
|
26
26
|
component_result = component_matches(component, uri)
|
27
|
-
|
28
|
-
|
27
|
+
return nil unless component_result
|
28
|
+
|
29
|
+
result.merge!(component_result)
|
29
30
|
end
|
30
31
|
result
|
31
32
|
end
|
@@ -35,7 +36,7 @@ module SitePrism
|
|
35
36
|
def matches?(url, expected_mappings = {})
|
36
37
|
actual_mappings = mappings(url)
|
37
38
|
if actual_mappings
|
38
|
-
expected_mappings.empty?
|
39
|
+
expected_mappings.empty? || all_expected_mappings_match?(expected_mappings, actual_mappings)
|
39
40
|
else
|
40
41
|
false
|
41
42
|
end
|
@@ -57,7 +58,6 @@ module SitePrism
|
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
|
-
# Memoizes the extracted component templates
|
61
61
|
def component_templates
|
62
62
|
@component_templates ||= extract_component_templates
|
63
63
|
end
|
@@ -66,14 +66,14 @@ module SitePrism
|
|
66
66
|
COMPONENT_NAMES.each_with_object({}) do |component, component_templates|
|
67
67
|
component_url = to_substituted_uri.public_send(component).to_s
|
68
68
|
|
69
|
-
next unless component_url && component_url
|
69
|
+
next unless component_url && !component_url.empty?
|
70
70
|
|
71
71
|
reverse_substitutions.each_pair do |substituted_value, template_value|
|
72
72
|
component_url = component_url.sub(substituted_value, template_value)
|
73
73
|
end
|
74
74
|
|
75
75
|
component_templates[component] = Addressable::Template.new(component_url.to_s)
|
76
|
-
end
|
76
|
+
end
|
77
77
|
end
|
78
78
|
|
79
79
|
# Returns empty hash if the template omits the component, a set of substitutions if the
|
@@ -83,7 +83,8 @@ module SitePrism
|
|
83
83
|
component_template = component_templates[component]
|
84
84
|
if component_template
|
85
85
|
component_url = uri.public_send(component).to_s
|
86
|
-
|
86
|
+
extracted_mappings = component_template.extract(component_url)
|
87
|
+
unless extracted_mappings
|
87
88
|
# to support Addressable's expansion of queries, ensure it's parsing the fragment as appropriate (e.g. {?params*})
|
88
89
|
prefix = COMPONENT_PREFIXES[component]
|
89
90
|
return nil unless prefix && (extracted_mappings = component_template.extract(prefix + component_url))
|
@@ -101,36 +102,38 @@ module SitePrism
|
|
101
102
|
begin
|
102
103
|
Addressable::URI.parse(url)
|
103
104
|
rescue Addressable::URI::InvalidURIError
|
104
|
-
raise SitePrism::InvalidUrlMatcher
|
105
|
+
raise SitePrism::InvalidUrlMatcher
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
108
109
|
def substitutions
|
109
|
-
@substitutions ||= slugs.each_with_index.reduce({}) do |memo,
|
110
|
-
slug, index =
|
110
|
+
@substitutions ||= slugs.each_with_index.reduce({}) do |memo, slug_index|
|
111
|
+
slug, index = slug_index
|
111
112
|
memo.merge(slug => slug_prefix(slug) + substitution_value(index))
|
112
113
|
end
|
113
114
|
end
|
114
115
|
|
115
116
|
def reverse_substitutions
|
116
|
-
@reverse_substitutions ||= slugs.each_with_index.reduce({}) do |memo,
|
117
|
-
slug, index =
|
117
|
+
@reverse_substitutions ||= slugs.each_with_index.reduce({}) do |memo, slug_index|
|
118
|
+
slug, index = slug_index
|
118
119
|
memo.merge(slug_prefix(slug) + substitution_value(index) => slug, substitution_value(index) => slug)
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
122
123
|
def slugs
|
123
|
-
pattern.scan(
|
124
|
+
pattern.scan(/{[^}]+}/)
|
124
125
|
end
|
125
126
|
|
126
|
-
# If a slug begins with non-alpha characters, it may denote the start of a new component
|
127
|
-
# We emit this prefix as part of the substituted slug
|
127
|
+
# If a slug begins with non-alpha characters, it may denote the start of a new component
|
128
|
+
# (e.g. query or fragment). We emit this prefix as part of the substituted slug
|
129
|
+
# so that Addressable's URI parser can see it as such.
|
128
130
|
def slug_prefix(slug)
|
129
|
-
matches = slug.match(/\A
|
131
|
+
matches = slug.match(/\A{([^A-Za-z]+)/)
|
130
132
|
matches && matches[1] || ''
|
131
133
|
end
|
132
134
|
|
133
|
-
# Generate a repeatable 5 character uniform alphabetical nonsense string
|
135
|
+
# Generate a repeatable 5 character uniform alphabetical nonsense string
|
136
|
+
# to allow parsing as a URI
|
134
137
|
def substitution_value(index)
|
135
138
|
Base64.urlsafe_encode64(Digest::SHA1.digest(index.to_s)).gsub(/[^A-Za-z]/, '')[0..5]
|
136
139
|
end
|
@@ -3,7 +3,15 @@
|
|
3
3
|
module SitePrism
|
4
4
|
module ElementChecker
|
5
5
|
def all_there?
|
6
|
-
|
6
|
+
elements_to_check.all? { |element| send "has_#{element}?" }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def elements_to_check
|
12
|
+
elements = self.class.mapped_items
|
13
|
+
elements = elements.select { |el| self.class.expected_items.include?(el) } if self.class.expected_items
|
14
|
+
elements
|
7
15
|
end
|
8
16
|
end
|
9
17
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module SitePrism
|
4
4
|
module ElementContainer
|
5
|
-
attr_reader :mapped_items
|
5
|
+
attr_reader :mapped_items, :expected_items
|
6
6
|
|
7
7
|
def element(element_name, *find_args)
|
8
8
|
build element_name, *find_args do
|
@@ -23,6 +23,10 @@ module SitePrism
|
|
23
23
|
end
|
24
24
|
alias collection elements
|
25
25
|
|
26
|
+
def expected_elements(*elements)
|
27
|
+
@expected_items = elements
|
28
|
+
end
|
29
|
+
|
26
30
|
def section(section_name, *args, &block)
|
27
31
|
section_class, find_args = extract_section_options args, &block
|
28
32
|
build section_name, *find_args do
|
@@ -60,7 +64,7 @@ module SitePrism
|
|
60
64
|
|
61
65
|
def add_to_mapped_items(item)
|
62
66
|
@mapped_items ||= []
|
63
|
-
@mapped_items << item
|
67
|
+
@mapped_items << item
|
64
68
|
end
|
65
69
|
|
66
70
|
def raise_if_block(obj, name, has_block)
|
@@ -178,7 +182,7 @@ module SitePrism
|
|
178
182
|
elsif block_given?
|
179
183
|
section_class = Class.new SitePrism::Section, &block
|
180
184
|
else
|
181
|
-
raise ArgumentError, 'You should provide section class either as a block, or as the second argument'
|
185
|
+
raise ArgumentError, 'You should provide section class either as a block, or as the second argument.'
|
182
186
|
end
|
183
187
|
return section_class, args
|
184
188
|
end
|
@@ -3,7 +3,13 @@
|
|
3
3
|
module SitePrism
|
4
4
|
class NoUrlForPage < StandardError; end
|
5
5
|
class NoUrlMatcherForPage < StandardError; end
|
6
|
-
|
6
|
+
|
7
|
+
class InvalidUrlMatcher < StandardError
|
8
|
+
def message
|
9
|
+
'Could not automatically match your URL. Templated port numbers are unsupported.'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
7
13
|
class NoSelectorForElement < StandardError; end
|
8
14
|
class TimeoutException < StandardError; end
|
9
15
|
class TimeOutWaitingForElementVisibility < StandardError; end
|
data/lib/site_prism/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,44 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: site_prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.11'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nat Ritmeyer
|
8
|
+
- Luke Hill
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2018-
|
12
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: addressable
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
|
-
- - ~>
|
18
|
+
- - "~>"
|
18
19
|
- !ruby/object:Gem::Version
|
19
20
|
version: '2.4'
|
20
21
|
type: :runtime
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
|
-
- - ~>
|
25
|
+
- - "~>"
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '2.4'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: capybara
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- - ~>
|
32
|
+
- - "~>"
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
34
|
+
version: '2.7'
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
37
|
version_requirements: !ruby/object:Gem::Requirement
|
37
38
|
requirements:
|
38
|
-
- - ~>
|
39
|
+
- - "~>"
|
39
40
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
41
|
+
version: '2.7'
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
43
|
name: cucumber
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,42 +57,42 @@ dependencies:
|
|
56
57
|
name: rake
|
57
58
|
requirement: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
|
-
- -
|
60
|
+
- - ">="
|
60
61
|
- !ruby/object:Gem::Version
|
61
62
|
version: '11.0'
|
62
63
|
type: :development
|
63
64
|
prerelease: false
|
64
65
|
version_requirements: !ruby/object:Gem::Requirement
|
65
66
|
requirements:
|
66
|
-
- -
|
67
|
+
- - ">="
|
67
68
|
- !ruby/object:Gem::Version
|
68
69
|
version: '11.0'
|
69
70
|
- !ruby/object:Gem::Dependency
|
70
71
|
name: redcarpet
|
71
72
|
requirement: !ruby/object:Gem::Requirement
|
72
73
|
requirements:
|
73
|
-
- - ~>
|
74
|
+
- - "~>"
|
74
75
|
- !ruby/object:Gem::Version
|
75
76
|
version: '3.0'
|
76
77
|
type: :development
|
77
78
|
prerelease: false
|
78
79
|
version_requirements: !ruby/object:Gem::Requirement
|
79
80
|
requirements:
|
80
|
-
- - ~>
|
81
|
+
- - "~>"
|
81
82
|
- !ruby/object:Gem::Version
|
82
83
|
version: '3.0'
|
83
84
|
- !ruby/object:Gem::Dependency
|
84
85
|
name: rspec
|
85
86
|
requirement: !ruby/object:Gem::Requirement
|
86
87
|
requirements:
|
87
|
-
- - ~>
|
88
|
+
- - "~>"
|
88
89
|
- !ruby/object:Gem::Version
|
89
90
|
version: '3.2'
|
90
91
|
type: :development
|
91
92
|
prerelease: false
|
92
93
|
version_requirements: !ruby/object:Gem::Requirement
|
93
94
|
requirements:
|
94
|
-
- - ~>
|
95
|
+
- - "~>"
|
95
96
|
- !ruby/object:Gem::Version
|
96
97
|
version: '3.2'
|
97
98
|
- !ruby/object:Gem::Dependency
|
@@ -112,47 +113,36 @@ dependencies:
|
|
112
113
|
name: selenium-webdriver
|
113
114
|
requirement: !ruby/object:Gem::Requirement
|
114
115
|
requirements:
|
115
|
-
- - ~>
|
116
|
+
- - "~>"
|
116
117
|
- !ruby/object:Gem::Version
|
117
118
|
version: 3.4.0
|
118
119
|
type: :development
|
119
120
|
prerelease: false
|
120
121
|
version_requirements: !ruby/object:Gem::Requirement
|
121
122
|
requirements:
|
122
|
-
- - ~>
|
123
|
+
- - "~>"
|
123
124
|
- !ruby/object:Gem::Version
|
124
125
|
version: 3.4.0
|
125
126
|
- !ruby/object:Gem::Dependency
|
126
127
|
name: simplecov
|
127
128
|
requirement: !ruby/object:Gem::Requirement
|
128
129
|
requirements:
|
129
|
-
- -
|
130
|
+
- - ">="
|
130
131
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0.
|
132
|
+
version: '0.11'
|
132
133
|
type: :development
|
133
134
|
prerelease: false
|
134
135
|
version_requirements: !ruby/object:Gem::Requirement
|
135
136
|
requirements:
|
136
|
-
- -
|
137
|
+
- - ">="
|
137
138
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0.
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
version: '0.8'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ~>
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0.8'
|
153
|
-
description: SitePrism gives you a simple, clean and semantic DSL for describing your
|
154
|
-
site using the Page Object Model pattern, for use with Capybara
|
155
|
-
email: nat@natontesting.com
|
139
|
+
version: '0.11'
|
140
|
+
description: |-
|
141
|
+
SitePrism gives you a simple, clean and semantic DSL for describing your site.
|
142
|
+
SitePrism implements the Page Object Model pattern on top of Capybara.
|
143
|
+
email:
|
144
|
+
- nat@natontesting.com
|
145
|
+
- lukehill_uk@hotmail.com
|
156
146
|
executables: []
|
157
147
|
extensions: []
|
158
148
|
extra_rdoc_files: []
|
@@ -179,17 +169,17 @@ require_paths:
|
|
179
169
|
- lib
|
180
170
|
required_ruby_version: !ruby/object:Gem::Requirement
|
181
171
|
requirements:
|
182
|
-
- -
|
172
|
+
- - ">="
|
183
173
|
- !ruby/object:Gem::Version
|
184
174
|
version: '2.0'
|
185
175
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
176
|
requirements:
|
187
|
-
- -
|
177
|
+
- - ">="
|
188
178
|
- !ruby/object:Gem::Version
|
189
179
|
version: '0'
|
190
180
|
requirements: []
|
191
181
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.
|
182
|
+
rubygems_version: 2.6.13
|
193
183
|
signing_key:
|
194
184
|
specification_version: 4
|
195
185
|
summary: A Page Object Model DSL for Capybara
|