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 +4 -4
- data/README.md +97 -28
- data/lib/site_prism.rb +5 -2
- data/lib/site_prism/dsl.rb +38 -13
- data/lib/site_prism/element_checker.rb +4 -0
- data/lib/site_prism/error.rb +0 -8
- data/lib/site_prism/page.rb +4 -33
- data/lib/site_prism/recursion_checker.rb +2 -1
- data/lib/site_prism/rspec_matchers.rb +50 -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 +53 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adf8cf393fc3ad828528159a54048e54c3c396f3743c79b10a75ea313ddd135c
|
4
|
+
data.tar.gz: f2fb2ecb2f8942e3e59228994da32262a65b14a2c49f573468100f1aca799061
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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:
|
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/
|
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.
|
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
|
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
|
426
|
-
element.
|
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.
|
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.
|
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.
|
500
|
-
|
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.
|
514
|
-
|
515
|
-
|
516
|
-
|
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`
|
721
|
-
site_prism to recurse through all section / sections items defined in your
|
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
|
-
```
|
748
|
+
```ruby
|
749
|
+
`require 'site_prism/all_there'`
|
750
|
+
|
731
751
|
SitePrism.use_all_there_gem = true
|
732
752
|
```
|
733
753
|
|
734
|
-
|
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
|
-
|
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.
|
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
|
data/lib/site_prism.rb
CHANGED
@@ -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 :
|
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
|
data/lib/site_prism/dsl.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/site_prism/error.rb
CHANGED
@@ -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`
|
data/lib/site_prism/page.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/site_prism/section.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
37
|
+
within(&block) if block_given?
|
32
38
|
end
|
33
39
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
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
|
-
|
46
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
data/lib/site_prism/version.rb
CHANGED
data/lib/site_prism/waiter.rb
CHANGED
@@ -2,33 +2,20 @@
|
|
2
2
|
|
3
3
|
module SitePrism
|
4
4
|
class Waiter
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
12
|
-
|
13
|
-
sleep(0.05)
|
13
|
+
break if timer.done?
|
14
14
|
|
15
|
-
|
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
|
+
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:
|
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.
|
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.
|
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.
|
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:
|
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.
|
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.
|
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.
|
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.
|
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: '
|
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: '
|
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:
|
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:
|
182
|
-
description:
|
183
|
-
SitePrism
|
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.
|
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
|
-
|
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
|