site_prism 3.6 → 3.7.3

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: 1ec5104247e3512bd7ebf0a48c579cc92041ef21b9c130531ef0cb4ff5a52f88
4
- data.tar.gz: a44ff822766bb37ff023048349037c0467ae47333d4b421bc53d8a59cb2af087
3
+ metadata.gz: 77096cbc91dc0e53b17b8f1af09415d52be9f2859333874869af7a4b07f3e488
4
+ data.tar.gz: 3562488e2a5122a6e71a43f3f042c6c18c6b97d89ee4bee8cf39efdbbd7963e3
5
5
  SHA512:
6
- metadata.gz: 1a6991ecd0110bb53533fb848c40753a13067aed17913f2dd261a5d0b4c8c1747f9f54d1be83d954856037e6cbd24abd665d498b74ff0ad835ab1bea1e0a084a
7
- data.tar.gz: bcfe1f63bcaf2b20c64241c03b1c9c718628609fa0bdaa67c01a78b02964b809135aa815e6b0073d4272235226eda5ad802b8b6852d8b118d0806d96e09e2068
6
+ metadata.gz: 5a97080c7a80c18b4fee6e4673957a16fe9a97a98d87b2cf4d4add2ce76500b326008684626757c16a090bc8a82a3363bd85d49b2b266815bcec49897f82b394
7
+ data.tar.gz: 22b3dc450956bbfbc05e0950815395c3cc4f44b9c5c8d28553cf784b8f95872f604ba177dab2a1b75c88f386f4a86544ee2fc46f70e1cf0c771b5a0bf0123cc3
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2019, The SitePrism team
1
+ Copyright (c) 2011-2021, The SitePrism team
2
2
 
3
3
  All rights reserved.
4
4
 
data/README.md CHANGED
@@ -1,29 +1,40 @@
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.com/site-prism/site_prism.png)](https://travis-ci.com/site-prism/site_prism)
3
+ [![Build Status](https://github.com/site-prism/site_prism/actions/workflows/ci.yml/badge.svg)](https://github.com/site-prism/site_prism/actions/workflows/ci.yml)
4
4
 
5
5
  _A Page Object Model DSL for Capybara_
6
6
 
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
 
14
+ ## Support
15
+
16
+ Support us with a monthly donation and help us continue our activities by supporting us as a [backer](https://opencollective.com/site-prism#backer)
17
+
18
+ Become a sponsor and get your logo on our README on Github with a link to your site. [How to Sponsor SitePrism?](https://opencollective.com/site-prism#sponsor)
19
+
20
+ Free Open Source software can only be maintained with the support of you. If you and/or your company find
21
+ value in SitePrism and would like to contribute financially to its ongoing maintenance and development,
22
+ then please do so. Visit the OpenCollective links above for more details.
23
+
14
24
  ## Developing / Contributing to SitePrism
15
25
 
16
26
  We love it when people want to get involved with our Open Source Project.
17
27
 
18
- We have a brief set of setup docs [HERE](https://github.com/site-prism/site_prism/blob/master/HACKING.md)
28
+ We have a brief set of setup docs [HERE](https://github.com/site-prism/site_prism/blob/main/HACKING.md)
19
29
 
20
30
  ## Supported Rubies / Browsers
21
31
 
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
- If you are using SitePrism with Ruby 2.3 it is highly advisable to upgrade to a more modern Ruby
24
- such as 2.6 or 2.7, if for any other reason, to get a noticeable speed boost!
32
+ SitePrism is built and tested to work on Ruby 2.4 - 2.7. Ruby 2.4 (Now EOL), is supported but
33
+ this version will be removed from the Support Matrix in the coming months.
34
+ If you are using SitePrism with Ruby 2.4 it is highly advisable to upgrade to a more modern Ruby
35
+ such as 2.7, if for any other reason, to get a noticeable speed boost!
25
36
 
26
- SitePrism should run on all major browsers. The gem's integration tests are ran on Chrome and Firefox.
37
+ SitePrism should run on all major browsers. The gem's integration tests are run on Chrome and Firefox.
27
38
 
28
39
  If you find you cannot integrate nicely with SitePrism, please open an
29
40
  [issue request](https://github.com/site-prism/site_prism/issues/new)
@@ -298,7 +309,13 @@ expect(@account_page).to be_displayed
298
309
  ```
299
310
 
300
311
  Calling `#displayed?` will return true if the browser's current URL
301
- matches the page's template and false if it doesn't.
312
+ matches the page's template and false if it doesn't. It will wait for
313
+ `Capybara.default_max_wait_time` seconds or you can pass an explicit
314
+ wait time in seconds as the first argument like this:
315
+
316
+ ```ruby
317
+ @account_page.displayed?(10) # wait up to 10 seconds for display
318
+ ```
302
319
 
303
320
  #### Specifying parameter values for templated URLs
304
321
 
@@ -425,8 +442,11 @@ as a string.
425
442
  #### Accessing the individual element
426
443
 
427
444
  The `element` method will add a number of methods to instances of the
428
- particular Page class. The first method to be added is the name of the
429
- element. So using the following example:
445
+ particular Page class. The first method added is the name of the
446
+ element. It finds the element using [Capybara::Node::Finders#find](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders#find-instance_method)
447
+ returning a [Capybara::Node::Element](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Element) or
448
+ raising [Capybara::ElementNotFound](https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/ElementNotFound)
449
+ if the element can not be found.
430
450
 
431
451
  ```ruby
432
452
  class Home < SitePrism::Page
@@ -450,7 +470,9 @@ end
450
470
  #### Testing for the existence of the element
451
471
 
452
472
  Another method added to the Page class by the `element` method is the
453
- `has_<element_name>?` method. Using the same example as above:
473
+ `has_<element_name>?` method.
474
+ 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).
475
+ Using the same example as above:
454
476
 
455
477
  ```ruby
456
478
  class Home < SitePrism::Page
@@ -480,7 +502,9 @@ end
480
502
 
481
503
  To test that an element does not exist on the page, it is not possible to just call
482
504
  `#not_to have_search_field`. SitePrism supplies the `#has_no_<element>?` method
483
- that should be used to test for non-existence. Using the above example:
505
+ that should be used to test for non-existence.
506
+ 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)
507
+ Using the above example:
484
508
 
485
509
  ```ruby
486
510
  @home = Home.new
@@ -499,8 +523,9 @@ end
499
523
  #### Waiting for an element to become visible
500
524
 
501
525
  A method that gets added by calling `element` is the
502
- `wait_until_<element_name>_visible` method. Calling this method will
503
- cause the test to wait for Capybara's default wait time for the element
526
+ `wait_until_<element_name>_visible` method.
527
+ 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).
528
+ Calling this method will cause the test to wait for Capybara's default wait time for the element
504
529
  to become visible. You can customise the wait time by supplying a number
505
530
  of seconds to wait in-line or configuring the default wait time.
506
531
 
@@ -513,10 +538,11 @@ of seconds to wait in-line or configuring the default wait time.
513
538
  #### Waiting for an element to become invisible
514
539
 
515
540
  Another method added by calling `element` is the
516
- `wait_until_<element_name>_invisible` method. Calling this method will
517
- cause the test to wait for Capybara's default wait time for the element
518
- to become invisible. You can as with the visibility waiter, customise
519
- the wait time in the same way.
541
+ `wait_until_<element_name>_invisible` method.
542
+ 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).
543
+ Calling this method will cause the test to wait for Capybara's default
544
+ wait time for the element to become invisible. You can as with the visibility
545
+ waiter, customise the wait time in the same way.
520
546
 
521
547
  ```ruby
522
548
  @home.wait_until_search_field_invisible
@@ -1489,7 +1515,7 @@ the validations will be performed in the following order:
1489
1515
  **NB:** `SitePrism::Page` **used to** include a default load validation on
1490
1516
  `page.displayed?` however for v3 this has been removed. It is therefore
1491
1517
  necessary to re-define this if you want to retain the behaviour
1492
- from site_prism v2. See [UPGRADING.md](https://github.com/site-prism/site_prism/blob/master/UPGRADING.md#default-load-validations)
1518
+ from site_prism v2. See [UPGRADING.md](https://github.com/site-prism/site_prism/blob/main/UPGRADING.md#default-load-validations)
1493
1519
  for more info on this.
1494
1520
 
1495
1521
  ## Using Capybara Query Options
@@ -4,6 +4,10 @@ require 'digest'
4
4
  require 'base64'
5
5
 
6
6
  module SitePrism
7
+ # [SitePrism::AddressableUrlMatcher]
8
+ # Used in a couple of places to allow users to ...
9
+ # Specify patterns for loading webpages
10
+ # Pass in hashable args or query parameters for loading dynamic pages
7
11
  class AddressableUrlMatcher
8
12
  attr_reader :pattern
9
13
 
@@ -43,12 +47,10 @@ module SitePrism
43
47
  def all_expected_mappings_match?(expected_mappings, actual_mappings)
44
48
  expected_mappings.all? do |key, expected_value|
45
49
  actual_value = actual_mappings[key.to_s]
46
- if expected_value.is_a?(Numeric)
47
- actual_value == expected_value.to_s
48
- elsif expected_value.is_a?(Regexp)
49
- actual_value.match(expected_value)
50
- else
51
- expected_value == actual_value
50
+ case expected_value
51
+ when Numeric; then actual_value == expected_value.to_s
52
+ when Regexp; then actual_value.match(expected_value)
53
+ else expected_value == actual_value
52
54
  end
53
55
  end
54
56
  end
@@ -126,7 +128,7 @@ module SitePrism
126
128
  end
127
129
 
128
130
  # If a slug begins with non-alpha characters, it may denote the start of
129
- # a new component (e.g. query or fragment). We emit thie prefix as part of
131
+ # a new component (e.g. query or fragment). We emit this prefix as part of
130
132
  # the substituted slug so that Addressable's URI parser can see it as such.
131
133
  def slug_prefix(slug)
132
134
  prefix = slug.match(/\A{([^A-Za-z]+)/)
@@ -1,8 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::Deprecator]
4
5
  class Deprecator
5
6
  class << self
7
+ # @return SitePrism.logger.warn(msg)
8
+ #
9
+ # Tells the user that they are using old functionality, which needs removing in the
10
+ # next major version
6
11
  def deprecate(old, new = nil)
7
12
  if new
8
13
  warn("#{old} is being deprecated and should no longer be used. Use #{new} instead.")
@@ -13,6 +18,14 @@ module SitePrism
13
18
  warn("#{old} will be removed in SitePrism v4. You have been warned!")
14
19
  end
15
20
 
21
+ # @return SitePrism.logger.debug(msg)
22
+ #
23
+ # Tells the user that they are using functionality which is non-optimal
24
+ # The functionality should usually provide a reason for it being poor, as well as an
25
+ # optional way of upgrading to something different
26
+ #
27
+ # NB: As this is bubbled up at debug level, often users will not see this. So it will
28
+ # never be a candidate for removal directly
16
29
  def soft_deprecate(old, reason, new = nil)
17
30
  debug("The #{old} method is changing, as is SitePrism, and is now configurable.")
18
31
  debug("REASON: #{reason}.")
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::DSL]
5
+ #
6
+ # This is the core Module Namespace for all of the public-facing DSL methods
7
+ # such as `element`. The code here is designed to be used through the defining
8
+ # of said items, and not to be instantiated directly.
9
+ #
10
+ # The whole package here can be thought of as [@api private]
4
11
  module DSL
5
12
  def self.included(klass)
6
13
  klass.extend ClassMethods
@@ -8,33 +15,28 @@ module SitePrism
8
15
 
9
16
  private
10
17
 
11
- # Call `find` inside context set on page/section
18
+ # Call `find` inside `to_capybara_node` context (Either Capybara::Session or Capybara::Node::Element)
12
19
  def _find(*find_args)
13
20
  kwargs = find_args.pop
14
- page.find(*find_args, **kwargs)
21
+ to_capybara_node.find(*find_args, **kwargs)
15
22
  end
16
23
 
17
- # Call `all` inside context set on page/section
24
+ # Call `all` inside `to_capybara_node` context (Either Capybara::Session or Capybara::Node::Element)
18
25
  def _all(*find_args)
19
26
  kwargs = find_args.pop
20
- page.all(*find_args, **kwargs)
27
+ to_capybara_node.all(*find_args, **kwargs)
21
28
  end
22
29
 
23
- # Call `has_selector?` inside context set on page/section
30
+ # Call `has_selector?` inside `to_capybara_node` context (Either Capybara::Session or Capybara::Node::Element)
24
31
  def element_exists?(*find_args)
25
32
  kwargs = find_args.pop
26
- page.has_selector?(*find_args, **kwargs)
33
+ to_capybara_node.has_selector?(*find_args, **kwargs)
27
34
  end
28
35
 
29
- # Call `has_no_selector?` inside context set on page/section
36
+ # Call `has_no_selector?` inside `to_capybara_node` context (Either Capybara::Session or Capybara::Node::Element)
30
37
  def element_does_not_exist?(*find_args)
31
38
  kwargs = find_args.pop
32
- page.has_no_selector?(*find_args, **kwargs)
33
- end
34
-
35
- # The default waiting time set by Capybara's configuration settings.
36
- def wait_time
37
- Capybara.default_max_wait_time
39
+ to_capybara_node.has_no_selector?(*find_args, **kwargs)
38
40
  end
39
41
 
40
42
  # Prevent users from calling methods with blocks when they shouldn't be.
@@ -92,21 +94,29 @@ module SitePrism
92
94
  #
93
95
  # If the hash is empty, then the hash is omitted from the payload sent
94
96
  # to Capybara, and the find / runtime arguments are sent alone.
97
+ #
98
+ # NB: If the +wait+ key is present in the options hash, even as false or 0, It will
99
+ # be set as the user-supplied value (So user error can be the cause for issues).
95
100
  def recombine_args(find_args, runtime_args, options)
96
101
  options.merge!(find_args.pop) if find_args.last.is_a? Hash
97
102
  options.merge!(runtime_args.pop) if runtime_args.last.is_a? Hash
98
- options[:wait] = wait_time unless wait_key_present?(options)
99
- end
100
-
101
- # Detect if the +wait+ key is present in the options hash.
102
- # Note that setting it to to false or 0, still will return true here.
103
- def wait_key_present?(options)
104
- options.key?(:wait)
103
+ options[:wait] = Capybara.default_max_wait_time unless options.key?(:wait)
105
104
  end
106
105
 
106
+ # [SitePrism::DSL::ClassMethods]
107
+ # This exposes all of the DSL definitions users will use when generating
108
+ # their POM classes.
109
+ #
110
+ # Many of these methods will be used in-line to allow users to generate a multitude of
111
+ # methods and locators for finding elements / sections on a page or section of a page
107
112
  module ClassMethods
108
113
  attr_reader :expected_items
109
114
 
115
+ # Creates an instance of a SitePrism Element - This will create several methods designed to
116
+ # Locate the element -> @return [Capybara::Node::Element]
117
+ # Check the elements presence or non-presence -> @return [Boolean]
118
+ # Wait for the elements to be present or not -> @return [TrueClass, SitePrism::Error]
119
+ # Validate certain properties about the element
110
120
  def element(name, *find_args)
111
121
  SitePrism::Deprecator.deprecate('Passing a block to :element') if block_given?
112
122
  build(:element, name, *find_args) do
@@ -118,6 +128,11 @@ module SitePrism
118
128
  end
119
129
  end
120
130
 
131
+ # Creates a enumerable instance of a SitePrism Element - This will create several methods designed to
132
+ # Locate the enumerable element -> @return [Capybara::Result]
133
+ # Check the elements presence or non-presence -> @return [Boolean]
134
+ # Wait for the elements to be present or not -> @return [TrueClass, SitePrism::Error]
135
+ # Validate certain properties about the elements
121
136
  def elements(name, *find_args)
122
137
  SitePrism::Deprecator.deprecate('Passing a block to :elements') if block_given?
123
138
  build(:elements, name, *find_args) do
@@ -129,10 +144,18 @@ module SitePrism
129
144
  end
130
145
  end
131
146
 
147
+ # Sets the `expected_items` iVar on a class. This property is used in conjunction with
148
+ # `all_there?` to provide a way of granularising the check made to only interrogate a sub-set
149
+ # of DSL defined items
132
150
  def expected_elements(*elements)
133
151
  @expected_items = elements
134
152
  end
135
153
 
154
+ # Creates an instance of a SitePrism Section - This will create several methods designed to
155
+ # Locate the section -> @return [SitePrism::Section]
156
+ # Check the section presence or non-presence -> @return [Boolean]
157
+ # Wait for the section to be present or not -> @return [TrueClass, SitePrism::Error]
158
+ # Validate certain properties about the section
136
159
  def section(name, *args, &block)
137
160
  section_class, find_args = extract_section_options(args, &block)
138
161
  build(:section, name, *find_args) do
@@ -144,6 +167,11 @@ module SitePrism
144
167
  end
145
168
  end
146
169
 
170
+ # Creates an enumerable instance of a SitePrism Section - This will create several methods designed to
171
+ # Locate the sections -> @return [Array]
172
+ # Check the sections presence or non-presence -> @return [Boolean]
173
+ # Wait for the sections to be present or not -> @return [TrueClass, SitePrism::Error]
174
+ # Validate certain properties about the section
147
175
  def sections(name, *args, &block)
148
176
  section_class, find_args = extract_section_options(args, &block)
149
177
  build(:sections, name, *find_args) do
@@ -169,12 +197,13 @@ module SitePrism
169
197
  end
170
198
  end
171
199
 
200
+ # Return a list of all mapped items on a SitePrism class instance (Page or Section)
201
+ # If legacy is set to true (Default) -> @return [Array]
202
+ # If legacy is set to false (New behaviour) -> @return [Hash]
172
203
  def mapped_items(legacy: true)
173
- if legacy
174
- old_mapped_items
175
- else
176
- new_mapped_items
177
- end
204
+ return old_mapped_items if legacy
205
+
206
+ new_mapped_items
178
207
  end
179
208
 
180
209
  private
@@ -189,13 +218,7 @@ module SitePrism
189
218
  end
190
219
 
191
220
  def new_mapped_items
192
- @new_mapped_items ||= {
193
- element: [],
194
- elements: [],
195
- section: [],
196
- sections: [],
197
- iframe: []
198
- }
221
+ @new_mapped_items ||= { element: [], elements: [], section: [], sections: [], iframe: [] }
199
222
  end
200
223
 
201
224
  def build(type, name, *find_args)
@@ -222,11 +245,9 @@ module SitePrism
222
245
  end
223
246
 
224
247
  def create_helper_method(proposed_method_name, *find_args)
225
- if find_args.empty?
226
- create_error_method(proposed_method_name)
227
- else
228
- yield
229
- end
248
+ return create_error_method(proposed_method_name) if find_args.empty?
249
+
250
+ yield
230
251
  end
231
252
 
232
253
  def create_existence_checker(element_name, *find_args)
@@ -275,6 +296,10 @@ module SitePrism
275
296
 
276
297
  def create_error_method(name)
277
298
  SitePrism.logger.error("#{name} has come from an item with no locators.")
299
+ SitePrism::Deprecator.soft_deprecate(
300
+ 'DSL definition with no find_args',
301
+ 'All DSL elements should have find_args'
302
+ )
278
303
  define_method(name) { raise SitePrism::InvalidElementError }
279
304
  end
280
305
 
@@ -310,7 +335,7 @@ module SitePrism
310
335
  def extract_section_options(args, &block)
311
336
  if args.first.is_a?(Class)
312
337
  klass = args.shift
313
- section_class = klass if klass.ancestors.include?(SitePrism::Section)
338
+ section_class = klass if klass <= SitePrism::Section
314
339
  end
315
340
 
316
341
  section_class = deduce_section_class(section_class, &block)
@@ -320,23 +345,26 @@ module SitePrism
320
345
 
321
346
  def deduce_section_class(base_class, &block)
322
347
  klass = base_class
323
- klass = Class.new(klass || SitePrism::Section, &block) if block_given?
348
+ klass = Class.new(klass || SitePrism::Section, &block) if block
324
349
  return klass if klass
325
350
 
326
- raise ArgumentError, "You should provide descendant of \
327
- SitePrism::Section class or/and a block as the second argument."
351
+ raise ArgumentError, 'You should provide descendant of SitePrism::Section class or/and a block as the second argument.'
328
352
  end
329
353
 
330
354
  def deduce_search_arguments(section_class, args)
331
355
  extract_search_arguments(args) ||
332
356
  extract_search_arguments(section_class.default_search_arguments) ||
333
- raise(ArgumentError, "You should provide search arguments \
334
- in section creation or set_default_search_arguments within section class")
357
+ invalidate_search_arguments!
335
358
  end
336
359
 
337
360
  def extract_search_arguments(args)
338
361
  args if args && !args.empty?
339
362
  end
363
+
364
+ def invalidate_search_arguments!
365
+ SitePrism.logger.error('Could not deduce search_arguments')
366
+ raise(ArgumentError, 'search arguments are needed in `section` definition or alternatively use `set_default_search_arguments`')
367
+ end
340
368
  end
341
369
  end
342
370
  end
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::ElementChecker]
5
+ #
6
+ # This allows users to run `#all_there?` checks on an instance.
7
+ #
8
+ # NB: This functionality is being removed in v4 in favour of the all_there gem
4
9
  module ElementChecker
5
10
  # Runnable in the scope of any SitePrism::Page or Section.
6
11
  # Returns +true+ when "every item" that is being checked is
@@ -21,20 +26,25 @@ module SitePrism
21
26
  # Override: 'one' => Perform one recursive dive into all section/sections
22
27
  # items and call #all_there? on all of those items too.
23
28
  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
29
+ case recursion
30
+ when :none; then elements_to_check.all? { |name| there?(name) }
31
+ when :one; then all_there_with_recursion
28
32
  else
29
33
  SitePrism.logger.debug("Input value '#{recursion}'. Valid values are :none or :one.")
30
34
  SitePrism.logger.error('Invalid recursion setting, Will not run #all_there?.')
31
35
  end
32
36
  end
33
37
 
38
+ # Returns each element that is currently present inside the scope being tested
39
+ #
40
+ # @return [Array]
34
41
  def elements_present
35
42
  _mapped_items.select { |name| there?(name) }
36
43
  end
37
44
 
45
+ # Returns each element that is not currently present inside the scope being tested
46
+ #
47
+ # @return [Array]
38
48
  def elements_missing
39
49
  elements_to_check.reject { |name| there?(name) }
40
50
  end
@@ -1,46 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::Loadable]
5
+ #
6
+ # SitePrism Loadable's are defined as checks or waiters which "must" pass before
7
+ # the rest of the loading logic can be performed on a class or section.
8
+ #
9
+ # Loadable's are primarily used with the `#load` method which will auto-execute them all
10
+ # in their defined order. But they can be used dynamically wherever desired.
4
11
  module Loadable
5
- module ClassMethods
6
- # The list of load_validations.
7
- # They will be executed in the order they are defined.
8
- #
9
- # @return [Array]
10
- def load_validations
11
- if superclass.respond_to?(:load_validations)
12
- superclass.load_validations + _load_validations
13
- else
14
- _load_validations
15
- end
16
- end
17
-
18
- # Appends a load validation block to the page class.
19
- #
20
- # When `loaded?` is called, these blocks are instance_eval'd
21
- # against the current page instance.
22
- # This allows users to wait for specific events to occur on
23
- # the page or certain elements to be loaded before performing
24
- # any actions on the page.
25
- #
26
- # @param block [&block] A block which returns true if the page
27
- # loaded successfully, or false if it did not.
28
- # This block can contain up to 2 elements in an array
29
- # The first is the physical validation test to be truthily evaluated.
30
- #
31
- # If this does not pass, then the 2nd item (if defined), is output
32
- # as an error message to the +FailedLoadValidationError+ that is thrown
33
- def load_validation(&block)
34
- _load_validations << block
35
- end
36
-
37
- private
38
-
39
- def _load_validations
40
- @_load_validations ||= []
41
- end
42
- end
43
-
44
12
  def self.included(base)
45
13
  base.extend(ClassMethods)
46
14
  end
@@ -99,5 +67,51 @@ module SitePrism
99
67
  passed
100
68
  end
101
69
  end
70
+
71
+ # [SitePrism::Loadable::ClassMethods]
72
+ # This exposes all of the DSL definitions users will use when generating "loadables"
73
+ #
74
+ # A "Loadable" is a definition whereby the page object once loaded must pass a boolean check
75
+ # These loadables are typically provided using the method `load_validation`
76
+ module ClassMethods
77
+ # The list of load_validations.
78
+ # They will be executed in the order they are defined.
79
+ #
80
+ # @return [Array]
81
+ def load_validations
82
+ if superclass.respond_to?(:load_validations)
83
+ superclass.load_validations + _load_validations
84
+ else
85
+ _load_validations
86
+ end
87
+ end
88
+
89
+ # Appends a load validation block to the page class.
90
+ #
91
+ # When `loaded?` is called, these blocks are instance_eval'd
92
+ # against the current page instance.
93
+ # This allows users to wait for specific events to occur on
94
+ # the page or certain elements to be loaded before performing
95
+ # any actions on the page.
96
+ #
97
+ # @param block [&block] A block which returns true if the page
98
+ # loaded successfully, or false if it did not.
99
+ # This block can contain up to 2 elements in an array
100
+ # The first is the physical validation test to be truthily evaluated.
101
+ #
102
+ # If this does not pass, then the 2nd item (if defined), is output
103
+ # as an error message to the +FailedLoadValidationError+ that is thrown
104
+ #
105
+ # @return [Proc]
106
+ def load_validation(&block)
107
+ _load_validations << block
108
+ end
109
+
110
+ private
111
+
112
+ def _load_validations
113
+ @_load_validations ||= []
114
+ end
115
+ end
102
116
  end
103
117
  end
@@ -10,23 +10,43 @@ module SitePrism
10
10
  class << self
11
11
  attr_reader :url
12
12
 
13
+ # Sets and returns the specific url that will be loaded for a page object
14
+ #
15
+ # @return [String]
13
16
  def set_url(page_url)
14
17
  @url = page_url.to_s
15
18
  end
16
19
 
20
+ # Sets and returns the specific url matcher that will be used to validate the page is loaded
21
+ #
22
+ # @return [Regexp]
17
23
  def set_url_matcher(page_url_matcher)
18
24
  @url_matcher = page_url_matcher
19
25
  end
20
26
 
27
+ # The specific url matcher that is used to validate the page is loaded.
28
+ # When one hasn't been previously set, use the url that was set as a direct Regexp exact matcher
29
+ #
30
+ # @return [Regexp]
21
31
  def url_matcher
22
32
  @url_matcher ||= url
23
33
  end
24
34
  end
25
35
 
36
+ # Where a Capybara HTML fragment has been directly injected into `#load` as a block return this loaded fragment
37
+ # Where a page has been directly navigated to through traditional means (i.e. Selenium), return an instance of the
38
+ # current Capybara session (With all applicable methods)
39
+ #
40
+ # @return [Capybara::Node::Simple || Capybara::Session]
26
41
  def page
27
42
  (defined?(@page) && @page) || Capybara.current_session
28
43
  end
29
44
 
45
+ # This scopes our calls inside Page correctly to the `Capybara::Session`
46
+ def to_capybara_node
47
+ page
48
+ end
49
+
30
50
  # Loads the page.
31
51
  # @param expansion_or_html
32
52
  # @param block [&block] An optional block to run once the page is loaded.
@@ -66,11 +86,11 @@ module SitePrism
66
86
  raise SitePrism::NoUrlMatcherForPageError unless url_matcher
67
87
 
68
88
  expected_mappings = args.last.is_a?(::Hash) ? args.pop : {}
69
- seconds = args&.first || wait_time
89
+ seconds = args&.first || Capybara.default_max_wait_time
70
90
  Waiter.wait_until_true(seconds) { url_matches?(expected_mappings) }
71
91
  end
72
92
 
73
- def url_matches(seconds = wait_time)
93
+ def url_matches(seconds = Capybara.default_max_wait_time)
74
94
  return unless displayed?(seconds)
75
95
  return regexp_backed_matches if url_matcher.is_a?(Regexp)
76
96
 
@@ -134,7 +154,7 @@ module SitePrism
134
154
  visit expanded_url
135
155
  if with_validations
136
156
  when_loaded(&block)
137
- elsif block_given?
157
+ elsif block
138
158
  yield self
139
159
  end
140
160
  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)
@@ -19,9 +19,7 @@ module SitePrism
19
19
  RSpec::Matchers.define(matcher) do |*args|
20
20
  match { |actual| actual.public_send(object_method, *args) }
21
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
22
+ return actual.public_send(negated_object_method, *args) if actual.respond_to?(negated_object_method)
25
23
 
26
24
  SitePrism.logger.debug(warning)
27
25
  !actual.public_send(object_method, *args)
@@ -2,7 +2,6 @@
2
2
 
3
3
  module SitePrism
4
4
  class Section
5
- include Capybara::DSL
6
5
  include ElementChecker
7
6
  include Loadable
8
7
  include DSL
@@ -10,48 +9,67 @@ module SitePrism
10
9
 
11
10
  attr_reader :root_element, :parent
12
11
 
13
- def self.set_default_search_arguments(*args)
14
- @default_search_arguments = args
15
- 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
22
+
23
+ private
16
24
 
17
- def self.default_search_arguments
18
- @default_search_arguments ||
19
- (
20
- superclass.respond_to?(:default_search_arguments) &&
21
- superclass.default_search_arguments
22
- ) ||
23
- nil
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
24
32
  end
25
33
 
26
34
  def initialize(parent, root_element, &block)
27
35
  @parent = parent
28
36
  @root_element = root_element
29
- within(&block) if block_given?
37
+ within(&block) if block
30
38
  end
31
39
 
32
- def within
33
- Capybara.within(@root_element) { yield(self) }
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
34
45
  end
35
46
 
36
- # Capybara::DSL module "delegates" Capybara methods to the "page" method
37
- # as such we need to overload this method so that the correct scoping
38
- # occurs and calls within a section (For example section.find(element))
39
- # correctly scope to look within the section only
40
- def page
41
- return root_element if root_element
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
42
52
 
43
- SitePrism.logger.warn('Root Element not found; Falling back to `super`')
44
- super
53
+ # This scopes our calls inside Section correctly to the `Capybara::Node::Element`
54
+ def to_capybara_node
55
+ root_element
45
56
  end
46
57
 
47
- def visible?
48
- 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) }
49
62
  end
50
63
 
51
- def_delegators :capybara_session,
52
- :execute_script,
53
- :evaluate_script,
54
- :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
55
73
 
56
74
  def capybara_session
57
75
  Capybara.current_session
@@ -62,9 +80,5 @@ module SitePrism
62
80
  candidate = candidate.parent until candidate.is_a?(SitePrism::Page)
63
81
  candidate
64
82
  end
65
-
66
- def native
67
- root_element.native
68
- end
69
83
  end
70
84
  end
@@ -1,9 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::Timer]
5
+ #
6
+ # Used to count asynchronously towards an overall desired duration or condition (Block)
4
7
  class Timer
5
8
  attr_reader :wait_time
6
9
 
10
+ # Return &block
11
+ #
12
+ # Count towards a specified time (Supplied)
7
13
  def self.run(wait_time, &block)
8
14
  new(wait_time).run(&block)
9
15
  end
@@ -13,10 +19,16 @@ module SitePrism
13
19
  @done = false
14
20
  end
15
21
 
22
+ # Return Boolean
23
+ #
24
+ # Whether the timer has completed
16
25
  def done?
17
26
  @done == true
18
27
  end
19
28
 
29
+ # Return &block
30
+ #
31
+ # Start the Timer and re-evaluate the block repeatedly
20
32
  def run
21
33
  start
22
34
  yield self
@@ -24,6 +36,9 @@ module SitePrism
24
36
  stop
25
37
  end
26
38
 
39
+ # Return [Boolean, Nil]
40
+ #
41
+ # Start the Timer in a separate process
27
42
  def start
28
43
  stop
29
44
  return if wait_time.zero?
@@ -35,6 +50,9 @@ module SitePrism
35
50
  end
36
51
  end
37
52
 
53
+ # Return True
54
+ #
55
+ # Forcibly stop the timer, and kill any threads created by it
38
56
  def stop
39
57
  if @thread
40
58
  @thread.kill
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
- VERSION = '3.6'
4
+ VERSION = '3.7.3'
5
5
  end
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SitePrism
4
+ # [SitePrism::Waiter]
4
5
  class Waiter
5
- def self.sleep_duration
6
- 0.05
7
- end
8
-
6
+ # @return Boolean
7
+ #
8
+ # A looper that will wait until the passed in block evaluates to true
9
+ # Alternatively it will time out once the wait_time is exceeded
9
10
  def self.wait_until_true(wait_time = Capybara.default_max_wait_time)
10
11
  Timer.run(wait_time) do |timer|
11
12
  loop do
12
13
  return true if yield
13
14
  break if timer.done?
14
15
 
15
- sleep(sleep_duration)
16
+ sleep(0.05)
16
17
  end
17
18
  raise SitePrism::TimeoutError, "Timed out after #{wait_time}s."
18
19
  end
data/lib/site_prism.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require 'site_prism/error'
4
4
  require 'addressable/template'
5
5
 
6
+ # [SitePrism] namespace
7
+ # We autoload our files underneath here to provide a slightly more optimal load solution
6
8
  module SitePrism
7
9
  autoload :AddressableUrlMatcher, 'site_prism/addressable_url_matcher'
8
10
  autoload :DSL, 'site_prism/dsl'
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.6'
4
+ version: 3.7.3
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: 2020-08-17 00:00:00.000000000 Z
12
+ date: 2021-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -17,34 +17,28 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '2.5'
20
+ version: '2.6'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '2.5'
27
+ version: '2.6'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: capybara
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '3.8'
35
- - - "<="
32
+ - - "~>"
36
33
  - !ruby/object:Gem::Version
37
- version: '3.29'
34
+ version: '3.15'
38
35
  type: :runtime
39
36
  prerelease: false
40
37
  version_requirements: !ruby/object:Gem::Requirement
41
38
  requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- version: '3.8'
45
- - - "<="
39
+ - - "~>"
46
40
  - !ruby/object:Gem::Version
47
- version: '3.29'
41
+ version: '3.15'
48
42
  - !ruby/object:Gem::Dependency
49
43
  name: site_prism-all_there
50
44
  requirement: !ruby/object:Gem::Requirement
@@ -69,16 +63,22 @@ dependencies:
69
63
  name: cucumber
70
64
  requirement: !ruby/object:Gem::Requirement
71
65
  requirements:
72
- - - "~>"
66
+ - - ">"
73
67
  - !ruby/object:Gem::Version
74
- version: '3.1'
68
+ version: '4'
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: '8'
75
72
  type: :development
76
73
  prerelease: false
77
74
  version_requirements: !ruby/object:Gem::Requirement
78
75
  requirements:
79
- - - "~>"
76
+ - - ">"
80
77
  - !ruby/object:Gem::Version
81
- version: '3.1'
78
+ version: '4'
79
+ - - "<"
80
+ - !ruby/object:Gem::Version
81
+ version: '8'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: pry-byebug
84
84
  requirement: !ruby/object:Gem::Requirement
@@ -93,83 +93,69 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: rake
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- version: '12.3'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- version: '12.3'
110
96
  - !ruby/object:Gem::Dependency
111
97
  name: rspec
112
98
  requirement: !ruby/object:Gem::Requirement
113
99
  requirements:
114
100
  - - "~>"
115
101
  - !ruby/object:Gem::Version
116
- version: '3.8'
102
+ version: '3.10'
117
103
  type: :development
118
104
  prerelease: false
119
105
  version_requirements: !ruby/object:Gem::Requirement
120
106
  requirements:
121
107
  - - "~>"
122
108
  - !ruby/object:Gem::Version
123
- version: '3.8'
109
+ version: '3.10'
124
110
  - !ruby/object:Gem::Dependency
125
111
  name: rubocop
126
112
  requirement: !ruby/object:Gem::Requirement
127
113
  requirements:
128
114
  - - "~>"
129
115
  - !ruby/object:Gem::Version
130
- version: 0.81.0
116
+ version: 1.11.0
131
117
  type: :development
132
118
  prerelease: false
133
119
  version_requirements: !ruby/object:Gem::Requirement
134
120
  requirements:
135
121
  - - "~>"
136
122
  - !ruby/object:Gem::Version
137
- version: 0.81.0
123
+ version: 1.11.0
138
124
  - !ruby/object:Gem::Dependency
139
125
  name: rubocop-performance
140
126
  requirement: !ruby/object:Gem::Requirement
141
127
  requirements:
142
128
  - - "~>"
143
129
  - !ruby/object:Gem::Version
144
- version: 1.5.1
130
+ version: 1.10.1
145
131
  type: :development
146
132
  prerelease: false
147
133
  version_requirements: !ruby/object:Gem::Requirement
148
134
  requirements:
149
135
  - - "~>"
150
136
  - !ruby/object:Gem::Version
151
- version: 1.5.1
137
+ version: 1.10.1
152
138
  - !ruby/object:Gem::Dependency
153
139
  name: rubocop-rspec
154
140
  requirement: !ruby/object:Gem::Requirement
155
141
  requirements:
156
142
  - - "~>"
157
143
  - !ruby/object:Gem::Version
158
- version: 1.33.0
144
+ version: 2.2.0
159
145
  type: :development
160
146
  prerelease: false
161
147
  version_requirements: !ruby/object:Gem::Requirement
162
148
  requirements:
163
149
  - - "~>"
164
150
  - !ruby/object:Gem::Version
165
- version: 1.33.0
151
+ version: 2.2.0
166
152
  - !ruby/object:Gem::Dependency
167
153
  name: selenium-webdriver
168
154
  requirement: !ruby/object:Gem::Requirement
169
155
  requirements:
170
156
  - - ">="
171
157
  - !ruby/object:Gem::Version
172
- version: '3.9'
158
+ version: '3.13'
173
159
  - - "<"
174
160
  - !ruby/object:Gem::Version
175
161
  version: '4.1'
@@ -179,7 +165,7 @@ dependencies:
179
165
  requirements:
180
166
  - - ">="
181
167
  - !ruby/object:Gem::Version
182
- version: '3.9'
168
+ version: '3.13'
183
169
  - - "<"
184
170
  - !ruby/object:Gem::Version
185
171
  version: '4.1'
@@ -189,28 +175,28 @@ dependencies:
189
175
  requirements:
190
176
  - - "~>"
191
177
  - !ruby/object:Gem::Version
192
- version: '0.17'
178
+ version: '0.18'
193
179
  type: :development
194
180
  prerelease: false
195
181
  version_requirements: !ruby/object:Gem::Requirement
196
182
  requirements:
197
183
  - - "~>"
198
184
  - !ruby/object:Gem::Version
199
- version: '0.17'
185
+ version: '0.18'
200
186
  - !ruby/object:Gem::Dependency
201
187
  name: webdrivers
202
188
  requirement: !ruby/object:Gem::Requirement
203
189
  requirements:
204
190
  - - "~>"
205
191
  - !ruby/object:Gem::Version
206
- version: '4.1'
192
+ version: '4.6'
207
193
  type: :development
208
194
  prerelease: false
209
195
  version_requirements: !ruby/object:Gem::Requirement
210
196
  requirements:
211
197
  - - "~>"
212
198
  - !ruby/object:Gem::Version
213
- version: '4.1'
199
+ version: '4.6'
214
200
  description: SitePrism gives you a simple, clean and semantic DSL for describing your
215
201
  site. SitePrism implements the Page Object Model pattern on top of Capybara.
216
202
  email:
@@ -242,7 +228,7 @@ licenses:
242
228
  - BSD-3-Clause
243
229
  metadata:
244
230
  bug_tracker_uri: https://github.com/site-prism/site_prism/issues
245
- changelog_uri: https://github.com/site-prism/site_prism/blob/master/CHANGELOG.md
231
+ changelog_uri: https://github.com/site-prism/site_prism/blob/main/CHANGELOG.md
246
232
  source_code_uri: https://github.com/site-prism/site_prism
247
233
  post_install_message:
248
234
  rdoc_options: []
@@ -259,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
245
  - !ruby/object:Gem::Version
260
246
  version: '0'
261
247
  requirements: []
262
- rubygems_version: 3.0.6
248
+ rubygems_version: 3.0.8
263
249
  signing_key:
264
250
  specification_version: 4
265
251
  summary: A Page Object Model DSL for Capybara