site_prism 3.4.1 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +111 -31
- data/lib/site_prism.rb +7 -2
- data/lib/site_prism/addressable_url_matcher.rb +8 -6
- data/lib/site_prism/deprecator.rb +11 -0
- data/lib/site_prism/dsl.rb +93 -43
- data/lib/site_prism/element_checker.rb +12 -4
- data/lib/site_prism/error.rb +0 -8
- data/lib/site_prism/loadable.rb +7 -0
- data/lib/site_prism/page.rb +6 -35
- data/lib/site_prism/recursion_checker.rb +2 -1
- data/lib/site_prism/rspec_matchers.rb +48 -0
- data/lib/site_prism/section.rb +49 -51
- data/lib/site_prism/timer.rb +47 -0
- data/lib/site_prism/version.rb +1 -1
- data/lib/site_prism/waiter.rb +7 -20
- metadata +60 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5deda0d9df9e83e2a66663a217cf5c434fd3ed25abae0d14778d99cd5db1c0f
|
4
|
+
data.tar.gz: 6c86aff27c00c5e91b01667f7da1f9ee6e2d33d4f95d18fbb0cfdd9fd44779c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 254398e151d390326bf085d0746391aedd247d1ed8bf47909d8fb87752b6cedd056ff32c14f324d5b33f4b922734ed01ec2467f64be59a8d97a07cf8aa002eea
|
7
|
+
data.tar.gz: 652781ebe825ed5f943ca0f8480a9b5fbd511e81e6c12d9ce95de7c3239073d4499f4165044c8c58888aeabf0cf2d9bc76e4ca6f2ae6baa6996093117577005a
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -7,23 +7,34 @@ _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:
|
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/
|
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.
|
23
|
-
|
24
|
-
|
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
|
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)
|
@@ -124,6 +135,7 @@ require 'capybara'
|
|
124
135
|
require 'capybara/cucumber'
|
125
136
|
require 'selenium-webdriver'
|
126
137
|
require 'site_prism'
|
138
|
+
require 'site_prism/all_there' # Optional but needed to perform more complex matching
|
127
139
|
```
|
128
140
|
|
129
141
|
The driver creation is identical to how you would normally create a Capybara driver,
|
@@ -135,6 +147,7 @@ Capybara.register_driver :site_prism do |app|
|
|
135
147
|
Capybara::Selenium::Driver.new(app, browser: browser, desired_capabilities: capabilities)
|
136
148
|
end
|
137
149
|
|
150
|
+
# Then tell Capybara to use the Driver you've just defined as its default driver
|
138
151
|
Capybara.configure do |config|
|
139
152
|
config.default_driver = :site_prism
|
140
153
|
end
|
@@ -149,6 +162,7 @@ require 'capybara'
|
|
149
162
|
require 'capybara/rspec'
|
150
163
|
require 'selenium-webdriver'
|
151
164
|
require 'site_prism'
|
165
|
+
require 'site_prism/all_there' # Optional but needed to perform more complex matching
|
152
166
|
```
|
153
167
|
|
154
168
|
And again, as above, a sample driver is no different to a normal driver instantiation in Capybara.
|
@@ -295,7 +309,13 @@ expect(@account_page).to be_displayed
|
|
295
309
|
```
|
296
310
|
|
297
311
|
Calling `#displayed?` will return true if the browser's current URL
|
298
|
-
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
|
+
```
|
299
319
|
|
300
320
|
#### Specifying parameter values for templated URLs
|
301
321
|
|
@@ -422,8 +442,11 @@ as a string.
|
|
422
442
|
#### Accessing the individual element
|
423
443
|
|
424
444
|
The `element` method will add a number of methods to instances of the
|
425
|
-
particular Page class. The first method
|
426
|
-
element.
|
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.
|
427
450
|
|
428
451
|
```ruby
|
429
452
|
class Home < SitePrism::Page
|
@@ -447,7 +470,9 @@ end
|
|
447
470
|
#### Testing for the existence of the element
|
448
471
|
|
449
472
|
Another method added to the Page class by the `element` method is the
|
450
|
-
`has_<element_name>?` method.
|
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:
|
451
476
|
|
452
477
|
```ruby
|
453
478
|
class Home < SitePrism::Page
|
@@ -477,7 +502,9 @@ end
|
|
477
502
|
|
478
503
|
To test that an element does not exist on the page, it is not possible to just call
|
479
504
|
`#not_to have_search_field`. SitePrism supplies the `#has_no_<element>?` method
|
480
|
-
that should be used to test for non-existence.
|
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:
|
481
508
|
|
482
509
|
```ruby
|
483
510
|
@home = Home.new
|
@@ -495,9 +522,10 @@ end
|
|
495
522
|
|
496
523
|
#### Waiting for an element to become visible
|
497
524
|
|
498
|
-
A method that gets added by calling `element` is the
|
499
|
-
`wait_until_<element_name>_visible` method.
|
500
|
-
|
525
|
+
A method that gets added by calling `element` is the
|
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
|
501
529
|
to become visible. You can customise the wait time by supplying a number
|
502
530
|
of seconds to wait in-line or configuring the default wait time.
|
503
531
|
|
@@ -510,10 +538,11 @@ of seconds to wait in-line or configuring the default wait time.
|
|
510
538
|
#### Waiting for an element to become invisible
|
511
539
|
|
512
540
|
Another method added by calling `element` is the
|
513
|
-
`wait_until_<element_name>_invisible` method.
|
514
|
-
|
515
|
-
|
516
|
-
|
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.
|
517
546
|
|
518
547
|
```ruby
|
519
548
|
@home.wait_until_search_field_invisible
|
@@ -717,8 +746,8 @@ through them to find out if all of your items are present then you can also do t
|
|
717
746
|
Simply pass a recursion parameter to the `#all_there?` check. Note that the only valid values
|
718
747
|
for this at the moment are `:none` and `:one`
|
719
748
|
|
720
|
-
Passing `:none`
|
721
|
-
site_prism to recurse through all section / sections items defined in your
|
749
|
+
Passing `:none` (default), will not change the functionality. However passing in `:one` will cause
|
750
|
+
`site_prism` to recurse through all `section` / `sections` items defined in your present scope.
|
722
751
|
|
723
752
|
Work alongside developing this functionality further is being continued in the
|
724
753
|
[site_prism-all_there](http://www.github.com/site-prism/site_prism-all_there) repo. So head on over
|
@@ -727,11 +756,33 @@ there if you're interested in how this feature will work going forwards
|
|
727
756
|
NB: At the moment a "primitive" but working copy of this is hosted inside this gem. But if you wish to
|
728
757
|
use the bleeding edge version of the logic. Then simply set the following configuration parameter
|
729
758
|
|
730
|
-
```
|
759
|
+
```ruby
|
760
|
+
`require 'site_prism/all_there'`
|
761
|
+
|
731
762
|
SitePrism.use_all_there_gem = true
|
732
763
|
```
|
733
764
|
|
734
|
-
|
765
|
+
### Getting the list of missing elements
|
766
|
+
|
767
|
+
If `#all_there?` returns false and you wish to get the list of missing elements for debugging purposes
|
768
|
+
you may want to use `#elements_missing` method. It will return all missing elements from the expected_elements list
|
769
|
+
|
770
|
+
If you do not provide a list of `expected_elements` this method will return all elements that are missing on the page;
|
771
|
+
from those which are defined.
|
772
|
+
|
773
|
+
```ruby
|
774
|
+
class Home < SitePrism::Page
|
775
|
+
element :name, '#name'
|
776
|
+
element :address, '#address'
|
777
|
+
element :success_message, 'span.alert-success'
|
778
|
+
|
779
|
+
expected_elements :name, :address
|
780
|
+
end
|
781
|
+
|
782
|
+
# and... Only `address` is on the page
|
783
|
+
|
784
|
+
@test_page.elements_missing #=> [:name]
|
785
|
+
```
|
735
786
|
|
736
787
|
## Sections
|
737
788
|
|
@@ -918,14 +969,13 @@ end
|
|
918
969
|
|
919
970
|
##### Accessing section elements using a block
|
920
971
|
|
921
|
-
|
972
|
+
You can execute a block within the context of a Section. This is
|
922
973
|
similar to Capybara's `within` method and allows for shorter test code
|
923
|
-
particularly with nested sections.
|
924
|
-
made a little prettier by simply passing a block in.
|
974
|
+
particularly with nested sections. Test code that might have to repeat the block name can be shortened up this way.
|
925
975
|
|
926
976
|
```ruby
|
927
977
|
Then(/^the home page menu contains a link to the various search functions$/) do
|
928
|
-
@home.menu do |menu|
|
978
|
+
@home.menu.within do |menu|
|
929
979
|
expect(menu).to have_search
|
930
980
|
expect(menu.search['href']).to include('google.com')
|
931
981
|
expect(menu).to have_images
|
@@ -934,6 +984,16 @@ Then(/^the home page menu contains a link to the various search functions$/) do
|
|
934
984
|
end
|
935
985
|
```
|
936
986
|
|
987
|
+
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.
|
988
|
+
|
989
|
+
```ruby
|
990
|
+
Then(/^the home page menu contains a link to the various search functions$/) do
|
991
|
+
@home.menu do |menu| # possible, but prefer: `@home.menu.within`
|
992
|
+
expect(menu).to have_search
|
993
|
+
end
|
994
|
+
end
|
995
|
+
```
|
996
|
+
|
937
997
|
#### Getting a section's parent
|
938
998
|
|
939
999
|
It is possible to ask a section for its parent (page, or section if this
|
@@ -1172,7 +1232,7 @@ This allows for pretty tests ...
|
|
1172
1232
|
```ruby
|
1173
1233
|
Then(/^there are lots of search_results$/) do
|
1174
1234
|
expect(@results_page.search_results.size).to eq(10)
|
1175
|
-
|
1235
|
+
|
1176
1236
|
@home.search_results.each do |result|
|
1177
1237
|
expect(result).to have_title
|
1178
1238
|
expect(result.blurb.text).not_to be_empty
|
@@ -1188,6 +1248,26 @@ element. So if the css selector finds 3 `li` elements, calling
|
|
1188
1248
|
`search_results` will return an array containing 3 instances of
|
1189
1249
|
`SearchResults`, each with one of the `li` elements as it's root element.
|
1190
1250
|
|
1251
|
+
##### Accessing Within a Collection of Sections
|
1252
|
+
|
1253
|
+
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:
|
1254
|
+
|
1255
|
+
```rb
|
1256
|
+
@home.search_results.first do |result|
|
1257
|
+
# This block is silently ignored.
|
1258
|
+
expect(result).to have_title
|
1259
|
+
end
|
1260
|
+
```
|
1261
|
+
Instead use `within` to access the inner-context of the Section.
|
1262
|
+
|
1263
|
+
```rb
|
1264
|
+
@home.search_results.first.within do |result|
|
1265
|
+
# This block is run within the context of the Section.
|
1266
|
+
expect(result).to have_title
|
1267
|
+
end
|
1268
|
+
```
|
1269
|
+
|
1270
|
+
|
1191
1271
|
#### Anonymous Section Collections
|
1192
1272
|
|
1193
1273
|
You can define collections of anonymous sections the same way you would
|
@@ -1384,7 +1464,7 @@ instance of the class when created.
|
|
1384
1464
|
|
1385
1465
|
### Skipping load Validations
|
1386
1466
|
|
1387
|
-
Defined load validations can be skipped for one `load` call by
|
1467
|
+
Defined load validations can be skipped for one `load` call by
|
1388
1468
|
passing in `with_validations: false`.
|
1389
1469
|
|
1390
1470
|
```ruby
|
@@ -1435,7 +1515,7 @@ the validations will be performed in the following order:
|
|
1435
1515
|
**NB:** `SitePrism::Page` **used to** include a default load validation on
|
1436
1516
|
`page.displayed?` however for v3 this has been removed. It is therefore
|
1437
1517
|
necessary to re-define this if you want to retain the behaviour
|
1438
|
-
from site_prism v2. See [UPGRADING.md](https://github.com/site-prism/site_prism/blob/
|
1518
|
+
from site_prism v2. See [UPGRADING.md](https://github.com/site-prism/site_prism/blob/main/UPGRADING.md#default-load-validations)
|
1439
1519
|
for more info on this.
|
1440
1520
|
|
1441
1521
|
## Using Capybara Query Options
|
@@ -1651,12 +1731,12 @@ as per the code below
|
|
1651
1731
|
Capybara.configure do |config|
|
1652
1732
|
config.default_max_wait_time = 11 #=> Wait up to 11 seconds for all queries to fail
|
1653
1733
|
# or if you don't want to ever wait
|
1654
|
-
config.default_max_wait_time = 0 #=> Don't ever wait!
|
1734
|
+
config.default_max_wait_time = 0 #=> Don't ever wait!
|
1655
1735
|
end
|
1656
1736
|
```
|
1657
1737
|
|
1658
1738
|
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.
|
1739
|
+
in any SitePrism method to help work-around special circumstances.
|
1660
1740
|
|
1661
1741
|
```ruby
|
1662
1742
|
# Option 1: using wait key assignment
|
data/lib/site_prism.rb
CHANGED
@@ -3,15 +3,20 @@
|
|
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
|
-
autoload :Deprecator, 'site_prism/deprecator'
|
9
10
|
autoload :DSL, 'site_prism/dsl'
|
11
|
+
autoload :Deprecator, 'site_prism/deprecator'
|
10
12
|
autoload :ElementChecker, 'site_prism/element_checker'
|
11
|
-
autoload :
|
13
|
+
autoload :Loadable, 'site_prism/loadable'
|
12
14
|
autoload :Logger, 'site_prism/logger'
|
13
15
|
autoload :Page, 'site_prism/page'
|
16
|
+
autoload :RecursionChecker, 'site_prism/recursion_checker'
|
17
|
+
autoload :RspecMatchers, 'site_prism/rspec_matchers'
|
14
18
|
autoload :Section, 'site_prism/section'
|
19
|
+
autoload :Timer, 'site_prism/timer'
|
15
20
|
autoload :Waiter, 'site_prism/waiter'
|
16
21
|
|
17
22
|
class << self
|
@@ -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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
@@ -1,8 +1,12 @@
|
|
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
|
+
# Tells the user that they are using old functionality, which needs removing in the
|
9
|
+
# next major version
|
6
10
|
def deprecate(old, new = nil)
|
7
11
|
if new
|
8
12
|
warn("#{old} is being deprecated and should no longer be used. Use #{new} instead.")
|
@@ -13,6 +17,13 @@ module SitePrism
|
|
13
17
|
warn("#{old} will be removed in SitePrism v4. You have been warned!")
|
14
18
|
end
|
15
19
|
|
20
|
+
# @return SitePrism.logger.debug(msg)
|
21
|
+
# Tells the user that they are using functionality which is non-optimal
|
22
|
+
# The functionality should usually provide a reason for it being poor, as well as an
|
23
|
+
# optional way of upgrading to something different
|
24
|
+
#
|
25
|
+
# NB: As this is bubbled up at debug level, often users will not see this. So it will
|
26
|
+
# never be a candidate for removal directly
|
16
27
|
def soft_deprecate(old, reason, new = nil)
|
17
28
|
debug("The #{old} method is changing, as is SitePrism, and is now configurable.")
|
18
29
|
debug("REASON: #{reason}.")
|
data/lib/site_prism/dsl.rb
CHANGED
@@ -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,9 +15,28 @@ module SitePrism
|
|
8
15
|
|
9
16
|
private
|
10
17
|
|
11
|
-
#
|
12
|
-
def
|
13
|
-
|
18
|
+
# Call `find` inside context set on page/section
|
19
|
+
def _find(*find_args)
|
20
|
+
kwargs = find_args.pop
|
21
|
+
page.find(*find_args, **kwargs)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Call `all` inside context set on page/section
|
25
|
+
def _all(*find_args)
|
26
|
+
kwargs = find_args.pop
|
27
|
+
page.all(*find_args, **kwargs)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Call `has_selector?` inside context set on page/section
|
31
|
+
def element_exists?(*find_args)
|
32
|
+
kwargs = find_args.pop
|
33
|
+
page.has_selector?(*find_args, **kwargs)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Call `has_no_selector?` inside context set on page/section
|
37
|
+
def element_does_not_exist?(*find_args)
|
38
|
+
kwargs = find_args.pop
|
39
|
+
page.has_no_selector?(*find_args, **kwargs)
|
14
40
|
end
|
15
41
|
|
16
42
|
# Prevent users from calling methods with blocks when they shouldn't be.
|
@@ -36,6 +62,14 @@ module SitePrism
|
|
36
62
|
raise SitePrism::UnsupportedBlockError
|
37
63
|
end
|
38
64
|
|
65
|
+
# Warn users from naming the elements starting with no_
|
66
|
+
def warn_if_dsl_collision(obj, name)
|
67
|
+
return unless name.to_s.start_with?('no_')
|
68
|
+
|
69
|
+
SitePrism.logger.warn("#{obj.class}##{name} should not start with no_")
|
70
|
+
SitePrism::Deprecator.deprecate('Using no_ prefix in DSL definition')
|
71
|
+
end
|
72
|
+
|
39
73
|
# Sanitize method called before calling any SitePrism DSL method or
|
40
74
|
# meta-programmed method. This ensures that the Capybara query is correct.
|
41
75
|
#
|
@@ -49,7 +83,7 @@ module SitePrism
|
|
49
83
|
|
50
84
|
recombine_args(find_args, runtime_args, options)
|
51
85
|
|
52
|
-
return [*find_args, *runtime_args] if options.empty?
|
86
|
+
return [*find_args, *runtime_args, {}] if options.empty?
|
53
87
|
|
54
88
|
[*find_args, *runtime_args, options]
|
55
89
|
end
|
@@ -60,55 +94,84 @@ module SitePrism
|
|
60
94
|
#
|
61
95
|
# If the hash is empty, then the hash is omitted from the payload sent
|
62
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).
|
63
100
|
def recombine_args(find_args, runtime_args, options)
|
64
101
|
options.merge!(find_args.pop) if find_args.last.is_a? Hash
|
65
102
|
options.merge!(runtime_args.pop) if runtime_args.last.is_a? Hash
|
66
|
-
options[:wait] =
|
67
|
-
end
|
68
|
-
|
69
|
-
# Detect if the +wait+ key is present in the options hash.
|
70
|
-
# Note that setting it to to false or 0, still will return true here.
|
71
|
-
def wait_key_present?(options)
|
72
|
-
options.key?(:wait)
|
103
|
+
options[:wait] = Capybara.default_max_wait_time unless options.key?(:wait)
|
73
104
|
end
|
74
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
|
75
112
|
module ClassMethods
|
76
113
|
attr_reader :expected_items
|
77
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
|
78
120
|
def element(name, *find_args)
|
79
121
|
SitePrism::Deprecator.deprecate('Passing a block to :element') if block_given?
|
80
122
|
build(:element, name, *find_args) do
|
81
123
|
define_method(name) do |*runtime_args, &element_block|
|
124
|
+
warn_if_dsl_collision(self, name)
|
82
125
|
raise_if_block(self, name, !element_block.nil?, :element)
|
83
126
|
_find(*merge_args(find_args, runtime_args))
|
84
127
|
end
|
85
128
|
end
|
86
129
|
end
|
87
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
|
88
136
|
def elements(name, *find_args)
|
89
137
|
SitePrism::Deprecator.deprecate('Passing a block to :elements') if block_given?
|
90
138
|
build(:elements, name, *find_args) do
|
91
139
|
define_method(name) do |*runtime_args, &element_block|
|
140
|
+
warn_if_dsl_collision(self, name)
|
92
141
|
raise_if_block(self, name, !element_block.nil?, :elements)
|
93
142
|
_all(*merge_args(find_args, runtime_args))
|
94
143
|
end
|
95
144
|
end
|
96
145
|
end
|
97
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
|
98
150
|
def expected_elements(*elements)
|
99
151
|
@expected_items = elements
|
100
152
|
end
|
101
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
|
102
159
|
def section(name, *args, &block)
|
103
160
|
section_class, find_args = extract_section_options(args, &block)
|
104
161
|
build(:section, name, *find_args) do
|
105
162
|
define_method(name) do |*runtime_args, &runtime_block|
|
163
|
+
warn_if_dsl_collision(self, name)
|
106
164
|
section_element = _find(*merge_args(find_args, runtime_args))
|
107
165
|
section_class.new(self, section_element, &runtime_block)
|
108
166
|
end
|
109
167
|
end
|
110
168
|
end
|
111
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
|
112
175
|
def sections(name, *args, &block)
|
113
176
|
section_class, find_args = extract_section_options(args, &block)
|
114
177
|
build(:sections, name, *find_args) do
|
@@ -135,11 +198,9 @@ module SitePrism
|
|
135
198
|
end
|
136
199
|
|
137
200
|
def mapped_items(legacy: true)
|
138
|
-
if legacy
|
139
|
-
|
140
|
-
|
141
|
-
new_mapped_items
|
142
|
-
end
|
201
|
+
return old_mapped_items if legacy
|
202
|
+
|
203
|
+
new_mapped_items
|
143
204
|
end
|
144
205
|
|
145
206
|
private
|
@@ -154,13 +215,7 @@ module SitePrism
|
|
154
215
|
end
|
155
216
|
|
156
217
|
def new_mapped_items
|
157
|
-
@new_mapped_items ||= {
|
158
|
-
element: [],
|
159
|
-
elements: [],
|
160
|
-
section: [],
|
161
|
-
sections: [],
|
162
|
-
iframe: [],
|
163
|
-
}
|
218
|
+
@new_mapped_items ||= { element: [], elements: [], section: [], sections: [], iframe: [] }
|
164
219
|
end
|
165
220
|
|
166
221
|
def build(type, name, *find_args)
|
@@ -181,27 +236,15 @@ module SitePrism
|
|
181
236
|
def add_helper_methods(name, *find_args)
|
182
237
|
create_existence_checker(name, *find_args)
|
183
238
|
create_nonexistence_checker(name, *find_args)
|
184
|
-
|
239
|
+
SitePrism::RspecMatchers.new(name)._create_rspec_existence_matchers if defined?(RSpec)
|
185
240
|
create_visibility_waiter(name, *find_args)
|
186
241
|
create_invisibility_waiter(name, *find_args)
|
187
242
|
end
|
188
243
|
|
189
244
|
def create_helper_method(proposed_method_name, *find_args)
|
190
|
-
if find_args.empty?
|
191
|
-
create_error_method(proposed_method_name)
|
192
|
-
else
|
193
|
-
yield
|
194
|
-
end
|
195
|
-
end
|
245
|
+
return create_error_method(proposed_method_name) if find_args.empty?
|
196
246
|
|
197
|
-
|
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
|
247
|
+
yield
|
205
248
|
end
|
206
249
|
|
207
250
|
def create_existence_checker(element_name, *find_args)
|
@@ -250,6 +293,10 @@ module SitePrism
|
|
250
293
|
|
251
294
|
def create_error_method(name)
|
252
295
|
SitePrism.logger.error("#{name} has come from an item with no locators.")
|
296
|
+
SitePrism::Deprecator.soft_deprecate(
|
297
|
+
'DSL definition with no find_args',
|
298
|
+
'All DSL elements should have find_args'
|
299
|
+
)
|
253
300
|
define_method(name) { raise SitePrism::InvalidElementError }
|
254
301
|
end
|
255
302
|
|
@@ -285,7 +332,7 @@ module SitePrism
|
|
285
332
|
def extract_section_options(args, &block)
|
286
333
|
if args.first.is_a?(Class)
|
287
334
|
klass = args.shift
|
288
|
-
section_class = klass if klass
|
335
|
+
section_class = klass if klass <= SitePrism::Section
|
289
336
|
end
|
290
337
|
|
291
338
|
section_class = deduce_section_class(section_class, &block)
|
@@ -298,20 +345,23 @@ module SitePrism
|
|
298
345
|
klass = Class.new(klass || SitePrism::Section, &block) if block_given?
|
299
346
|
return klass if klass
|
300
347
|
|
301
|
-
raise ArgumentError,
|
302
|
-
SitePrism::Section class or/and a block as the second argument."
|
348
|
+
raise ArgumentError, 'You should provide descendant of SitePrism::Section class or/and a block as the second argument.'
|
303
349
|
end
|
304
350
|
|
305
351
|
def deduce_search_arguments(section_class, args)
|
306
352
|
extract_search_arguments(args) ||
|
307
353
|
extract_search_arguments(section_class.default_search_arguments) ||
|
308
|
-
|
309
|
-
in section creation or set_default_search_arguments within section class")
|
354
|
+
invalidate_search_arguments!
|
310
355
|
end
|
311
356
|
|
312
357
|
def extract_search_arguments(args)
|
313
358
|
args if args && !args.empty?
|
314
359
|
end
|
360
|
+
|
361
|
+
def invalidate_search_arguments!
|
362
|
+
SitePrism.logger.error('Could not deduce search_arguments')
|
363
|
+
raise(ArgumentError, 'search arguments are needed in `section` definition or alternatively use `set_default_search_arguments`')
|
364
|
+
end
|
315
365
|
end
|
316
366
|
end
|
317
367
|
end
|