site_prism 3.2 → 3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bb0a772ccdabf209eba492206b0c664418fa46f1b2bdb2c8d08cbcf384b5522
4
- data.tar.gz: be9c7ca220f2a20122a3bfd955fa617acda1ecb3d6aedac9472300f4c17ff014
3
+ metadata.gz: 95c8d9ff0cf7f2b818a8b8cb987ca39f2b512138d572a08533b8466feae6cb63
4
+ data.tar.gz: 6239a4a2cd9be9233396f2b221328645dcb50a56e531ee0d5b63faa3dbd9bf53
5
5
  SHA512:
6
- metadata.gz: d21079c647c16bcb896374557448fc9c514ce8d3d16379e77f64be741b2ef76f7c2438ff9fd3d0f5bdd96a3678d92b40e162d3847a04647de1ed553b7a786b2f
7
- data.tar.gz: bf7ea9e4ff98d6ae92427a98b21a35bd519638080c5b3c55f9565e163710b748c11152374293ee783d32a1f1ef599bbac5be99a56f696d144fb1f53d0d7836d4
6
+ metadata.gz: a9a7a79356b8f4c16aad85f923db99a549bba2c78ec23624f245504ce3bbffd7698bad6a572ddbb34cbf9f2406da76bda7ce5d2433d874270112025e5e9d79ea
7
+ data.tar.gz: 897ae6d1b6a944b52bc5f36ebb81e2796657a276bfa41994fd0a5315031457d404b46408660556644eb262258c8033b72aa5d7400bd79d13f8085993575df826
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SitePrism
2
2
  [![Gem Version](https://badge.fury.io/rb/site_prism.svg)](https://badge.fury.io/rb/site_prism)
3
- [![Build Status](https://travis-ci.org/natritmeyer/site_prism.png)](https://travis-ci.org/natritmeyer/site_prism)
3
+ [![Build Status](https://travis-ci.com/site-prism/site_prism.png)](https://travis-ci.com/site-prism/site_prism)
4
4
 
5
5
  _A Page Object Model DSL for Capybara_
6
6
 
@@ -9,24 +9,24 @@ for use with Capybara in automated acceptance testing.
9
9
 
10
10
  Find the pretty documentation here: http://rdoc.info/gems/site_prism/frames
11
11
 
12
- Make sure to add your project/company to https://github.com/natritmeyer/site_prism/wiki/Who-is-using-SitePrism
12
+ Make sure to add your project/company to https://github.com/site-prism/site_prism/wiki/Who-is-using-SitePrism
13
13
 
14
14
  ## Developing / Contributing to SitePrism
15
15
 
16
16
  We love it when people want to get involved with our Open Source Project.
17
17
 
18
- We have a brief set of setup docs [HERE](https://github.com/natritmeyer/site_prism/blob/master/development_setup.md)
18
+ We have a brief set of setup docs [HERE](https://github.com/site-prism/site_prism/blob/master/HACKING.md)
19
19
 
20
20
  ## Supported Rubies / Browsers
21
21
 
22
22
  SitePrism is built and tested to work on Ruby 2.4 - 2.6. Ruby 2.3 (Now EOL), is supported but not tested against.
23
23
  If you are using SitePrism with Ruby 2.3 it is highly advisable to upgrade to a more modern Ruby
24
- such as 2.5 or 2.6, if for any other reason, to get a noticeable speed boost!
24
+ such as 2.6 or 2.7, if for any other reason, to get a noticeable speed boost!
25
25
 
26
26
  SitePrism should run on all major browsers. The gem's integration tests are ran on Chrome and Firefox.
27
27
 
28
28
  If you find you cannot integrate nicely with SitePrism, please open an
29
- [issue request](https://github.com/natritmeyer/site_prism/issues/new)
29
+ [issue request](https://github.com/site-prism/site_prism/issues/new)
30
30
 
31
31
  ## Synopsis
32
32
 
@@ -42,14 +42,14 @@ class Home < SitePrism::Page
42
42
  element :search_field, 'input[name="q"]'
43
43
  element :search_button, 'button[name="btnK"]'
44
44
  elements :footer_links, '#footer a'
45
- section :menu, MenuSection, '#gbx3'
45
+ section :menu, Menu, '#gbx3'
46
46
  end
47
47
 
48
48
  class SearchResults < SitePrism::Page
49
49
  set_url_matcher(/google.com\/results\?.*/)
50
50
 
51
- section :menu, MenuSection, '#gbx3'
52
- sections :search_results, SearchResultSection, '#results li'
51
+ section :menu, Menu, '#gbx3'
52
+ sections :search_results, SearchResults, '#results li'
53
53
 
54
54
  def search_result_links
55
55
  search_results.map { |result| result.title['href'] }
@@ -58,13 +58,13 @@ end
58
58
 
59
59
  # define sections used on multiple pages or multiple times on one page
60
60
 
61
- class MenuSection < SitePrism::Section
61
+ class Menu < SitePrism::Section
62
62
  element :search, 'a.search'
63
63
  element :images, 'a.image-search'
64
64
  element :maps, 'a.map-search'
65
65
  end
66
66
 
67
- class SearchResultSection < SitePrism::Section
67
+ class SearchResults < SitePrism::Section
68
68
  element :title, 'a.title'
69
69
  element :blurb, 'span.result-description'
70
70
  end
@@ -124,6 +124,22 @@ require 'capybara'
124
124
  require 'capybara/cucumber'
125
125
  require 'selenium-webdriver'
126
126
  require 'site_prism'
127
+ require 'site_prism/all_there' # Optional but needed to perform more complex matching
128
+ ```
129
+
130
+ The driver creation is identical to how you would normally create a Capybara driver,
131
+ a sample Selenium one could look something like this...
132
+
133
+ ```ruby
134
+ Capybara.register_driver :site_prism do |app|
135
+ browser = ENV.fetch('browser', 'firefox').to_sym
136
+ Capybara::Selenium::Driver.new(app, browser: browser, desired_capabilities: capabilities)
137
+ end
138
+
139
+ # Then tell Capybara to use the Driver you've just defined as its default driver
140
+ Capybara.configure do |config|
141
+ config.default_driver = :site_prism
142
+ end
127
143
  ```
128
144
 
129
145
  ### Using SitePrism with RSpec
@@ -135,8 +151,11 @@ require 'capybara'
135
151
  require 'capybara/rspec'
136
152
  require 'selenium-webdriver'
137
153
  require 'site_prism'
154
+ require 'site_prism/all_there' # Optional but needed to perform more complex matching
138
155
  ```
139
156
 
157
+ And again, as above, a sample driver is no different to a normal driver instantiation in Capybara.
158
+
140
159
  ## Introduction to the Page Object Model
141
160
 
142
161
  The Page Object Model is a test automation pattern that aims to create
@@ -158,7 +177,7 @@ multiple pages, or many times on a page using the concept of sections.
158
177
  As you might be able to guess from the name, pages are fairly central to
159
178
  the Page Object Model. Here's how SitePrism models them:
160
179
 
161
- ### Creating a Page Model
180
+ ### Creating your first Page using the Page Object Model
162
181
 
163
182
  The simplest page is one that has nothing defined in it. Here's an
164
183
  example of how to begin modelling a home page:
@@ -168,7 +187,7 @@ class Home < SitePrism::Page
168
187
  end
169
188
  ```
170
189
 
171
- The above has nothing useful defined, only the name.
190
+ The above has nothing useful defined, so to start with lets give it some properties.
172
191
 
173
192
  ### Adding a URL
174
193
 
@@ -177,7 +196,7 @@ you'll need to set its URL. Here's how:
177
196
 
178
197
  ```ruby
179
198
  class Home < SitePrism::Page
180
- set_url 'http://www.google.com'
199
+ set_url 'http://www.mysite.com/home.htm'
181
200
  end
182
201
  ```
183
202
 
@@ -332,7 +351,7 @@ end
332
351
  SitePrism's `#displayed?` predicate method allows for semantic code in your tests:
333
352
 
334
353
  ```ruby
335
- Then /^the account page is displayed$/ do
354
+ Then(/^the account page is displayed$/) do
336
355
  expect(@account_page).to be_displayed
337
356
  expect(@some_other_page).not_to be_displayed
338
357
  end
@@ -431,7 +450,7 @@ end
431
450
  #### Testing for the existence of the element
432
451
 
433
452
  Another method added to the Page class by the `element` method is the
434
- `has_<element name>?` method. Using the same example as above:
453
+ `has_<element_name>?` method. Using the same example as above:
435
454
 
436
455
  ```ruby
437
456
  class Home < SitePrism::Page
@@ -452,7 +471,7 @@ end
452
471
  ...which makes for nice test code:
453
472
 
454
473
  ```ruby
455
- Then /^the search field exists$/ do
474
+ Then(/^the search field exists$/) do
456
475
  expect(@home).to have_search_field
457
476
  end
458
477
  ```
@@ -472,14 +491,14 @@ that should be used to test for non-existence. Using the above example:
472
491
  ...which makes for nice test code:
473
492
 
474
493
  ```ruby
475
- Then /^the search field exists$/ do
494
+ Then(/^the search field exists$/)do
476
495
  expect(@home).to have_no_search_field #NB: NOT => expect(@home).not_to have_search_field
477
496
  end
478
497
  ```
479
498
 
480
499
  #### Waiting for an element to become visible
481
500
 
482
- A method that gets added by calling `element` is the
501
+ A method that gets added by calling `element` is the
483
502
  `wait_until_<element_name>_visible` method. Calling this method will
484
503
  cause the test to wait for Capybara's default wait time for the element
485
504
  to become visible. You can customise the wait time by supplying a number
@@ -594,7 +613,6 @@ Or even run some tests ...
594
613
  ```ruby
595
614
  expect(@friends_page.names.map { |name| name.text }).to eq(['Alice', 'Bob', 'Fred'])
596
615
  expect(@friends_page.names.size).to eq(3)
597
- expect(@friends_page).to have(3).names
598
616
  ```
599
617
 
600
618
  #### Testing for the existence of the element collection
@@ -620,7 +638,7 @@ Then the following method is available:
620
638
  This in turn allows the following nice test code
621
639
 
622
640
  ```ruby
623
- Then /^there should be some names listed on the page$/ do
641
+ Then(/^there should be some names listed on the page$/) do
624
642
  expect(@friends_page).to have_names #=> This only passes if there is at least one `name`
625
643
  end
626
644
  ```
@@ -661,7 +679,7 @@ are present in the browser and `false` if they're not all there.
661
679
 
662
680
  # and...
663
681
 
664
- Then /^the friends page contains all the expected elements$/ do
682
+ Then(/^the friends page contains all the expected elements$/) do
665
683
  expect(@friends_page).to be_all_there
666
684
  end
667
685
  ```
@@ -696,6 +714,28 @@ end
696
714
  @test_page.elements_present #=> [:address_field]
697
715
  ```
698
716
 
717
+ If you are specifying a highly nested set of sections inside a Page and need to recurse
718
+ through them to find out if all of your items are present then you can also do this.
719
+
720
+ Simply pass a recursion parameter to the `#all_there?` check. Note that the only valid values
721
+ for this at the moment are `:none` and `:one`
722
+
723
+ Passing `:none` (default), will not change the functionality. However passing in `:one` will cause
724
+ `site_prism` to recurse through all `section` / `sections` items defined in your present scope.
725
+
726
+ Work alongside developing this functionality further is being continued in the
727
+ [site_prism-all_there](http://www.github.com/site-prism/site_prism-all_there) repo. So head on over
728
+ there if you're interested in how this feature will work going forwards
729
+
730
+ NB: At the moment a "primitive" but working copy of this is hosted inside this gem. But if you wish to
731
+ use the bleeding edge version of the logic. Then simply set the following configuration parameter
732
+
733
+ ```ruby
734
+ `require 'site_prism/all_there'`
735
+
736
+ SitePrism.use_all_there_gem = true
737
+ ```
738
+
699
739
  ## Sections
700
740
 
701
741
  SitePrism allows you to model sections of a page that appear on multiple
@@ -751,7 +791,7 @@ class People < SitePrism::Section
751
791
  element :footer, 'h4'
752
792
  end
753
793
 
754
- class HomePage < SitePrism::Page
794
+ class Home < SitePrism::Page
755
795
  # section people_with_block will have `headline` and
756
796
  # `footer` elements in it
757
797
  section :people_with_block, People do
@@ -871,7 +911,7 @@ end
871
911
  This then leads to some pretty test code ...
872
912
 
873
913
  ```ruby
874
- Then /^the home page menu contains a link to the various search functions$/ do
914
+ Then(/^the home page menu contains a link to the various search functions$/) do
875
915
  expect(@home.menu).to have_search
876
916
  expect(@home.menu.search['href']).to include('google.com')
877
917
  expect(@home.menu).to have_images
@@ -881,14 +921,13 @@ end
881
921
 
882
922
  ##### Accessing section elements using a block
883
923
 
884
- A Section can be scoped so it is only accessible inside a block. This is
924
+ You can execute a block within the context of a Section. This is
885
925
  similar to Capybara's `within` method and allows for shorter test code
886
- particularly with nested sections. Some of this test code can be
887
- made a little prettier by simply passing a block in.
926
+ particularly with nested sections. Test code that might have to repeat the block name can be shortened up this way.
888
927
 
889
928
  ```ruby
890
- Then /^the home page menu contains a link to the various search functions$/ do
891
- @home.menu do |menu|
929
+ Then(/^the home page menu contains a link to the various search functions$/) do
930
+ @home.menu.within do |menu|
892
931
  expect(menu).to have_search
893
932
  expect(menu.search['href']).to include('google.com')
894
933
  expect(menu).to have_images
@@ -897,33 +936,43 @@ Then /^the home page menu contains a link to the various search functions$/ do
897
936
  end
898
937
  ```
899
938
 
939
+ Note that on an individual section it's possible to pass a block directly to the section without using `within`. Because the block is executed only during `Section` initialization this won't work when accessing a single Section from an array of Sections. For that reason we recommend using `within` which works in either case.
940
+
941
+ ```ruby
942
+ Then(/^the home page menu contains a link to the various search functions$/) do
943
+ @home.menu do |menu| # possible, but prefer: `@home.menu.within`
944
+ expect(menu).to have_search
945
+ end
946
+ end
947
+ ```
948
+
900
949
  #### Getting a section's parent
901
950
 
902
951
  It is possible to ask a section for its parent (page, or section if this
903
952
  section is a subsection). For example, given the following setup:
904
953
 
905
954
  ```ruby
906
- class MySubSection < SitePrism::Section
907
- element :some_element, 'abc'
955
+ class DestinationFilters < SitePrism::Section
956
+ element :morocco, 'abc'
908
957
  end
909
958
 
910
- class MySection < SitePrism::Section
911
- section :my_subsection, MySubSection, 'def'
959
+ class FilterPanel < SitePrism::Section
960
+ section :destination_filters, DestinationFilters, 'def'
912
961
  end
913
962
 
914
- class MyPage < SitePrism::Page
915
- section :my_section, MySection, 'ghi'
963
+ class Home < SitePrism::Page
964
+ section :filter_panel, FilterPanel, 'ghi'
916
965
  end
917
966
  ```
918
967
 
919
968
  Then calling `#parent` will return the following:
920
969
 
921
970
  ```ruby
922
- @my_page = MyPage.new
923
- @my_page.load
971
+ @home = Home.new
972
+ @home.load
924
973
 
925
- @my_page.my_section.parent #=> returns @my_page
926
- @my_page.my_section.my_subsection.parent #=> returns @my_page.my_section
974
+ @home.filter_panel.parent #=> returns @home
975
+ @home.filter_panel.destination_filters.parent #=> returns @home.filter_panel
927
976
  ```
928
977
 
929
978
  #### Getting a section's parent page
@@ -1044,7 +1093,7 @@ end
1044
1093
 
1045
1094
  # how to login (fatuous, but demonstrates the point):
1046
1095
 
1047
- Then /^I sign in$/ do
1096
+ Then(/^I sign in$/) do
1048
1097
  @home = Home.new
1049
1098
  @home.load
1050
1099
  expect(@home).to have_login_and_registration
@@ -1056,7 +1105,7 @@ end
1056
1105
 
1057
1106
  # how to sign up:
1058
1107
 
1059
- When /^I enter my name into the home page's registration form$/ do
1108
+ When(/^I enter my name into the home page's registration form$/) do
1060
1109
  @home = Home.new
1061
1110
  @home.load
1062
1111
  expect(@home.login_and_registration).to have_first_name
@@ -1133,9 +1182,9 @@ end
1133
1182
  This allows for pretty tests ...
1134
1183
 
1135
1184
  ```ruby
1136
- Then /^there are lots of search_results$/ do
1185
+ Then(/^there are lots of search_results$/) do
1137
1186
  expect(@results_page.search_results.size).to eq(10)
1138
-
1187
+
1139
1188
  @home.search_results.each do |result|
1140
1189
  expect(result).to have_title
1141
1190
  expect(result.blurb.text).not_to be_empty
@@ -1144,13 +1193,33 @@ end
1144
1193
  ```
1145
1194
 
1146
1195
  The css selector that is passed as the 3rd argument to the
1147
- `sections` method ("#results li") is used to find a number of capybara
1196
+ `sections` method (`#results li`) is used to find a number of capybara
1148
1197
  elements. Each capybara element found using the css selector is used to
1149
1198
  create a new instance of `SearchResults` and becomes its root
1150
1199
  element. So if the css selector finds 3 `li` elements, calling
1151
1200
  `search_results` will return an array containing 3 instances of
1152
1201
  `SearchResults`, each with one of the `li` elements as it's root element.
1153
1202
 
1203
+ ##### Accessing Within a Collection of Sections
1204
+
1205
+ When using an iterator such as `each` to pass a block through to a collection of sections it is possible to skip using `within`. However some caution is warranted when accessing the Sections directly from an array, as the block can only be executed when the section is being initialized. The following does not work:
1206
+
1207
+ ```rb
1208
+ @home.search_results.first do |result|
1209
+ # This block is silently ignored.
1210
+ expect(result).to have_title
1211
+ end
1212
+ ```
1213
+ Instead use `within` to access the inner-context of the Section.
1214
+
1215
+ ```rb
1216
+ @home.search_results.first.within do |result|
1217
+ # This block is run within the context of the Section.
1218
+ expect(result).to have_title
1219
+ end
1220
+ ```
1221
+
1222
+
1154
1223
  #### Anonymous Section Collections
1155
1224
 
1156
1225
  You can define collections of anonymous sections the same way you would
@@ -1197,7 +1266,7 @@ Here's how to test for the existence of the section:
1197
1266
  This allows for some pretty tests ...
1198
1267
 
1199
1268
  ```ruby
1200
- Then /^there are search results on the page$/ do
1269
+ Then(/^there are search results on the page$/) do
1201
1270
  expect(@home).to have_search_results
1202
1271
  end
1203
1272
  ```
@@ -1347,7 +1416,7 @@ instance of the class when created.
1347
1416
 
1348
1417
  ### Skipping load Validations
1349
1418
 
1350
- Defined load validations can be skipped for one `load` call by
1419
+ Defined load validations can be skipped for one `load` call by
1351
1420
  passing in `with_validations: false`.
1352
1421
 
1353
1422
  ```ruby
@@ -1398,7 +1467,7 @@ the validations will be performed in the following order:
1398
1467
  **NB:** `SitePrism::Page` **used to** include a default load validation on
1399
1468
  `page.displayed?` however for v3 this has been removed. It is therefore
1400
1469
  necessary to re-define this if you want to retain the behaviour
1401
- from site_prism v2. See [UPGRADING.md](https://github.com/natritmeyer/site_prism/blob/master/UPGRADING.md#default-load-validations)
1470
+ from site_prism v2. See [UPGRADING.md](https://github.com/site-prism/site_prism/blob/master/UPGRADING.md#default-load-validations)
1402
1471
  for more info on this.
1403
1472
 
1404
1473
  ## Using Capybara Query Options
@@ -1448,7 +1517,7 @@ Now we can write pretty, non-failing tests without hard coding these options
1448
1517
  into our page and section classes:
1449
1518
 
1450
1519
  ```ruby
1451
- Then /^there are search results on the page$/ do
1520
+ Then(/^there are search results on the page$/) do
1452
1521
  expect(@results_page).to have_search_results(count: 25)
1453
1522
  end
1454
1523
  ```
@@ -1581,7 +1650,7 @@ class Home < SitePrism::Page
1581
1650
  end
1582
1651
 
1583
1652
  # cucumber step that performs login
1584
- When /^I log in$/ do
1653
+ When(/^I log in$/) do
1585
1654
  @home = Home.new
1586
1655
  @home.load
1587
1656
 
@@ -1612,9 +1681,9 @@ as per the code below
1612
1681
 
1613
1682
  ```ruby
1614
1683
  Capybara.configure do |config|
1615
- config.default_max_wait_time = 11 #=> Wait up to 11 seconds for all querys to fail
1616
- # or alternatively, if you don't want to ever wait
1617
- config.default_max_wait_time = 0 #=> Don't ever wait!
1684
+ config.default_max_wait_time = 11 #=> Wait up to 11 seconds for all queries to fail
1685
+ # or if you don't want to ever wait
1686
+ config.default_max_wait_time = 0 #=> Don't ever wait!
1618
1687
  end
1619
1688
  ```
1620
1689
 
@@ -1636,6 +1705,9 @@ end
1636
1705
  There's a SitePrism plugin called `site_prism.vcr` that lets you use
1637
1706
  SitePrism with the VCR gem. Check it out [HERE](https://github.com/dnesteryuk/site_prism.vcr)
1638
1707
 
1708
+ Note that as of 2016 this plugin doesn't appear to have been under active development. Also it is
1709
+ still pinned to the `2.x` series of site_prism so use it of your own accord.
1710
+
1639
1711
  # Epilogue
1640
1712
 
1641
1713
  So, we've seen how to use SitePrism to put together page objects made up
@@ -5,14 +5,18 @@ require 'addressable/template'
5
5
 
6
6
  module SitePrism
7
7
  autoload :AddressableUrlMatcher, 'site_prism/addressable_url_matcher'
8
+ autoload :Deprecator, 'site_prism/deprecator'
8
9
  autoload :DSL, 'site_prism/dsl'
9
10
  autoload :ElementChecker, 'site_prism/element_checker'
11
+ autoload :RecursionChecker, 'site_prism/recursion_checker'
10
12
  autoload :Logger, 'site_prism/logger'
11
13
  autoload :Page, 'site_prism/page'
12
14
  autoload :Section, 'site_prism/section'
13
15
  autoload :Waiter, 'site_prism/waiter'
14
16
 
15
17
  class << self
18
+ attr_reader :use_all_there_gem
19
+
16
20
  def configure
17
21
  yield self
18
22
  end
@@ -63,5 +67,13 @@ module SitePrism
63
67
  def log_level
64
68
  %i[DEBUG INFO WARN ERROR FATAL UNKNOWN][logger.level]
65
69
  end
70
+
71
+ # Whether you wish to use the new experimental all_there dependent gem
72
+ # This will be enforced from site_prism v4 onwards as this is where
73
+ # the development of this functionality will be focused
74
+ def use_all_there_gem=(value)
75
+ logger.debug("Setting use_all_there_gem to #{value}")
76
+ @use_all_there_gem = value
77
+ end
66
78
  end
67
79
  end
@@ -98,7 +98,7 @@ module SitePrism
98
98
  begin
99
99
  Addressable::URI.parse(url)
100
100
  rescue Addressable::URI::InvalidURIError
101
- SitePrism.logger.warn("Ensure you don't use templated port numbers.")
101
+ SitePrism.logger.fatal("Ensure you don't use templated port numbers.")
102
102
  raise SitePrism::InvalidUrlMatcherError
103
103
  end
104
104
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SitePrism
4
+ class Deprecator
5
+ class << self
6
+ def deprecate(old, new = nil)
7
+ if new
8
+ warn("#{old} is being deprecated and should no longer be used. Use #{new} instead.")
9
+ else
10
+ warn("#{old} is being deprecated and should no longer be used.")
11
+ end
12
+
13
+ warn("#{old} will be removed in SitePrism v4. You have been warned!")
14
+ end
15
+
16
+ def soft_deprecate(old, reason, new = nil)
17
+ debug("The #{old} method is changing, as is SitePrism, and is now configurable.")
18
+ debug("REASON: #{reason}.")
19
+ debug('Moving forwards into SitePrism v4, the default behaviour will change.')
20
+ debug("We advise you change to using #{new}") if new
21
+ end
22
+
23
+ private
24
+
25
+ def warn(msg)
26
+ SitePrism.logger.warn(msg)
27
+ end
28
+
29
+ def debug(msg)
30
+ SitePrism.logger.debug(msg)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -36,6 +36,14 @@ module SitePrism
36
36
  raise SitePrism::UnsupportedBlockError
37
37
  end
38
38
 
39
+ # Warn users from naming the elements starting with no_
40
+ def warn_if_dsl_collision(obj, name)
41
+ return unless name.to_s.start_with?('no_')
42
+
43
+ SitePrism.logger.warn("#{obj.class}##{name} should not start with no_")
44
+ SitePrism::Deprecator.deprecate('Using no_ prefix in DSL definition')
45
+ end
46
+
39
47
  # Sanitize method called before calling any SitePrism DSL method or
40
48
  # meta-programmed method. This ensures that the Capybara query is correct.
41
49
  #
@@ -49,7 +57,7 @@ module SitePrism
49
57
 
50
58
  recombine_args(find_args, runtime_args, options)
51
59
 
52
- return [*find_args, *runtime_args] if options.empty?
60
+ return [*find_args, *runtime_args, {}] if options.empty?
53
61
 
54
62
  [*find_args, *runtime_args, options]
55
63
  end
@@ -76,8 +84,10 @@ module SitePrism
76
84
  attr_reader :expected_items
77
85
 
78
86
  def element(name, *find_args)
87
+ SitePrism::Deprecator.deprecate('Passing a block to :element') if block_given?
79
88
  build(:element, name, *find_args) do
80
89
  define_method(name) do |*runtime_args, &element_block|
90
+ warn_if_dsl_collision(self, name)
81
91
  raise_if_block(self, name, !element_block.nil?, :element)
82
92
  _find(*merge_args(find_args, runtime_args))
83
93
  end
@@ -85,8 +95,10 @@ module SitePrism
85
95
  end
86
96
 
87
97
  def elements(name, *find_args)
98
+ SitePrism::Deprecator.deprecate('Passing a block to :elements') if block_given?
88
99
  build(:elements, name, *find_args) do
89
100
  define_method(name) do |*runtime_args, &element_block|
101
+ warn_if_dsl_collision(self, name)
90
102
  raise_if_block(self, name, !element_block.nil?, :elements)
91
103
  _all(*merge_args(find_args, runtime_args))
92
104
  end
@@ -101,6 +113,7 @@ module SitePrism
101
113
  section_class, find_args = extract_section_options(args, &block)
102
114
  build(:section, name, *find_args) do
103
115
  define_method(name) do |*runtime_args, &runtime_block|
116
+ warn_if_dsl_collision(self, name)
104
117
  section_element = _find(*merge_args(find_args, runtime_args))
105
118
  section_class.new(self, section_element, &runtime_block)
106
119
  end
@@ -120,6 +133,7 @@ module SitePrism
120
133
  end
121
134
 
122
135
  def iframe(name, klass, *args)
136
+ SitePrism.logger.debug('Block passed into iFrame construct at build time') if block_given?
123
137
  element_find_args = deduce_iframe_element_find_args(args)
124
138
  scope_find_args = deduce_iframe_scope_find_args(args)
125
139
  build(:iframe, name, *element_find_args) do
@@ -131,12 +145,35 @@ module SitePrism
131
145
  end
132
146
  end
133
147
 
134
- def mapped_items
135
- @mapped_items ||= []
148
+ def mapped_items(legacy: true)
149
+ if legacy
150
+ old_mapped_items
151
+ else
152
+ new_mapped_items
153
+ end
136
154
  end
137
155
 
138
156
  private
139
157
 
158
+ def old_mapped_items
159
+ SitePrism::Deprecator.soft_deprecate(
160
+ '.mapped_items on a class',
161
+ 'To allow easier recursion through the items in conjunction with #all_there?',
162
+ '.mapped_items(legacy: false)'
163
+ )
164
+ @old_mapped_items ||= []
165
+ end
166
+
167
+ def new_mapped_items
168
+ @new_mapped_items ||= {
169
+ element: [],
170
+ elements: [],
171
+ section: [],
172
+ sections: [],
173
+ iframe: [],
174
+ }
175
+ end
176
+
140
177
  def build(type, name, *find_args)
141
178
  if find_args.empty?
142
179
  create_error_method(name)
@@ -148,7 +185,8 @@ module SitePrism
148
185
  end
149
186
 
150
187
  def map_item(type, name)
151
- mapped_items << { type => name.to_sym }
188
+ old_mapped_items << { type => name }
189
+ new_mapped_items[type] << name.to_sym
152
190
  end
153
191
 
154
192
  def add_helper_methods(name, *find_args)
@@ -173,9 +211,7 @@ module SitePrism
173
211
 
174
212
  RSpec::Matchers.define "have_#{element_name}" do |*args|
175
213
  match { |actual| actual.public_send(matcher, *args) }
176
- match_when_negated do |actual|
177
- actual.public_send(negated_matcher, *args)
178
- end
214
+ match_when_negated { |actual| actual.public_send(negated_matcher, *args) }
179
215
  end
180
216
  end
181
217
 
@@ -224,7 +260,7 @@ module SitePrism
224
260
  end
225
261
 
226
262
  def create_error_method(name)
227
- SitePrism.logger.error("#{name} has come from an item with 0 locators.")
263
+ SitePrism.logger.error("#{name} has come from an item with no locators.")
228
264
  define_method(name) { raise SitePrism::InvalidElementError }
229
265
  end
230
266
 
@@ -250,7 +286,7 @@ module SitePrism
250
286
  return unless looks_like_xpath?(args[0])
251
287
 
252
288
  SitePrism.logger.warn('The arguments passed in look like xpath. Check your locators.')
253
- SitePrism.logger.debug("Default locator: #{Capybara.default_selector}")
289
+ SitePrism.logger.debug("Default locator strategy: #{Capybara.default_selector}")
254
290
  end
255
291
 
256
292
  def looks_like_xpath?(arg)
@@ -13,54 +13,59 @@ module SitePrism
13
13
  # @my_page.all_there?
14
14
  # => true - If the three items above are all present
15
15
  #
16
- # Note that #elements_to_check will affect the hash of mapped_items
16
+ # Note that #elements_to_check will check the hash of mapped_items
17
17
  #
18
- # When using the recursion parameter, one of three values is valid.
18
+ # When using the recursion parameter, one of two values is valid.
19
19
  #
20
20
  # Default: 'none' => Perform no recursion when calling #all_there?
21
- # Override: 'one' => Perform one recursive dive into all section
22
- # items and call #all_there? on those items too.
23
- def all_there?(recursion: 'none')
24
- SitePrism.logger.info('Setting for recursion is being ignored for now.')
25
-
26
- if %w[none one].include?(recursion)
27
- elements_to_check.all? { |item_name| there?(item_name) }
21
+ # Override: 'one' => Perform one recursive dive into all section/sections
22
+ # items and call #all_there? on all of those items too.
23
+ def all_there?(recursion: :none)
24
+ if recursion == :none
25
+ elements_to_check.all? { |name| there?(name) }
26
+ elsif recursion == :one
27
+ all_there_with_recursion
28
28
  else
29
- SitePrism.logger.error('Invalid recursion setting, Will not run.')
29
+ SitePrism.logger.debug("Input value '#{recursion}'. Valid values are :none or :one.")
30
+ SitePrism.logger.error('Invalid recursion setting, Will not run #all_there?.')
30
31
  end
31
32
  end
32
33
 
33
34
  def elements_present
34
- _mapped_items.select { |item_name| there?(item_name) }
35
+ _mapped_items.select { |name| there?(name) }
35
36
  end
36
37
 
37
38
  private
38
39
 
39
- # If the page or section has expected_items set, return expected_items
40
- # that are mapped; otherwise just return the list of all mapped_items
40
+ def all_there_with_recursion
41
+ if SitePrism.use_all_there_gem
42
+ SitePrism::AllThere::RecursionChecker.new(self).all_there?
43
+ else
44
+ RecursionChecker.new(self).all_there?
45
+ end
46
+ end
47
+
48
+ # If the page or section has expected_items set, return expected_items that are mapped
49
+ # otherwise just return the list of all mapped_items
41
50
  def elements_to_check
42
51
  if _expected_items
43
52
  SitePrism.logger.debug('Expected Items has been set.')
44
- _mapped_items.select { |item_name| _expected_items.include?(item_name) }
53
+ _mapped_items.select { |name| _expected_items.include?(name) }
45
54
  else
46
55
  _mapped_items
47
56
  end
48
57
  end
49
58
 
50
59
  def _mapped_items
51
- mapped_items_list.map(&:values).flatten
52
- end
53
-
54
- def mapped_items_list
55
- self.class.mapped_items.uniq
60
+ self.class.mapped_items(legacy: false).values.flatten.uniq
56
61
  end
57
62
 
58
63
  def _expected_items
59
64
  self.class.expected_items
60
65
  end
61
66
 
62
- def there?(item_name)
63
- send("has_#{item_name}?")
67
+ def there?(name)
68
+ send("has_#{name}?")
64
69
  end
65
70
  end
66
71
  end
@@ -3,7 +3,6 @@
3
3
  require 'site_prism/loadable'
4
4
 
5
5
  module SitePrism
6
- # rubocop:disable Metrics/ClassLength
7
6
  class Page
8
7
  include Capybara::DSL
9
8
  include ElementChecker
@@ -104,19 +103,23 @@ module SitePrism
104
103
  private
105
104
 
106
105
  def _find(*find_args)
107
- page.find(*find_args)
106
+ kwargs = find_args.pop
107
+ page.find(*find_args, **kwargs)
108
108
  end
109
109
 
110
110
  def _all(*find_args)
111
- page.all(*find_args)
111
+ kwargs = find_args.pop
112
+ page.all(*find_args, **kwargs)
112
113
  end
113
114
 
114
115
  def element_exists?(*find_args)
115
- page.has_selector?(*find_args)
116
+ kwargs = find_args.pop
117
+ page.has_selector?(*find_args, **kwargs)
116
118
  end
117
119
 
118
120
  def element_does_not_exist?(*find_args)
119
- page.has_no_selector?(*find_args)
121
+ kwargs = find_args.pop
122
+ page.has_no_selector?(*find_args, **kwargs)
120
123
  end
121
124
 
122
125
  def regexp_backed_matches
@@ -167,5 +170,4 @@ module SitePrism
167
170
  end
168
171
  end
169
172
  end
170
- # rubocop:enable Metrics/ClassLength
171
173
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SitePrism
4
+ class RecursionChecker
5
+ attr_reader :instance
6
+ private :instance
7
+
8
+ def initialize(instance)
9
+ @instance = instance
10
+ end
11
+
12
+ def all_there?
13
+ regular_items_all_there = expected_item_map.flatten.all? { |name| there?(name) }
14
+ return false unless regular_items_all_there
15
+
16
+ section_all_there =
17
+ section_classes_to_check.all?(&:all_there?)
18
+ return false unless section_all_there
19
+
20
+ # Returning this final check here is fine, as the previous two checks must
21
+ # have returned +true+ in order to hit this part of the method-call
22
+ sections_classes_to_check.all?(&:all_there?)
23
+ end
24
+
25
+ def expected_item_map
26
+ [
27
+ expected(mapped_items, :element),
28
+ expected(mapped_items, :elements),
29
+ expected(mapped_items, :section),
30
+ expected(mapped_items, :sections),
31
+ expected(mapped_items, :iframe),
32
+ ]
33
+ end
34
+
35
+ def expected(_map, type)
36
+ mapped_items[type].select { |name| elements_to_check.include?(name) }
37
+ end
38
+
39
+ def section_classes_to_check
40
+ expected_item_map[2].map { |name| instance.send(name) }
41
+ end
42
+
43
+ def sections_classes_to_check
44
+ expected_item_map[3].map { |name| instance.send(name) }.flatten
45
+ end
46
+
47
+ private
48
+
49
+ # If the page or section has expected_items set, return expected_items that are mapped
50
+ # otherwise just return the list of all mapped_items
51
+ def elements_to_check
52
+ if _expected_items
53
+ SitePrism.logger.debug('Expected Items has been set.')
54
+ _mapped_items.select { |name| _expected_items.include?(name) }
55
+ else
56
+ _mapped_items
57
+ end
58
+ end
59
+
60
+ def _mapped_items
61
+ mapped_items.values.flatten.uniq
62
+ end
63
+
64
+ def _expected_items
65
+ instance.class.expected_items
66
+ end
67
+
68
+ def there?(name)
69
+ instance.send("has_#{name}?")
70
+ end
71
+
72
+ def mapped_items
73
+ @mapped_items ||= instance.class.mapped_items(legacy: false)
74
+ end
75
+ end
76
+ end
@@ -25,10 +25,14 @@ module SitePrism
25
25
  nil
26
26
  end
27
27
 
28
- def initialize(parent, root_element)
28
+ def initialize(parent, root_element, &block)
29
29
  @parent = parent
30
30
  @root_element = root_element
31
- Capybara.within(@root_element) { yield(self) } if block_given?
31
+ within(&block) if block_given?
32
+ end
33
+
34
+ def within
35
+ Capybara.within(@root_element) { yield(self) }
32
36
  end
33
37
 
34
38
  # Capybara::DSL module "delegates" Capybara methods to the "page" method
@@ -68,19 +72,23 @@ module SitePrism
68
72
  private
69
73
 
70
74
  def _find(*find_args)
71
- page.find(*find_args)
75
+ kwargs = find_args.pop
76
+ page.find(*find_args, **kwargs)
72
77
  end
73
78
 
74
79
  def _all(*find_args)
75
- page.all(*find_args)
80
+ kwargs = find_args.pop
81
+ page.all(*find_args, **kwargs)
76
82
  end
77
83
 
78
84
  def element_exists?(*find_args)
79
- page.has_selector?(*find_args)
85
+ kwargs = find_args.pop
86
+ page.has_selector?(*find_args, **kwargs)
80
87
  end
81
88
 
82
89
  def element_does_not_exist?(*find_args)
83
- page.has_no_selector?(*find_args)
90
+ kwargs = find_args.pop
91
+ page.has_no_selector?(*find_args, **kwargs)
84
92
  end
85
93
  end
86
94
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
- VERSION = '3.2'
4
+ VERSION = '3.5'
5
5
  end
@@ -26,7 +26,7 @@ module SitePrism
26
26
  raise(
27
27
  SitePrism::FrozenInTimeError,
28
28
  'Time appears to be frozen. For more info, see ' \
29
- 'https://github.com/natritmeyer/site_prism/blob/master/lib/site_prism/error.rb'
29
+ 'https://github.com/site-prism/site_prism/blob/master/lib/site_prism/error.rb'
30
30
  )
31
31
  end
32
32
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: site_prism
3
3
  version: !ruby/object:Gem::Version
4
- version: '3.2'
4
+ version: '3.5'
5
5
  platform: ruby
6
6
  authors:
7
- - Nat Ritmeyer
8
7
  - Luke Hill
8
+ - Nat Ritmeyer
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-05-14 00:00:00.000000000 Z
12
+ date: 2020-06-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -29,16 +29,36 @@ dependencies:
29
29
  name: capybara
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - "<="
33
33
  - !ruby/object:Gem::Version
34
- version: '3.2'
34
+ version: '3.29'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - "<="
40
+ - !ruby/object:Gem::Version
41
+ version: '3.29'
42
+ - !ruby/object:Gem::Dependency
43
+ name: site_prism-all_there
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
40
47
  - !ruby/object:Gem::Version
41
- version: '3.2'
48
+ version: 0.3.1
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '1.0'
52
+ type: :runtime
53
+ prerelease: false
54
+ version_requirements: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 0.3.1
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
42
62
  - !ruby/object:Gem::Dependency
43
63
  name: cucumber
44
64
  requirement: !ruby/object:Gem::Requirement
@@ -54,31 +74,31 @@ dependencies:
54
74
  - !ruby/object:Gem::Version
55
75
  version: '3.1'
56
76
  - !ruby/object:Gem::Dependency
57
- name: dotenv
77
+ name: pry-byebug
58
78
  requirement: !ruby/object:Gem::Requirement
59
79
  requirements:
60
- - - "~>"
80
+ - - ">="
61
81
  - !ruby/object:Gem::Version
62
- version: '2.6'
82
+ version: '0'
63
83
  type: :development
64
84
  prerelease: false
65
85
  version_requirements: !ruby/object:Gem::Requirement
66
86
  requirements:
67
- - - "~>"
87
+ - - ">="
68
88
  - !ruby/object:Gem::Version
69
- version: '2.6'
89
+ version: '0'
70
90
  - !ruby/object:Gem::Dependency
71
91
  name: rake
72
92
  requirement: !ruby/object:Gem::Requirement
73
93
  requirements:
74
- - - "~>"
94
+ - - ">="
75
95
  - !ruby/object:Gem::Version
76
96
  version: '12.3'
77
97
  type: :development
78
98
  prerelease: false
79
99
  version_requirements: !ruby/object:Gem::Requirement
80
100
  requirements:
81
- - - "~>"
101
+ - - ">="
82
102
  - !ruby/object:Gem::Version
83
103
  version: '12.3'
84
104
  - !ruby/object:Gem::Dependency
@@ -101,28 +121,42 @@ dependencies:
101
121
  requirements:
102
122
  - - "~>"
103
123
  - !ruby/object:Gem::Version
104
- version: 0.67.0
124
+ version: 0.75.0
105
125
  type: :development
106
126
  prerelease: false
107
127
  version_requirements: !ruby/object:Gem::Requirement
108
128
  requirements:
109
129
  - - "~>"
110
130
  - !ruby/object:Gem::Version
111
- version: 0.67.0
131
+ version: 0.75.0
112
132
  - !ruby/object:Gem::Dependency
113
133
  name: rubocop-performance
114
134
  requirement: !ruby/object:Gem::Requirement
115
135
  requirements:
116
136
  - - "~>"
117
137
  - !ruby/object:Gem::Version
118
- version: 1.0.0
138
+ version: 1.5.1
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.5.1
146
+ - !ruby/object:Gem::Dependency
147
+ name: rubocop-rspec
148
+ requirement: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 1.33.0
119
153
  type: :development
120
154
  prerelease: false
121
155
  version_requirements: !ruby/object:Gem::Requirement
122
156
  requirements:
123
157
  - - "~>"
124
158
  - !ruby/object:Gem::Version
125
- version: 1.0.0
159
+ version: 1.33.0
126
160
  - !ruby/object:Gem::Dependency
127
161
  name: selenium-webdriver
128
162
  requirement: !ruby/object:Gem::Requirement
@@ -143,35 +177,33 @@ dependencies:
143
177
  requirements:
144
178
  - - "~>"
145
179
  - !ruby/object:Gem::Version
146
- version: '0.16'
180
+ version: '0.17'
147
181
  type: :development
148
182
  prerelease: false
149
183
  version_requirements: !ruby/object:Gem::Requirement
150
184
  requirements:
151
185
  - - "~>"
152
186
  - !ruby/object:Gem::Version
153
- version: '0.16'
187
+ version: '0.17'
154
188
  - !ruby/object:Gem::Dependency
155
189
  name: webdrivers
156
190
  requirement: !ruby/object:Gem::Requirement
157
191
  requirements:
158
192
  - - "~>"
159
193
  - !ruby/object:Gem::Version
160
- version: 3.9.1
194
+ version: '4.0'
161
195
  type: :development
162
196
  prerelease: false
163
197
  version_requirements: !ruby/object:Gem::Requirement
164
198
  requirements:
165
199
  - - "~>"
166
200
  - !ruby/object:Gem::Version
167
- version: 3.9.1
168
- description: |-
169
- SitePrism gives you a simple,
170
- clean and semantic DSL for describing your site.
171
- SitePrism implements the Page Object Model pattern on top of Capybara.
201
+ version: '4.0'
202
+ description: SitePrism gives you a simple, clean and semantic DSL for describing your
203
+ site. SitePrism implements the Page Object Model pattern on top of Capybara.
172
204
  email:
173
- - nat@natontesting.com
174
205
  - lukehill_uk@hotmail.com
206
+ - nat@natontesting.com
175
207
  executables: []
176
208
  extensions: []
177
209
  extra_rdoc_files: []
@@ -180,22 +212,24 @@ files:
180
212
  - README.md
181
213
  - lib/site_prism.rb
182
214
  - lib/site_prism/addressable_url_matcher.rb
215
+ - lib/site_prism/deprecator.rb
183
216
  - lib/site_prism/dsl.rb
184
217
  - lib/site_prism/element_checker.rb
185
218
  - lib/site_prism/error.rb
186
219
  - lib/site_prism/loadable.rb
187
220
  - lib/site_prism/logger.rb
188
221
  - lib/site_prism/page.rb
222
+ - lib/site_prism/recursion_checker.rb
189
223
  - lib/site_prism/section.rb
190
224
  - lib/site_prism/version.rb
191
225
  - lib/site_prism/waiter.rb
192
- homepage: https://github.com/natritmeyer/site_prism
226
+ homepage: https://github.com/site-prism/site_prism
193
227
  licenses:
194
228
  - BSD-3-Clause
195
229
  metadata:
196
- bug_tracker_uri: https://github.com/natritmeyer/site_prism/issues
197
- changelog_uri: https://github.com/natritmeyer/site_prism/blob/master/CHANGELOG.md
198
- source_code_uri: https://github.com/natritmeyer/site_prism
230
+ bug_tracker_uri: https://github.com/site-prism/site_prism/issues
231
+ changelog_uri: https://github.com/site-prism/site_prism/blob/master/CHANGELOG.md
232
+ source_code_uri: https://github.com/site-prism/site_prism
199
233
  post_install_message:
200
234
  rdoc_options: []
201
235
  require_paths:
@@ -211,8 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
245
  - !ruby/object:Gem::Version
212
246
  version: '0'
213
247
  requirements: []
214
- rubyforge_project:
215
- rubygems_version: 2.7.8
248
+ rubygems_version: 3.0.6
216
249
  signing_key:
217
250
  specification_version: 4
218
251
  summary: A Page Object Model DSL for Capybara