site_prism 3.4 → 3.7

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: c80d215b3527e90d15660f863dcb13b251e10f465dfc0ef47c344ebf6ea4b54b
4
- data.tar.gz: 04cf863dcd21233726aea475e4eefc676c7d387717c29e9dda68ede2113b7319
3
+ metadata.gz: adf8cf393fc3ad828528159a54048e54c3c396f3743c79b10a75ea313ddd135c
4
+ data.tar.gz: f2fb2ecb2f8942e3e59228994da32262a65b14a2c49f573468100f1aca799061
5
5
  SHA512:
6
- metadata.gz: 9a53a48fd0f06f6ee754b9d78e27251a9768c9e227c6970807c85aefbc4e3a1f2d36fe90baa4d01867cef1f7a446ccc7d97177865a5e5da4760a5d75428338fe
7
- data.tar.gz: 9c88141815dfc9b5e3299efa204d9bead7ecf89c91a58a66fdacc3544abca17afd65c265a8d0a484d4d90122835317449cd8d9bf875b594085244449989dfc73
6
+ metadata.gz: aecf017750d915a617052242d8959af91ec1b154e5d394f2fa7df096649cf198052ecdf25cef22476f88682c45d71ff6c49c39262726d7d75ea33d07b751f47b
7
+ data.tar.gz: e2ed8f07246c08e910fd870ecc9140f813619109b107ae6448d59f98176b84b6f50c58cc8609615e68f5ddd0e09076b3b30f906fe0647994d78ec4df7b2d1941
data/README.md CHANGED
@@ -7,7 +7,7 @@ _A Page Object Model DSL for Capybara_
7
7
  SitePrism gives you a simple, clean and semantic DSL for describing your site using the Page Object Model pattern,
8
8
  for use with Capybara in automated acceptance testing.
9
9
 
10
- Find the pretty documentation here: http://rdoc.info/gems/site_prism/frames
10
+ Find the pretty documentation here: https://rdoc.info/gems/site_prism/frames
11
11
 
12
12
  Make sure to add your project/company to https://github.com/site-prism/site_prism/wiki/Who-is-using-SitePrism
13
13
 
@@ -15,15 +15,15 @@ Make sure to add your project/company to https://github.com/site-prism/site_pris
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/site-prism/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
- SitePrism should run on all major browsers. The gem's integration tests are ran on Chrome and Firefox.
26
+ SitePrism should run on all major browsers. The gem's integration tests are run on Chrome and Firefox.
27
27
 
28
28
  If you find you cannot integrate nicely with SitePrism, please open an
29
29
  [issue request](https://github.com/site-prism/site_prism/issues/new)
@@ -124,6 +124,7 @@ 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
127
128
  ```
128
129
 
129
130
  The driver creation is identical to how you would normally create a Capybara driver,
@@ -135,6 +136,7 @@ Capybara.register_driver :site_prism do |app|
135
136
  Capybara::Selenium::Driver.new(app, browser: browser, desired_capabilities: capabilities)
136
137
  end
137
138
 
139
+ # Then tell Capybara to use the Driver you've just defined as its default driver
138
140
  Capybara.configure do |config|
139
141
  config.default_driver = :site_prism
140
142
  end
@@ -149,6 +151,7 @@ require 'capybara'
149
151
  require 'capybara/rspec'
150
152
  require 'selenium-webdriver'
151
153
  require 'site_prism'
154
+ require 'site_prism/all_there' # Optional but needed to perform more complex matching
152
155
  ```
153
156
 
154
157
  And again, as above, a sample driver is no different to a normal driver instantiation in Capybara.
@@ -295,7 +298,13 @@ expect(@account_page).to be_displayed
295
298
  ```
296
299
 
297
300
  Calling `#displayed?` will return true if the browser's current URL
298
- matches the page's template and false if it doesn't.
301
+ matches the page's template and false if it doesn't. It will wait for
302
+ `Capybara.default_max_wait_time` seconds or you can pass an explicit
303
+ wait time in seconds as the first argument like this:
304
+
305
+ ```ruby
306
+ @account_page.displayed?(10) # wait up to 10 seconds for display
307
+ ```
299
308
 
300
309
  #### Specifying parameter values for templated URLs
301
310
 
@@ -422,8 +431,11 @@ as a string.
422
431
  #### Accessing the individual element
423
432
 
424
433
  The `element` method will add a number of methods to instances of the
425
- particular Page class. The first method to be added is the name of the
426
- element. So using the following example:
434
+ particular Page class. The first method added is the name of the
435
+ element. It finds the element using [Capybara::Node::Finders#find](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders#find-instance_method)
436
+ returning a [Capybara::Node::Element](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Element) or
437
+ raising [Capybara::ElementNotFound](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/ElementNotFound)
438
+ if the element can not be found.
427
439
 
428
440
  ```ruby
429
441
  class Home < SitePrism::Page
@@ -447,7 +459,9 @@ end
447
459
  #### Testing for the existence of the element
448
460
 
449
461
  Another method added to the Page class by the `element` method is the
450
- `has_<element_name>?` method. Using the same example as above:
462
+ `has_<element_name>?` method.
463
+ This method delegates to [Capybara::Node::Matchers#has_selector?](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Matchers#has_selector%3F-instance_method).
464
+ Using the same example as above:
451
465
 
452
466
  ```ruby
453
467
  class Home < SitePrism::Page
@@ -477,7 +491,9 @@ end
477
491
 
478
492
  To test that an element does not exist on the page, it is not possible to just call
479
493
  `#not_to have_search_field`. SitePrism supplies the `#has_no_<element>?` method
480
- that should be used to test for non-existence. Using the above example:
494
+ that should be used to test for non-existence.
495
+ This method delegates to [Capybara::Node::Matchers#has_no_selector?](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Matchers#has_no_selector%3F-instance_method)
496
+ Using the above example:
481
497
 
482
498
  ```ruby
483
499
  @home = Home.new
@@ -495,9 +511,10 @@ end
495
511
 
496
512
  #### Waiting for an element to become visible
497
513
 
498
- A method that gets added by calling `element` is the
499
- `wait_until_<element_name>_visible` method. Calling this method will
500
- cause the test to wait for Capybara's default wait time for the element
514
+ A method that gets added by calling `element` is the
515
+ `wait_until_<element_name>_visible` method.
516
+ This method delegates to [Capybara::Node::Matchers#has_selector?](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Matchers#has_selector%3F-instance_method).
517
+ Calling this method will cause the test to wait for Capybara's default wait time for the element
501
518
  to become visible. You can customise the wait time by supplying a number
502
519
  of seconds to wait in-line or configuring the default wait time.
503
520
 
@@ -510,10 +527,11 @@ of seconds to wait in-line or configuring the default wait time.
510
527
  #### Waiting for an element to become invisible
511
528
 
512
529
  Another method added by calling `element` is the
513
- `wait_until_<element_name>_invisible` method. Calling this method will
514
- cause the test to wait for Capybara's default wait time for the element
515
- to become invisible. You can as with the visibility waiter, customise
516
- the wait time in the same way.
530
+ `wait_until_<element_name>_invisible` method.
531
+ This method delegates to [Capybara::Node::Matchers#has_no_selector?](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Matchers#has_no_selector%3F-instance_method).
532
+ Calling this method will cause the test to wait for Capybara's default
533
+ wait time for the element to become invisible. You can as with the visibility
534
+ waiter, customise the wait time in the same way.
517
535
 
518
536
  ```ruby
519
537
  @home.wait_until_search_field_invisible
@@ -717,8 +735,8 @@ through them to find out if all of your items are present then you can also do t
717
735
  Simply pass a recursion parameter to the `#all_there?` check. Note that the only valid values
718
736
  for this at the moment are `:none` and `:one`
719
737
 
720
- Passing `:none` in (default), will not change the functionality. However passing in `:one` will cause
721
- site_prism to recurse through all section / sections items defined in your current scope.
738
+ Passing `:none` (default), will not change the functionality. However passing in `:one` will cause
739
+ `site_prism` to recurse through all `section` / `sections` items defined in your present scope.
722
740
 
723
741
  Work alongside developing this functionality further is being continued in the
724
742
  [site_prism-all_there](http://www.github.com/site-prism/site_prism-all_there) repo. So head on over
@@ -727,11 +745,33 @@ there if you're interested in how this feature will work going forwards
727
745
  NB: At the moment a "primitive" but working copy of this is hosted inside this gem. But if you wish to
728
746
  use the bleeding edge version of the logic. Then simply set the following configuration parameter
729
747
 
730
- ```rb
748
+ ```ruby
749
+ `require 'site_prism/all_there'`
750
+
731
751
  SitePrism.use_all_there_gem = true
732
752
  ```
733
753
 
734
- Make sure as well to require the gem code by doing `require 'site_prism/all_there'`
754
+ ### Getting the list of missing elements
755
+
756
+ If `#all_there?` returns false and you wish to get the list of missing elements for debugging purposes
757
+ you may want to use `#elements_missing` method. It will return all missing elements from the expected_elements list
758
+
759
+ If you do not provide a list of `expected_elements` this method will return all elements that are missing on the page;
760
+ from those which are defined.
761
+
762
+ ```ruby
763
+ class Home < SitePrism::Page
764
+ element :name, '#name'
765
+ element :address, '#address'
766
+ element :success_message, 'span.alert-success'
767
+
768
+ expected_elements :name, :address
769
+ end
770
+
771
+ # and... Only `address` is on the page
772
+
773
+ @test_page.elements_missing #=> [:name]
774
+ ```
735
775
 
736
776
  ## Sections
737
777
 
@@ -918,14 +958,13 @@ end
918
958
 
919
959
  ##### Accessing section elements using a block
920
960
 
921
- A Section can be scoped so it is only accessible inside a block. This is
961
+ You can execute a block within the context of a Section. This is
922
962
  similar to Capybara's `within` method and allows for shorter test code
923
- particularly with nested sections. Some of this test code can be
924
- made a little prettier by simply passing a block in.
963
+ particularly with nested sections. Test code that might have to repeat the block name can be shortened up this way.
925
964
 
926
965
  ```ruby
927
966
  Then(/^the home page menu contains a link to the various search functions$/) do
928
- @home.menu do |menu|
967
+ @home.menu.within do |menu|
929
968
  expect(menu).to have_search
930
969
  expect(menu.search['href']).to include('google.com')
931
970
  expect(menu).to have_images
@@ -934,6 +973,16 @@ Then(/^the home page menu contains a link to the various search functions$/) do
934
973
  end
935
974
  ```
936
975
 
976
+ 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.
977
+
978
+ ```ruby
979
+ Then(/^the home page menu contains a link to the various search functions$/) do
980
+ @home.menu do |menu| # possible, but prefer: `@home.menu.within`
981
+ expect(menu).to have_search
982
+ end
983
+ end
984
+ ```
985
+
937
986
  #### Getting a section's parent
938
987
 
939
988
  It is possible to ask a section for its parent (page, or section if this
@@ -1172,7 +1221,7 @@ This allows for pretty tests ...
1172
1221
  ```ruby
1173
1222
  Then(/^there are lots of search_results$/) do
1174
1223
  expect(@results_page.search_results.size).to eq(10)
1175
-
1224
+
1176
1225
  @home.search_results.each do |result|
1177
1226
  expect(result).to have_title
1178
1227
  expect(result.blurb.text).not_to be_empty
@@ -1188,6 +1237,26 @@ element. So if the css selector finds 3 `li` elements, calling
1188
1237
  `search_results` will return an array containing 3 instances of
1189
1238
  `SearchResults`, each with one of the `li` elements as it's root element.
1190
1239
 
1240
+ ##### Accessing Within a Collection of Sections
1241
+
1242
+ 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:
1243
+
1244
+ ```rb
1245
+ @home.search_results.first do |result|
1246
+ # This block is silently ignored.
1247
+ expect(result).to have_title
1248
+ end
1249
+ ```
1250
+ Instead use `within` to access the inner-context of the Section.
1251
+
1252
+ ```rb
1253
+ @home.search_results.first.within do |result|
1254
+ # This block is run within the context of the Section.
1255
+ expect(result).to have_title
1256
+ end
1257
+ ```
1258
+
1259
+
1191
1260
  #### Anonymous Section Collections
1192
1261
 
1193
1262
  You can define collections of anonymous sections the same way you would
@@ -1384,7 +1453,7 @@ instance of the class when created.
1384
1453
 
1385
1454
  ### Skipping load Validations
1386
1455
 
1387
- Defined load validations can be skipped for one `load` call by
1456
+ Defined load validations can be skipped for one `load` call by
1388
1457
  passing in `with_validations: false`.
1389
1458
 
1390
1459
  ```ruby
@@ -1651,12 +1720,12 @@ as per the code below
1651
1720
  Capybara.configure do |config|
1652
1721
  config.default_max_wait_time = 11 #=> Wait up to 11 seconds for all queries to fail
1653
1722
  # or if you don't want to ever wait
1654
- config.default_max_wait_time = 0 #=> Don't ever wait!
1723
+ config.default_max_wait_time = 0 #=> Don't ever wait!
1655
1724
  end
1656
1725
  ```
1657
1726
 
1658
1727
  Note that even with implicit waits on you can dynamically modify the wait times
1659
- in any SitePrism method to help work-around special circumstances.
1728
+ in any SitePrism method to help work-around special circumstances.
1660
1729
 
1661
1730
  ```ruby
1662
1731
  # Option 1: using wait key assignment
@@ -5,13 +5,16 @@ require 'addressable/template'
5
5
 
6
6
  module SitePrism
7
7
  autoload :AddressableUrlMatcher, 'site_prism/addressable_url_matcher'
8
- autoload :Deprecator, 'site_prism/deprecator'
9
8
  autoload :DSL, 'site_prism/dsl'
9
+ autoload :Deprecator, 'site_prism/deprecator'
10
10
  autoload :ElementChecker, 'site_prism/element_checker'
11
- autoload :RecursionChecker, 'site_prism/recursion_checker'
11
+ autoload :Loadable, 'site_prism/loadable'
12
12
  autoload :Logger, 'site_prism/logger'
13
13
  autoload :Page, 'site_prism/page'
14
+ autoload :RecursionChecker, 'site_prism/recursion_checker'
15
+ autoload :RspecMatchers, 'site_prism/rspec_matchers'
14
16
  autoload :Section, 'site_prism/section'
17
+ autoload :Timer, 'site_prism/timer'
15
18
  autoload :Waiter, 'site_prism/waiter'
16
19
 
17
20
  class << self
@@ -8,6 +8,30 @@ module SitePrism
8
8
 
9
9
  private
10
10
 
11
+ # Call `find` inside context set on page/section
12
+ def _find(*find_args)
13
+ kwargs = find_args.pop
14
+ page.find(*find_args, **kwargs)
15
+ end
16
+
17
+ # Call `all` inside context set on page/section
18
+ def _all(*find_args)
19
+ kwargs = find_args.pop
20
+ page.all(*find_args, **kwargs)
21
+ end
22
+
23
+ # Call `has_selector?` inside context set on page/section
24
+ def element_exists?(*find_args)
25
+ kwargs = find_args.pop
26
+ page.has_selector?(*find_args, **kwargs)
27
+ end
28
+
29
+ # Call `has_no_selector?` inside context set on page/section
30
+ def element_does_not_exist?(*find_args)
31
+ kwargs = find_args.pop
32
+ page.has_no_selector?(*find_args, **kwargs)
33
+ end
34
+
11
35
  # The default waiting time set by Capybara's configuration settings.
12
36
  def wait_time
13
37
  Capybara.default_max_wait_time
@@ -36,6 +60,14 @@ module SitePrism
36
60
  raise SitePrism::UnsupportedBlockError
37
61
  end
38
62
 
63
+ # Warn users from naming the elements starting with no_
64
+ def warn_if_dsl_collision(obj, name)
65
+ return unless name.to_s.start_with?('no_')
66
+
67
+ SitePrism.logger.warn("#{obj.class}##{name} should not start with no_")
68
+ SitePrism::Deprecator.deprecate('Using no_ prefix in DSL definition')
69
+ end
70
+
39
71
  # Sanitize method called before calling any SitePrism DSL method or
40
72
  # meta-programmed method. This ensures that the Capybara query is correct.
41
73
  #
@@ -49,7 +81,7 @@ module SitePrism
49
81
 
50
82
  recombine_args(find_args, runtime_args, options)
51
83
 
52
- return [*find_args, *runtime_args] if options.empty?
84
+ return [*find_args, *runtime_args, {}] if options.empty?
53
85
 
54
86
  [*find_args, *runtime_args, options]
55
87
  end
@@ -79,6 +111,7 @@ module SitePrism
79
111
  SitePrism::Deprecator.deprecate('Passing a block to :element') if block_given?
80
112
  build(:element, name, *find_args) do
81
113
  define_method(name) do |*runtime_args, &element_block|
114
+ warn_if_dsl_collision(self, name)
82
115
  raise_if_block(self, name, !element_block.nil?, :element)
83
116
  _find(*merge_args(find_args, runtime_args))
84
117
  end
@@ -89,6 +122,7 @@ module SitePrism
89
122
  SitePrism::Deprecator.deprecate('Passing a block to :elements') if block_given?
90
123
  build(:elements, name, *find_args) do
91
124
  define_method(name) do |*runtime_args, &element_block|
125
+ warn_if_dsl_collision(self, name)
92
126
  raise_if_block(self, name, !element_block.nil?, :elements)
93
127
  _all(*merge_args(find_args, runtime_args))
94
128
  end
@@ -103,6 +137,7 @@ module SitePrism
103
137
  section_class, find_args = extract_section_options(args, &block)
104
138
  build(:section, name, *find_args) do
105
139
  define_method(name) do |*runtime_args, &runtime_block|
140
+ warn_if_dsl_collision(self, name)
106
141
  section_element = _find(*merge_args(find_args, runtime_args))
107
142
  section_class.new(self, section_element, &runtime_block)
108
143
  end
@@ -159,7 +194,7 @@ module SitePrism
159
194
  elements: [],
160
195
  section: [],
161
196
  sections: [],
162
- iframe: [],
197
+ iframe: []
163
198
  }
164
199
  end
165
200
 
@@ -181,7 +216,7 @@ module SitePrism
181
216
  def add_helper_methods(name, *find_args)
182
217
  create_existence_checker(name, *find_args)
183
218
  create_nonexistence_checker(name, *find_args)
184
- create_rspec_existence_matchers(name) if defined?(RSpec)
219
+ SitePrism::RspecMatchers.new(name)._create_rspec_existence_matchers if defined?(RSpec)
185
220
  create_visibility_waiter(name, *find_args)
186
221
  create_invisibility_waiter(name, *find_args)
187
222
  end
@@ -194,16 +229,6 @@ module SitePrism
194
229
  end
195
230
  end
196
231
 
197
- def create_rspec_existence_matchers(element_name)
198
- matcher = "has_#{element_name}?"
199
- negated_matcher = "has_no_#{element_name}?"
200
-
201
- RSpec::Matchers.define "have_#{element_name}" do |*args|
202
- match { |actual| actual.public_send(matcher, *args) }
203
- match_when_negated { |actual| actual.public_send(negated_matcher, *args) }
204
- end
205
- end
206
-
207
232
  def create_existence_checker(element_name, *find_args)
208
233
  method_name = "has_#{element_name}?"
209
234
  create_helper_method(method_name, *find_args) do
@@ -35,6 +35,10 @@ module SitePrism
35
35
  _mapped_items.select { |name| there?(name) }
36
36
  end
37
37
 
38
+ def elements_missing
39
+ elements_to_check.reject { |name| there?(name) }
40
+ end
41
+
38
42
  private
39
43
 
40
44
  def all_there_with_recursion
@@ -25,14 +25,6 @@ module SitePrism
25
25
  # Formerly known as `NoSelectorForElement`
26
26
  class InvalidElementError < SitePrismError; end
27
27
 
28
- # A tool like Timecop is being used to "freeze time" by overriding Time.now
29
- # and similar methods. In this case, our waiter functions won't work, because
30
- # Time.now does not change.
31
- # If you encounter this issue, check that you are not doing Timecop.freeze without
32
- # an accompanying Timecop.return.
33
- # Also check out Timecop.safe_mode https://github.com/travisjeffery/timecop#timecopsafe_mode
34
- class FrozenInTimeError < SitePrismError; end
35
-
36
28
  # The condition that was being evaluated inside the block did not evaluate
37
29
  # to true within the time limit
38
30
  # Formerly known as `TimeoutException`
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'site_prism/loadable'
4
-
5
3
  module SitePrism
6
- # rubocop:disable Metrics/ClassLength
7
4
  class Page
8
5
  include Capybara::DSL
9
6
  include ElementChecker
@@ -27,11 +24,7 @@ module SitePrism
27
24
  end
28
25
 
29
26
  def page
30
- if defined?(@page)
31
- @page
32
- else
33
- Capybara.current_session
34
- end
27
+ (defined?(@page) && @page) || Capybara.current_session
35
28
  end
36
29
 
37
30
  # Loads the page.
@@ -79,18 +72,13 @@ module SitePrism
79
72
 
80
73
  def url_matches(seconds = wait_time)
81
74
  return unless displayed?(seconds)
75
+ return regexp_backed_matches if url_matcher.is_a?(Regexp)
82
76
 
83
- if url_matcher.is_a?(Regexp)
84
- regexp_backed_matches
85
- else
86
- template_backed_matches
87
- end
77
+ template_backed_matches
88
78
  end
89
79
 
90
80
  def url(expansion = {})
91
- return nil if self.class.url.nil?
92
-
93
- Addressable::Template.new(self.class.url).expand(expansion).to_s
81
+ self.class.url && Addressable::Template.new(self.class.url).expand(expansion).to_s
94
82
  end
95
83
 
96
84
  def url_matcher
@@ -103,22 +91,6 @@ module SitePrism
103
91
 
104
92
  private
105
93
 
106
- def _find(*find_args)
107
- page.find(*find_args)
108
- end
109
-
110
- def _all(*find_args)
111
- page.all(*find_args)
112
- end
113
-
114
- def element_exists?(*find_args)
115
- page.has_selector?(*find_args)
116
- end
117
-
118
- def element_does_not_exist?(*find_args)
119
- page.has_no_selector?(*find_args)
120
- end
121
-
122
94
  def regexp_backed_matches
123
95
  url_matcher.match(page.current_url)
124
96
  end
@@ -167,5 +139,4 @@ module SitePrism
167
139
  end
168
140
  end
169
141
  end
170
- # rubocop:enable Metrics/ClassLength
171
142
  end
@@ -3,6 +3,7 @@
3
3
  module SitePrism
4
4
  class RecursionChecker
5
5
  attr_reader :instance
6
+
6
7
  private :instance
7
8
 
8
9
  def initialize(instance)
@@ -28,7 +29,7 @@ module SitePrism
28
29
  expected(mapped_items, :elements),
29
30
  expected(mapped_items, :section),
30
31
  expected(mapped_items, :sections),
31
- expected(mapped_items, :iframe),
32
+ expected(mapped_items, :iframe)
32
33
  ]
33
34
  end
34
35
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SitePrism
4
+ class RspecMatchers
5
+ attr_reader :element_name
6
+
7
+ def initialize(element_name)
8
+ @element_name = element_name
9
+ end
10
+
11
+ def _create_rspec_existence_matchers
12
+ SitePrism.logger.debug('Including all relevant matcher names / warnings in RSpec scope.')
13
+ create_rspec_existence_matchers(matcher, object_method, negated_object_method, warning)
14
+ end
15
+
16
+ private
17
+
18
+ def create_rspec_existence_matchers(matcher, object_method, negated_object_method, warning)
19
+ RSpec::Matchers.define(matcher) do |*args|
20
+ match { |actual| actual.public_send(object_method, *args) }
21
+ match_when_negated do |actual|
22
+ if actual.respond_to?(negated_object_method)
23
+ return actual.public_send(negated_object_method, *args)
24
+ end
25
+
26
+ SitePrism.logger.debug(warning)
27
+ !actual.public_send(object_method, *args)
28
+ end
29
+ end
30
+ end
31
+
32
+ def matcher
33
+ "have_#{element_name}"
34
+ end
35
+
36
+ def object_method
37
+ "has_#{element_name}?"
38
+ end
39
+
40
+ def negated_object_method
41
+ "has_no_#{element_name}?"
42
+ end
43
+
44
+ def warning
45
+ "The RSpec matcher '#{matcher}' was added by SitePrism, but the object under test "\
46
+ "does not respond to '#{negated_object_method}' and is probably not a SitePrism object. "\
47
+ 'Falling back to the default RSpec matcher.'
48
+ end
49
+ end
50
+ end
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'site_prism/loadable'
4
-
5
3
  module SitePrism
6
4
  class Section
7
- include Capybara::DSL
8
5
  include ElementChecker
9
6
  include Loadable
10
7
  include DSL
@@ -12,44 +9,67 @@ module SitePrism
12
9
 
13
10
  attr_reader :root_element, :parent
14
11
 
15
- def self.set_default_search_arguments(*args)
16
- @default_search_arguments = args
17
- end
12
+ class << self
13
+ def set_default_search_arguments(*args)
14
+ @default_search_arguments = args
15
+ end
16
+
17
+ def default_search_arguments
18
+ return @default_search_arguments if @default_search_arguments
19
+
20
+ superclass.respond_to?(:default_search_arguments) && superclass.default_search_arguments
21
+ end
18
22
 
19
- def self.default_search_arguments
20
- @default_search_arguments ||
21
- (
22
- superclass.respond_to?(:default_search_arguments) &&
23
- superclass.default_search_arguments
24
- ) ||
25
- nil
23
+ private
24
+
25
+ def root_element_methods
26
+ ::Capybara::Session::NODE_METHODS + %i[native visible?]
27
+ end
28
+
29
+ def session_methods
30
+ ::Capybara::Session::DSL_METHODS - root_element_methods
31
+ end
26
32
  end
27
33
 
28
- def initialize(parent, root_element)
34
+ def initialize(parent, root_element, &block)
29
35
  @parent = parent
30
36
  @root_element = root_element
31
- Capybara.within(@root_element) { yield(self) } if block_given?
37
+ within(&block) if block_given?
32
38
  end
33
39
 
34
- # Capybara::DSL module "delegates" Capybara methods to the "page" method
35
- # as such we need to overload this method so that the correct scoping
36
- # occurs and calls within a section (For example section.find(element))
37
- # correctly scope to look within the section only
38
- def page
39
- return root_element if root_element
40
+ # Send all root_element methods through `#root_element`
41
+ # NB: This requires a method called `#to_capybara_node` being created and
42
+ # then set to this value (Capybara agnostic API)
43
+ root_element_methods.each do |method|
44
+ def_delegators :root_element, method
45
+ end
46
+
47
+ # Send all methods that previously acted on the `#page` method that existed previously
48
+ # through to the same location - But directly as `Capybara.current_session`
49
+ session_methods.each do |method|
50
+ def_delegators :capybara_session, method
51
+ end
40
52
 
41
- SitePrism.logger.warn('Root Element not found; Falling back to `super`')
42
- super
53
+ # This scopes our calls inside Section correctly to the `Capybara::Node::Element`
54
+ def to_capybara_node
55
+ root_element
43
56
  end
44
57
 
45
- def visible?
46
- page.visible?
58
+ # This allows us to return anything thats passed in as a block to the section at
59
+ # creation time, so that an anonymous section or such-like will have the extra methods
60
+ def within
61
+ Capybara.within(root_element) { yield(self) }
47
62
  end
48
63
 
49
- def_delegators :capybara_session,
50
- :execute_script,
51
- :evaluate_script,
52
- :within_frame
64
+ # This was the old API-style of delegating through the Capybara.page call and over-loading
65
+ # the method so we always went through our correct `root_element`
66
+ def page
67
+ SitePrism::Deprecator.deprecate('Using page inside section')
68
+ return root_element if root_element
69
+
70
+ SitePrism.logger.warn('Root Element not found; Falling back to Capybara.current_session')
71
+ capybara_session
72
+ end
53
73
 
54
74
  def capybara_session
55
75
  Capybara.current_session
@@ -60,27 +80,5 @@ module SitePrism
60
80
  candidate = candidate.parent until candidate.is_a?(SitePrism::Page)
61
81
  candidate
62
82
  end
63
-
64
- def native
65
- root_element.native
66
- end
67
-
68
- private
69
-
70
- def _find(*find_args)
71
- page.find(*find_args)
72
- end
73
-
74
- def _all(*find_args)
75
- page.all(*find_args)
76
- end
77
-
78
- def element_exists?(*find_args)
79
- page.has_selector?(*find_args)
80
- end
81
-
82
- def element_does_not_exist?(*find_args)
83
- page.has_no_selector?(*find_args)
84
- end
85
83
  end
86
84
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SitePrism
4
+ class Timer
5
+ attr_reader :wait_time
6
+
7
+ def self.run(wait_time, &block)
8
+ new(wait_time).run(&block)
9
+ end
10
+
11
+ def initialize(wait_time)
12
+ @wait_time = wait_time
13
+ @done = false
14
+ end
15
+
16
+ def done?
17
+ @done == true
18
+ end
19
+
20
+ def run
21
+ start
22
+ yield self
23
+ ensure
24
+ stop
25
+ end
26
+
27
+ def start
28
+ stop
29
+ return if wait_time.zero?
30
+
31
+ @done = false
32
+ @thread = Thread.start do
33
+ sleep wait_time
34
+ @done = true
35
+ end
36
+ end
37
+
38
+ def stop
39
+ if @thread
40
+ @thread.kill
41
+ @thread.join
42
+ @thread = nil
43
+ end
44
+ @done = true
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
- VERSION = '3.4'
4
+ VERSION = '3.7'
5
5
  end
@@ -2,33 +2,20 @@
2
2
 
3
3
  module SitePrism
4
4
  class Waiter
5
- class << self
6
- def wait_until_true(wait_time = Capybara.default_max_wait_time)
7
- start_time = Time.now
5
+ def self.sleep_duration
6
+ 0.05
7
+ end
8
8
 
9
+ def self.wait_until_true(wait_time = Capybara.default_max_wait_time)
10
+ Timer.run(wait_time) do |timer|
9
11
  loop do
10
12
  return true if yield
11
- break if Time.now - start_time > wait_time
12
-
13
- sleep(0.05)
13
+ break if timer.done?
14
14
 
15
- check_for_time_stopped!(start_time)
15
+ sleep(sleep_duration)
16
16
  end
17
-
18
17
  raise SitePrism::TimeoutError, "Timed out after #{wait_time}s."
19
18
  end
20
-
21
- private
22
-
23
- def check_for_time_stopped!(start_time)
24
- return unless start_time == Time.now
25
-
26
- raise(
27
- SitePrism::FrozenInTimeError,
28
- 'Time appears to be frozen. For more info, see ' \
29
- 'https://github.com/site-prism/site_prism/blob/master/lib/site_prism/error.rb'
30
- )
31
- end
32
19
  end
33
20
  end
34
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: site_prism
3
3
  version: !ruby/object:Gem::Version
4
- version: '3.4'
4
+ version: '3.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luke Hill
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-08-01 00:00:00.000000000 Z
12
+ date: 2020-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -31,28 +31,34 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '3.3'
34
+ version: '3.8'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '3.3'
41
+ version: '3.8'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: site_prism-all_there
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: 0.2.0
48
+ version: 0.3.1
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '1.0'
49
52
  type: :runtime
50
53
  prerelease: false
51
54
  version_requirements: !ruby/object:Gem::Requirement
52
55
  requirements:
53
- - - "~>"
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 0.3.1
59
+ - - "<"
54
60
  - !ruby/object:Gem::Version
55
- version: 0.2.0
61
+ version: '1.0'
56
62
  - !ruby/object:Gem::Dependency
57
63
  name: cucumber
58
64
  requirement: !ruby/object:Gem::Requirement
@@ -67,18 +73,32 @@ dependencies:
67
73
  - - "~>"
68
74
  - !ruby/object:Gem::Version
69
75
  version: '3.1'
76
+ - !ruby/object:Gem::Dependency
77
+ name: pry-byebug
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
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,28 @@ dependencies:
101
121
  requirements:
102
122
  - - "~>"
103
123
  - !ruby/object:Gem::Version
104
- version: 0.73.0
124
+ version: 0.83.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.73.0
131
+ version: 0.83.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.4.0
138
+ version: 1.5.1
119
139
  type: :development
120
140
  prerelease: false
121
141
  version_requirements: !ruby/object:Gem::Requirement
122
142
  requirements:
123
143
  - - "~>"
124
144
  - !ruby/object:Gem::Version
125
- version: 1.4.0
145
+ version: 1.5.1
126
146
  - !ruby/object:Gem::Dependency
127
147
  name: rubocop-rspec
128
148
  requirement: !ruby/object:Gem::Requirement
@@ -141,16 +161,22 @@ dependencies:
141
161
  name: selenium-webdriver
142
162
  requirement: !ruby/object:Gem::Requirement
143
163
  requirements:
144
- - - "~>"
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '3.11'
167
+ - - "<"
145
168
  - !ruby/object:Gem::Version
146
- version: '3.7'
169
+ version: '4.1'
147
170
  type: :development
148
171
  prerelease: false
149
172
  version_requirements: !ruby/object:Gem::Requirement
150
173
  requirements:
151
- - - "~>"
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '3.11'
177
+ - - "<"
152
178
  - !ruby/object:Gem::Version
153
- version: '3.7'
179
+ version: '4.1'
154
180
  - !ruby/object:Gem::Dependency
155
181
  name: simplecov
156
182
  requirement: !ruby/object:Gem::Requirement
@@ -171,18 +197,16 @@ dependencies:
171
197
  requirements:
172
198
  - - "~>"
173
199
  - !ruby/object:Gem::Version
174
- version: 3.9.3
200
+ version: '4.1'
175
201
  type: :development
176
202
  prerelease: false
177
203
  version_requirements: !ruby/object:Gem::Requirement
178
204
  requirements:
179
205
  - - "~>"
180
206
  - !ruby/object:Gem::Version
181
- version: 3.9.3
182
- description: |-
183
- SitePrism gives you a simple,
184
- clean and semantic DSL for describing your site.
185
- SitePrism implements the Page Object Model pattern on top of Capybara.
207
+ version: '4.1'
208
+ description: SitePrism gives you a simple, clean and semantic DSL for describing your
209
+ site. SitePrism implements the Page Object Model pattern on top of Capybara.
186
210
  email:
187
211
  - lukehill_uk@hotmail.com
188
212
  - nat@natontesting.com
@@ -202,7 +226,9 @@ files:
202
226
  - lib/site_prism/logger.rb
203
227
  - lib/site_prism/page.rb
204
228
  - lib/site_prism/recursion_checker.rb
229
+ - lib/site_prism/rspec_matchers.rb
205
230
  - lib/site_prism/section.rb
231
+ - lib/site_prism/timer.rb
206
232
  - lib/site_prism/version.rb
207
233
  - lib/site_prism/waiter.rb
208
234
  homepage: https://github.com/site-prism/site_prism
@@ -212,10 +238,7 @@ metadata:
212
238
  bug_tracker_uri: https://github.com/site-prism/site_prism/issues
213
239
  changelog_uri: https://github.com/site-prism/site_prism/blob/master/CHANGELOG.md
214
240
  source_code_uri: https://github.com/site-prism/site_prism
215
- post_install_message: |-
216
- site_prism has now moved to a new organisation to facilitate better
217
- management of the codebase. The new organisation link is available at www.github.com/site-prism
218
- and will house the site_prism gem plus new associated co-dependent gems.
241
+ post_install_message:
219
242
  rdoc_options: []
220
243
  require_paths:
221
244
  - lib
@@ -223,15 +246,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
223
246
  requirements:
224
247
  - - ">="
225
248
  - !ruby/object:Gem::Version
226
- version: '2.3'
249
+ version: '2.4'
227
250
  required_rubygems_version: !ruby/object:Gem::Requirement
228
251
  requirements:
229
252
  - - ">="
230
253
  - !ruby/object:Gem::Version
231
254
  version: '0'
232
255
  requirements: []
233
- rubyforge_project:
234
- rubygems_version: 2.7.8
256
+ rubygems_version: 3.0.6
235
257
  signing_key:
236
258
  specification_version: 4
237
259
  summary: A Page Object Model DSL for Capybara