capybara-reloads 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 980ec37f08c81b19646193192a014368ada60f31cc52fc64b4bc03584ed40a77
4
+ data.tar.gz: abca8c70caad1c2e131b22633e926aa1abd5dcc94c13b2cf587ad9fdfbeae7dd
5
+ SHA512:
6
+ metadata.gz: 96d1a31f3d3a64233fd22e0d7f7bf1a2c6512823225e7fc282443f6f41cc0235c3d6ffaea1ea54dc773b4b876c0c9cc70fd6bc709822415cfe631732b7530eab
7
+ data.tar.gz: 26b22dac221bf078884da1e5f6649b2d8ebc606875374609f43d99061747a4a9e50b28e1e4b3df207b98e9b4b532db23ad9cffdc23a37e4ac8f4f1baf6009d81
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-12-25
4
+
5
+ - Initial functionallity for reloading and tracking states.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in capybara-reloads.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rubocop", "~> 1.21"
data/Gemfile.lock ADDED
@@ -0,0 +1,71 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ capybara-reloads (0.1.0)
5
+ capybara (~> 3.0)
6
+ capybara-screenshot (~> 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.8.1)
12
+ public_suffix (>= 2.0.2, < 6.0)
13
+ ast (2.4.2)
14
+ capybara (3.38.0)
15
+ addressable
16
+ matrix
17
+ mini_mime (>= 0.1.3)
18
+ nokogiri (~> 1.8)
19
+ rack (>= 1.6.0)
20
+ rack-test (>= 0.6.3)
21
+ regexp_parser (>= 1.5, < 3.0)
22
+ xpath (~> 3.2)
23
+ capybara-screenshot (1.0.26)
24
+ capybara (>= 1.0, < 4)
25
+ launchy
26
+ json (2.6.3)
27
+ launchy (2.5.0)
28
+ addressable (~> 2.7)
29
+ matrix (0.4.2)
30
+ mini_mime (1.1.2)
31
+ nokogiri (1.13.10-arm64-darwin)
32
+ racc (~> 1.4)
33
+ parallel (1.22.1)
34
+ parser (3.1.3.0)
35
+ ast (~> 2.4.1)
36
+ public_suffix (5.0.1)
37
+ racc (1.6.2)
38
+ rack (3.0.2)
39
+ rack-test (2.0.2)
40
+ rack (>= 1.3)
41
+ rainbow (3.1.1)
42
+ rake (13.0.6)
43
+ regexp_parser (2.6.1)
44
+ rexml (3.2.5)
45
+ rubocop (1.41.1)
46
+ json (~> 2.3)
47
+ parallel (~> 1.10)
48
+ parser (>= 3.1.2.1)
49
+ rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 1.8, < 3.0)
51
+ rexml (>= 3.2.5, < 4.0)
52
+ rubocop-ast (>= 1.23.0, < 2.0)
53
+ ruby-progressbar (~> 1.7)
54
+ unicode-display_width (>= 1.4.0, < 3.0)
55
+ rubocop-ast (1.24.0)
56
+ parser (>= 3.1.1.0)
57
+ ruby-progressbar (1.11.0)
58
+ unicode-display_width (2.3.0)
59
+ xpath (3.2.0)
60
+ nokogiri (~> 1.8)
61
+
62
+ PLATFORMS
63
+ arm64-darwin-21
64
+
65
+ DEPENDENCIES
66
+ capybara-reloads!
67
+ rake (~> 13.0)
68
+ rubocop (~> 1.21)
69
+
70
+ BUNDLED WITH
71
+ 2.3.23
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # Capybara::Reloads
2
+
3
+ Reload the page when a Capybara selector fails. After reload assert the selector again. Repeat until the number of reloads is equal to allow_max_reloads. Store screenshot and html version of the page to allow for easier debug and understanding of why the spec has failed.
4
+
5
+ When used for a randomly failing spec it will store and show the states before every load.
6
+
7
+ ```ruby
8
+ expect(page).to have_xpath("//..the xpath value",
9
+ allow_max_reloads: Capybara::Reloads.recommended_allow_max_reloads)
10
+ ```
11
+
12
+ If the selector is first not matched and matched after reload capybara-reloads will report it as:
13
+
14
+ ```bash
15
+ Failures:
16
+
17
+ 1) Articles system specs
18
+ Failure/Error: raise message
19
+
20
+ RuntimeError:
21
+ The example initially failed, but after 1 reloads it was successful.
22
+ States are shown below in order:
23
+
24
+ State 0
25
+ {
26
+ "html": ".../tmp/capybara/screenshot_2022-12-25-21-57-53.129.html",
27
+ "image": ".../tmp/capybara/screenshot_2022-12-25-21-57-53.129.png",
28
+ "exception": "expected to find xpath \"//a[@class='select2-choice']/span[text()='United States']\" but there were no matches",
29
+ "reloads_made": 0
30
+ }
31
+ State 1
32
+ {
33
+ "html": ".../tmp/capybara/screenshot_2022-12-25-21-57-53.906.html",
34
+ "image": ".../tmp/capybara/screenshot_2022-12-25-21-57-53.906.png",
35
+ "exception": null,
36
+ "reloads_made": 1
37
+ }
38
+
39
+ [Screenshot Image]: .../tmp/capybara/failures_r_spec_example_groups_article_807.png
40
+
41
+
42
+ # .../capybara-reloads/lib/capybara/reloads/node/matchers.rb:54:in `after_success'
43
+ # .../capybara-reloads/lib/capybara/reloads/node/matchers.rb:28:in `block in with_reload_on_fail'
44
+ # .../capybara-reloads/lib/capybara/reloads/node/matchers.rb:23:in `loop'
45
+ # .../capybara-reloads/lib/capybara/reloads/node/matchers.rb:23:in `with_reload_on_fail'
46
+ # .../capybara-reloads/lib/capybara/reloads/node/matchers.rb:7:in `assert_selector'
47
+ # .../gems/capybara-3.38.0/lib/capybara/session.rb:773:in `assert_selector'
48
+ # .../gems/capybara-3.38.0/lib/capybara/rspec/matchers/have_selector.rb:18:in `element_matches?'
49
+ # .../gems/capybara-3.38.0/lib/capybara/rspec/matchers/base.rb:51:in `matches?'
50
+ # ./spec/system/articles_spec.rb:101:in `block (3 levels) in <top (required)>'
51
+ # ./spec/system/articles_spec.rb:157:in `block (3 levels) in <top (required)>'
52
+ # ./spec/system/articles_spec.rb:135:in `upto'
53
+ # ./spec/system/articles_spec.rb:135:in `block (2 levels) in <top (required)>'
54
+ # ./spec/spec_helper.rb:664:in `block (2 levels) in <top (required)>'
55
+ # .../gems/webmock-3.14.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'
56
+
57
+ Finished in 13.71 seconds (files took 4.49 seconds to load)
58
+ ```
59
+
60
+ ## What's the goal and the job to be done
61
+
62
+ Sometimes a spec for an application that uses JavaScript fails "randomly". The goal of capybara-reloads is to help identify and resolve specs that are randomly failing due to JavaScript timing, load and reload precularities in non-trivial platform. It helps by saving a screenshot and html version of the page, reloading the page, and trying the selector again. If the second or the third time the selector is matched then the gem reports this.
63
+
64
+ An alternative to capybara-reloads is:
65
+
66
+ ```ruby
67
+ 0.upto(2) do
68
+ begin
69
+ expect(page).to have_xpath "//..the xpath"
70
+ rescue Exception=>e
71
+ save screenshots and html of the page
72
+ page.refresh
73
+ end
74
+ end
75
+ ```
76
+ but the above has to be done for every call and makes the spec more difficult to read and maintain. capybara-reloads patches Capybara in a way that makes enabling the reload for every or for specific selector very easy.
77
+
78
+ ## Reasoning
79
+
80
+ A non-trivial suite of system specs running over a non-trivial platform often contains specs that fail randomly, generally due to part of the JS not loading properly or not loading at all.
81
+
82
+ It is difficult to debug these randomly failing specs.
83
+
84
+ Capybara provides a mechanism to wait for an expression to be matched agains a page. Check Capybara.default_max_wait_time and the 'wait: ' options on selectors.
85
+
86
+ There are cases where waiting for an expression does not help as the JS has not loaded. One reason might be that the JS is loaded through a network request and is inserted on the page without a proper async attribute on the script tag. Another reason might a a bug in a JS around timing issues. Non-trivial apps often load JS from sprockets, webpack, esbuild, vite, network and others where the source is comming from rails gems, npm packages or as hosted scripts.
87
+
88
+ The issue with randomly failing spec is that they reduce the trust that a team has in the system specs. Team members might be reluctant to develop and run a proper system specs when a spec fails from time to time.
89
+
90
+ During the development of this gem I stumbled upon such a case where the JS on the page was not loaded at all. I ran a spec 100 times and the results were:
91
+
92
+ - 100 times - 0 failed
93
+ - 100 times - Run 2 and Run 14 failed
94
+ - 100 times - 0 failed
95
+ - 1000 times - Run 353, 370, 409, 575, 624, 721, 959 failed
96
+
97
+ capybara-reloads is **not designed to hide this issues**. These are real issues that happen for real user requests. It is very possible that 1 in 100-200 requests from the set above loads a page that is broken for the user. Users generally reload the page and move one. If it happens once in a few hundred requests they might not even notice it.
98
+
99
+ capybara-reloads is **designed to help identify, track and bring more light to this issue**. In this way teams could have more visibility on the patterns in the suites. They could budget proper time to address these issue when they feel they are important. capybara-reloads also provides a way to track information like images and html versions of the page, to log information and to place brakepoints for when this issues occur.
100
+
101
+ ## Installation
102
+
103
+ Add to gem file
104
+
105
+ $ gem install capybara-reloads
106
+
107
+ or add to Gemfile
108
+
109
+ gem 'capybara-reloads'
110
+
111
+ ## Usage
112
+
113
+ capybara-reloads is non-intrusive. It will extend Capybara, but will not change behavior and will not cause a reload unless enabled. **To enable it the value of 'allow_max_reloads' should be explicitly set.**
114
+
115
+ For RSpec add the configuration to spes/spec_helper.rb or spec/rails_helper.rb
116
+
117
+ ### To enable globally for all specs
118
+
119
+ This will enable capybara-reloads for every matcher.
120
+
121
+ ```ruby
122
+ Capybara::Reloads.allow_max_reloads = 2
123
+ ```
124
+
125
+ It is recommended to use the Capybara::Reloads.recommended_allow_max_reloads value like:
126
+
127
+ ```ruby
128
+ Capybara::Reloads.allow_max_reloads = Capybara::Reloads.recommended_allow_max_reloads
129
+ ```
130
+
131
+ ### To enable for specific matcher
132
+
133
+ ```ruby
134
+ expect(page).to have_xpath "//..the xpath value", allow_max_reloads: 2
135
+ ```
136
+
137
+ or the recommended
138
+
139
+ ```ruby
140
+ expect(page).to have_xpath("//..the xpath value",
141
+ allow_max_reloads: Capybara::Reloads.recommended_allow_max_reloads)
142
+ ```
143
+
144
+ ### Stop at a breakpoint only when reload 'fixed it'
145
+
146
+ The example below configures capybara-reloads with a breakpoint where a debugger will stop only after a selector was first not matched, then page was refreshed and then the selector was matched for the second page.
147
+
148
+ ```ruby
149
+ Capybara::Reloads.allow_max_reloads = 1
150
+ Capybara::Reloads.reload_fixed_it_callback do |args|
151
+ debugger
152
+ Capybara::Reloads.construct_message(args)
153
+ end
154
+ ```
155
+
156
+ ## Configuration
157
+
158
+ ```ruby
159
+ # The number of reloads that capybara-reloads will do. It will check if the selector is matched for every returned page.
160
+ # It is a bad idea to have this set to a large number and 1-2 is the recommended on.
161
+ #
162
+ # Default value is 0 which disables any reloads
163
+ Capybara::Reloads.allow_max_reloads
164
+
165
+ # The number of max reloads recommended by capybara-reloads author
166
+ Capybara::Reloads.recommended_allow_max_reloads
167
+
168
+ # By default when capybara-reloads reloads the page and the matcher is resolved on the new page, we will throw an expection even though the new
169
+ # page makes the specs pass. In this way we clearly inform that this spec fails and should be inspected.
170
+ # When you are ok with the test continuing you can set 'only_report' to true
171
+ #
172
+ # Require.
173
+ # Default value is false
174
+ Capybara::Reloads::only_report
175
+
176
+ # A Proc called before reload of the page
177
+ #
178
+ # It is useful to print a different kind of message, to stop, debug and inspect the state.
179
+ #
180
+ # Capybara::Reloads.before_reload_callback = Proc.new do |args|
181
+ # args[:base] # contains the instance of Capybara::Node::Base where we assert the matcher
182
+ # args[:expcetion] # contains the Capybara::ElementNotFound exception that occurred
183
+ # end
184
+ #
185
+ # Optional. Can be set to nil
186
+ # Default value is provided that prints a message that the page will be reloaded
187
+ Capybara::Reloads.before_reload_callback
188
+
189
+ # A Proc called to reload the page
190
+ #
191
+ # Capybara::Reloads.reload_callback = Proc.new do |args|
192
+ # args[:base] # contains the instance of Capybara::Node::Base where we assert the matcher
193
+ # end
194
+ #
195
+ # Required.
196
+ # Default value is provided. Check source code of what it is as of current version
197
+ Capybara::Reloads.reload_callback
198
+
199
+ # A proc called after capybara-reloads has reloaded the page and the new page passes the test.
200
+ # This means that the reload has 'fixed the test'. By default screenshot and html version
201
+ # of the page are saved in a 'states' array after every assert of the matcher.
202
+ #
203
+ # Capybara::Reloads.reload_callback = Proc.new do |args|
204
+ # args[:states] # contains the states after every assert of the matcher
205
+ # # The states object contains
206
+ # {
207
+ # :html=>"/path/to/html",
208
+ # :image=>"/path/to/screenshot",
209
+ # :exception=>... # The Capybara::ElementNotFound exception that occurred,
210
+ # :reloads_made=>... # The number of reloads that were made when this state was saved
211
+ # }
212
+ # args[:reloads_made] # contains the reloads that were already made before this proc was called
213
+ #
214
+ # # This return value should be a message.
215
+ # # It will be reported or raise based on Capybara::Reloads.only_report
216
+ # # This gives the chance to add additional things to the report message
217
+ # # that are important for this spec/suite
218
+ # # The default message is constructed with Capybara::Reloads.construct_message(args)
219
+ # message
220
+ # end
221
+ #
222
+ # Required.
223
+ # Default value is provided. Check source code of what it is as of current version
224
+ # Should return a message
225
+ Capybara::Reloads.reload_fixed_it_callback
226
+ ```
227
+
228
+ ## Development
229
+
230
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
231
+
232
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
233
+
234
+ ## Contributing
235
+
236
+ Bug reports and pull requests are welcome on GitHub at https://github.com/thebravoman/capybara-reloads.
237
+
238
+ ## License
239
+
240
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/capybara/reloads/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "capybara-reloads"
7
+ spec.version = Capybara::Reloads::VERSION
8
+ spec.authors = ["Kiril Mitov"]
9
+ spec.email = ["kiril [at] retreaver [dot] com"]
10
+
11
+ spec.summary = "Utilities for Capybara to allow us to reload the page and check if examples will then pass."
12
+ spec.homepage = "https://kmitov.com"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/thebravoman/capybara-reloads"
18
+ spec.metadata["changelog_uri"] = "https://github.com/thebravoman/capybara-reloads/CHANGELOG.md"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ # Uncomment to register a new dependency of your gem
32
+ # spec.add_dependency "example-gem", "~> 1.0"
33
+ spec.add_dependency "capybara", "~> 3.0"
34
+ spec.add_dependency "capybara-screenshot", "~> 1.0"
35
+
36
+ # For more information and examples about making a new gem, check out our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
@@ -0,0 +1,70 @@
1
+ module Capybara
2
+ module Reloads
3
+ module Node
4
+ module Matchers
5
+
6
+ def assert_selector(*args, &optional_filter_block)
7
+ with_reload_on_fail(args.last.delete(:allow_max_reloads)) do
8
+ super
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def with_reload_on_fail allow_max_reloads_arg
15
+ local_max_reloads = allow_max_reloads_arg || Capybara::Reloads.allow_max_reloads
16
+ unless local_max_reloads.is_a?(Numeric) || local_max_reloads == nil
17
+ raise "'allow_max_reloads' must be Numeric or nil"
18
+ end
19
+ local_max_reloads == local_max_reloads || 0
20
+ result = nil
21
+ reloads_made = 0
22
+ @previous_states = []
23
+ loop do
24
+ begin
25
+ result = yield
26
+ # there is a result. We don't have to retry
27
+ # If previously there were errors get the current state and report
28
+ after_success reloads_made
29
+ break
30
+ rescue Capybara::ElementNotFound => e
31
+ record_state e, reloads_made
32
+ if reloads_made == local_max_reloads
33
+ raise e
34
+ end
35
+ reloads_made+=1
36
+ args = {base: self, exception: e}
37
+ # Allows us to change the way we report that a refresh should happend
38
+ if Capybara::Reloads.before_reload_callback != nil
39
+ Capybara::Reloads.before_reload_callback.call(args)
40
+ end
41
+ Capybara::Reloads.reload_callback.call(args)
42
+ end
43
+ end
44
+ result
45
+ end
46
+
47
+ def after_success reloads_made
48
+ if @previous_states.size > 0
49
+ record_state nil, reloads_made
50
+ message = Capybara::Reloads.reload_fixed_it_callback.call(states: @previous_states, reloads_made: reloads_made)
51
+ if Capybara::Reloads.only_report
52
+ puts message
53
+ else
54
+ raise message
55
+ end
56
+ @previous_states = []
57
+ end
58
+ end
59
+
60
+ def record_state exception, reloads_made
61
+ html_and_image = Capybara::Screenshot.screenshot_and_save_page
62
+ # html_and_image is of the form
63
+ # {:html=>"...screenshot_2022-12-25-17-42-37.712.html", :image=>"...screenshot_2022-12-25-17-42-37.712.png"}
64
+ @previous_states << html_and_image.merge({exception: exception, reloads_made: reloads_made})
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ module Reloads
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "reloads/version"
4
+ require_relative "reloads/node/matchers"
5
+
6
+ module Capybara
7
+ module Reloads
8
+ class Error < StandardError; end
9
+ @@recommended_allow_max_reloads = 2
10
+
11
+ # By default Capybara::Reloads should have no impact
12
+ # It should be explicitly enabled, by setting to the recommended_allow_max_reloads with
13
+ # Capybara::Reloads.allow_max_reloads = CapybaraReload.recommended_allow_max_reloads
14
+ @@allow_max_reloads = 0
15
+
16
+ # The goal of Capybara::Reloads is to help identify places where the JS does not load
17
+ # not to hide them. By default Capybara::Reloads will try to reload to see if the error
18
+ # we can continue, but even if we do it will by default report this as an error.
19
+ # In this way we have clearly shown that this example depends on reloading the page
20
+ # and this is the real error here. Not that we can't find an element on the page
21
+ # but that this element is found sometimes and if we refresh it will be found
22
+ # more often than not
23
+ #
24
+ # To make Capybara::Reloads continue use only_report
25
+ @@only_report = false
26
+
27
+ @@before_reload_callback = Proc.new do |args|
28
+ puts "Refreshing the page as an exception occurred: #{args[:exception].message}"
29
+ end
30
+
31
+ @@reload_callback = Proc.new do |args|
32
+ base = args[:base]
33
+ base.session.refresh
34
+ end
35
+
36
+ @@reload_fixed_it_callback = Proc.new do |args|
37
+ Capybara::Reloads.construct_message(args)
38
+ end
39
+
40
+ # @param args
41
+ # @params states
42
+ # @params reloads_made
43
+ def self.construct_message args
44
+ message = <<-MESSAGE
45
+ The example initially failed, but after #{args[:reloads_made]} reloads it was successful.
46
+ States are shown below in order:
47
+ MESSAGE
48
+ args[:states].each_with_index do |state, index|
49
+ message += "\n"
50
+ message += "State #{index}\n"
51
+ message += JSON.pretty_generate(state)
52
+ end
53
+ message
54
+ end
55
+
56
+ def self.recommended_allow_max_reloads
57
+ @@recommended_allow_max_reloads
58
+ end
59
+
60
+ def self.allow_max_reloads
61
+ @@allow_max_reloads
62
+ end
63
+
64
+ def self.allow_max_reloads=(reloads)
65
+ if reloads > @@recommended_allow_max_reloads
66
+ puts "You are setting Capybara::Reloads.allow_max_reloads to be #{reloads}."
67
+ puts "This is more than the recommended value of #{@@recommended_allow_max_reloads} (Capybara::Reloads.recommended_allow_max_reloads)."
68
+ puts "Please refer to documentation about why this might be a bad idea."
69
+ end
70
+ @@allow_max_reloads = reloads
71
+ end
72
+
73
+ def self.only_report
74
+ @@only_report
75
+ end
76
+
77
+ def self.only_report=(value)
78
+ @@only_report = value
79
+ end
80
+
81
+ def self.before_reload_callback
82
+ @@before_reload_callback
83
+ end
84
+
85
+ def self.before_reload_callback=(the_proc)
86
+ @@before_reload_callback = the_proc
87
+ end
88
+
89
+ def self.reload_callback
90
+ @@reload_callback
91
+ end
92
+
93
+ def self.reload_callback=(the_proc)
94
+ @@reload_callback = the_proc
95
+ end
96
+
97
+ def self.reload_fixed_it_callback
98
+ @@reload_fixed_it_callback
99
+ end
100
+
101
+ end
102
+ end
103
+
104
+ Capybara::Node::Base.send(:prepend, Capybara::Reloads::Node::Matchers)
@@ -0,0 +1,6 @@
1
+ module Capybara
2
+ module Reloads
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capybara-reloads
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kiril Mitov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: capybara-screenshot
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ description:
42
+ email:
43
+ - kiril [at] retreaver [dot] com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".rubocop.yml"
49
+ - CHANGELOG.md
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - capybara-reloads.gemspec
56
+ - lib/capybara/reloads.rb
57
+ - lib/capybara/reloads/node/matchers.rb
58
+ - lib/capybara/reloads/version.rb
59
+ - sig/capybara/reloads.rbs
60
+ homepage: https://kmitov.com
61
+ licenses:
62
+ - MIT
63
+ metadata:
64
+ homepage_uri: https://kmitov.com
65
+ source_code_uri: https://github.com/thebravoman/capybara-reloads
66
+ changelog_uri: https://github.com/thebravoman/capybara-reloads/CHANGELOG.md
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 2.6.0
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.1.6
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Utilities for Capybara to allow us to reload the page and check if examples
86
+ will then pass.
87
+ test_files: []